A Simple TCP & UDP Socket Library. An update from that of Hiroshi Yamaguchi.
ClientSocket.cpp@0:1e4a74c2c16f, 2012-05-23 (annotated)
- Committer:
- macgyveremir
- Date:
- Wed May 23 16:26:44 2012 +0000
- Revision:
- 0:1e4a74c2c16f
Fixed dropping of null bytes (0x00) from incoming binary TCP frames
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
macgyveremir | 0:1e4a74c2c16f | 1 | /* |
macgyveremir | 0:1e4a74c2c16f | 2 | Copyright (c) 2011, Senio Networks, Inc. |
macgyveremir | 0:1e4a74c2c16f | 3 | |
macgyveremir | 0:1e4a74c2c16f | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy |
macgyveremir | 0:1e4a74c2c16f | 5 | of this software and associated documentation files (the "Software"), to deal |
macgyveremir | 0:1e4a74c2c16f | 6 | in the Software without restriction, including without limitation the rights |
macgyveremir | 0:1e4a74c2c16f | 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
macgyveremir | 0:1e4a74c2c16f | 8 | copies of the Software, and to permit persons to whom the Software is |
macgyveremir | 0:1e4a74c2c16f | 9 | furnished to do so, subject to the following conditions: |
macgyveremir | 0:1e4a74c2c16f | 10 | |
macgyveremir | 0:1e4a74c2c16f | 11 | The above copyright notice and this permission notice shall be included in |
macgyveremir | 0:1e4a74c2c16f | 12 | all copies or substantial portions of the Software. |
macgyveremir | 0:1e4a74c2c16f | 13 | |
macgyveremir | 0:1e4a74c2c16f | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
macgyveremir | 0:1e4a74c2c16f | 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
macgyveremir | 0:1e4a74c2c16f | 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
macgyveremir | 0:1e4a74c2c16f | 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
macgyveremir | 0:1e4a74c2c16f | 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
macgyveremir | 0:1e4a74c2c16f | 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
macgyveremir | 0:1e4a74c2c16f | 20 | THE SOFTWARE. |
macgyveremir | 0:1e4a74c2c16f | 21 | */ |
macgyveremir | 0:1e4a74c2c16f | 22 | |
macgyveremir | 0:1e4a74c2c16f | 23 | #include "SimpleSocket.h" |
macgyveremir | 0:1e4a74c2c16f | 24 | #include <stdarg.h> |
macgyveremir | 0:1e4a74c2c16f | 25 | |
macgyveremir | 0:1e4a74c2c16f | 26 | ClientSocket::ClientSocket(IpAddr ip, TCPSocket *socket, bool debug) |
macgyveremir | 0:1e4a74c2c16f | 27 | : ip(ip), socket(socket), readable(true), writable(true), preread(false), |
macgyveremir | 0:1e4a74c2c16f | 28 | state(CONNECTED), debug(debug) { |
macgyveremir | 0:1e4a74c2c16f | 29 | if (socket) |
macgyveremir | 0:1e4a74c2c16f | 30 | socket->setOnEvent(this, &ClientSocket::onTCPSocketEvent); |
macgyveremir | 0:1e4a74c2c16f | 31 | } |
macgyveremir | 0:1e4a74c2c16f | 32 | |
macgyveremir | 0:1e4a74c2c16f | 33 | ClientSocket::ClientSocket(IpAddr ip, int port, float timeout, bool debug) |
macgyveremir | 0:1e4a74c2c16f | 34 | : readable(true), writable(true), preread(false), debug(debug) { |
macgyveremir | 0:1e4a74c2c16f | 35 | createClientSocket(ip, port, timeout); |
macgyveremir | 0:1e4a74c2c16f | 36 | } |
macgyveremir | 0:1e4a74c2c16f | 37 | |
macgyveremir | 0:1e4a74c2c16f | 38 | ClientSocket::ClientSocket(char *hostname, int port, float timeout, bool debug) |
macgyveremir | 0:1e4a74c2c16f | 39 | : readable(true), writable(true), preread(false), debug(debug) { |
macgyveremir | 0:1e4a74c2c16f | 40 | Resolver resolver; |
macgyveremir | 0:1e4a74c2c16f | 41 | createClientSocket(resolver.resolve(hostname, debug), port, timeout); |
macgyveremir | 0:1e4a74c2c16f | 42 | } |
macgyveremir | 0:1e4a74c2c16f | 43 | |
macgyveremir | 0:1e4a74c2c16f | 44 | ClientSocket::ClientSocket(const ClientSocket& that) { |
macgyveremir | 0:1e4a74c2c16f | 45 | *this = that; |
macgyveremir | 0:1e4a74c2c16f | 46 | ::printf("cc called\n"); |
macgyveremir | 0:1e4a74c2c16f | 47 | } |
macgyveremir | 0:1e4a74c2c16f | 48 | |
macgyveremir | 0:1e4a74c2c16f | 49 | void ClientSocket::createClientSocket(IpAddr ip, int port, float timeout) { |
macgyveremir | 0:1e4a74c2c16f | 50 | this->ip = ip; |
macgyveremir | 0:1e4a74c2c16f | 51 | socket = new TCPSocket(); |
macgyveremir | 0:1e4a74c2c16f | 52 | socket->setOnEvent(this, &ClientSocket::onTCPSocketEvent); |
macgyveremir | 0:1e4a74c2c16f | 53 | SocketError err = socket->connect(Host(ip, port)); |
macgyveremir | 0:1e4a74c2c16f | 54 | if (!err) { |
macgyveremir | 0:1e4a74c2c16f | 55 | Timer timer; |
macgyveremir | 0:1e4a74c2c16f | 56 | timer.start(); |
macgyveremir | 0:1e4a74c2c16f | 57 | state = CONNECTING; |
macgyveremir | 0:1e4a74c2c16f | 58 | while (state == CONNECTING && timer.read() < timeout) { |
macgyveremir | 0:1e4a74c2c16f | 59 | Net::poll(); |
macgyveremir | 0:1e4a74c2c16f | 60 | if (state == CONNECTED) |
macgyveremir | 0:1e4a74c2c16f | 61 | return; |
macgyveremir | 0:1e4a74c2c16f | 62 | wait_us(100); |
macgyveremir | 0:1e4a74c2c16f | 63 | } |
macgyveremir | 0:1e4a74c2c16f | 64 | } else |
macgyveremir | 0:1e4a74c2c16f | 65 | DBG(SocketError(err)); |
macgyveremir | 0:1e4a74c2c16f | 66 | |
macgyveremir | 0:1e4a74c2c16f | 67 | writable = false; |
macgyveremir | 0:1e4a74c2c16f | 68 | state = DISCONNECTED; |
macgyveremir | 0:1e4a74c2c16f | 69 | socket->resetOnEvent(); |
macgyveremir | 0:1e4a74c2c16f | 70 | socket->close(); |
macgyveremir | 0:1e4a74c2c16f | 71 | delete socket; |
macgyveremir | 0:1e4a74c2c16f | 72 | socket = 0; |
macgyveremir | 0:1e4a74c2c16f | 73 | } |
macgyveremir | 0:1e4a74c2c16f | 74 | |
macgyveremir | 0:1e4a74c2c16f | 75 | IpAddr ClientSocket::getIp() { |
macgyveremir | 0:1e4a74c2c16f | 76 | return ip; |
macgyveremir | 0:1e4a74c2c16f | 77 | } |
macgyveremir | 0:1e4a74c2c16f | 78 | |
macgyveremir | 0:1e4a74c2c16f | 79 | bool ClientSocket::connected() { |
macgyveremir | 0:1e4a74c2c16f | 80 | if (socket) |
macgyveremir | 0:1e4a74c2c16f | 81 | Net::poll(); |
macgyveremir | 0:1e4a74c2c16f | 82 | |
macgyveremir | 0:1e4a74c2c16f | 83 | if (!readable && state == DISCONNECTED) |
macgyveremir | 0:1e4a74c2c16f | 84 | close(); |
macgyveremir | 0:1e4a74c2c16f | 85 | |
macgyveremir | 0:1e4a74c2c16f | 86 | return socket != 0; |
macgyveremir | 0:1e4a74c2c16f | 87 | } |
macgyveremir | 0:1e4a74c2c16f | 88 | |
macgyveremir | 0:1e4a74c2c16f | 89 | bool ClientSocket::available() { |
macgyveremir | 0:1e4a74c2c16f | 90 | if (preread) |
macgyveremir | 0:1e4a74c2c16f | 91 | return true; |
macgyveremir | 0:1e4a74c2c16f | 92 | |
macgyveremir | 0:1e4a74c2c16f | 93 | if (!readable) |
macgyveremir | 0:1e4a74c2c16f | 94 | Net::poll(); |
macgyveremir | 0:1e4a74c2c16f | 95 | |
macgyveremir | 0:1e4a74c2c16f | 96 | if (readable) { |
macgyveremir | 0:1e4a74c2c16f | 97 | char c; |
macgyveremir | 0:1e4a74c2c16f | 98 | int ret = socket->recv(&c, 1); |
macgyveremir | 0:1e4a74c2c16f | 99 | if (ret > 0) |
macgyveremir | 0:1e4a74c2c16f | 100 | { |
macgyveremir | 0:1e4a74c2c16f | 101 | preread = true; |
macgyveremir | 0:1e4a74c2c16f | 102 | preread_byte = c; |
macgyveremir | 0:1e4a74c2c16f | 103 | return true; |
macgyveremir | 0:1e4a74c2c16f | 104 | } |
macgyveremir | 0:1e4a74c2c16f | 105 | else |
macgyveremir | 0:1e4a74c2c16f | 106 | readable = false; |
macgyveremir | 0:1e4a74c2c16f | 107 | } |
macgyveremir | 0:1e4a74c2c16f | 108 | |
macgyveremir | 0:1e4a74c2c16f | 109 | if (!readable && state == DISCONNECTED) |
macgyveremir | 0:1e4a74c2c16f | 110 | close(); |
macgyveremir | 0:1e4a74c2c16f | 111 | |
macgyveremir | 0:1e4a74c2c16f | 112 | return false; |
macgyveremir | 0:1e4a74c2c16f | 113 | } |
macgyveremir | 0:1e4a74c2c16f | 114 | |
macgyveremir | 0:1e4a74c2c16f | 115 | void ClientSocket::onTCPSocketEvent(TCPSocketEvent e) { |
macgyveremir | 0:1e4a74c2c16f | 116 | DBG(SocketEvent(e)); |
macgyveremir | 0:1e4a74c2c16f | 117 | |
macgyveremir | 0:1e4a74c2c16f | 118 | switch (e) { |
macgyveremir | 0:1e4a74c2c16f | 119 | case TCPSOCKET_CONNECTED: |
macgyveremir | 0:1e4a74c2c16f | 120 | state = CONNECTED; |
macgyveremir | 0:1e4a74c2c16f | 121 | break; |
macgyveremir | 0:1e4a74c2c16f | 122 | case TCPSOCKET_READABLE: |
macgyveremir | 0:1e4a74c2c16f | 123 | readable = true; |
macgyveremir | 0:1e4a74c2c16f | 124 | break; |
macgyveremir | 0:1e4a74c2c16f | 125 | case TCPSOCKET_WRITEABLE: |
macgyveremir | 0:1e4a74c2c16f | 126 | writable = true; |
macgyveremir | 0:1e4a74c2c16f | 127 | break; |
macgyveremir | 0:1e4a74c2c16f | 128 | case TCPSOCKET_DISCONNECTED: |
macgyveremir | 0:1e4a74c2c16f | 129 | state = DISCONNECTED; |
macgyveremir | 0:1e4a74c2c16f | 130 | break; |
macgyveremir | 0:1e4a74c2c16f | 131 | } |
macgyveremir | 0:1e4a74c2c16f | 132 | } |
macgyveremir | 0:1e4a74c2c16f | 133 | |
macgyveremir | 0:1e4a74c2c16f | 134 | int ClientSocket::read() { |
macgyveremir | 0:1e4a74c2c16f | 135 | char c; |
macgyveremir | 0:1e4a74c2c16f | 136 | |
macgyveremir | 0:1e4a74c2c16f | 137 | if (preread) |
macgyveremir | 0:1e4a74c2c16f | 138 | { |
macgyveremir | 0:1e4a74c2c16f | 139 | preread = false; |
macgyveremir | 0:1e4a74c2c16f | 140 | c = preread_byte; |
macgyveremir | 0:1e4a74c2c16f | 141 | return c; |
macgyveremir | 0:1e4a74c2c16f | 142 | } |
macgyveremir | 0:1e4a74c2c16f | 143 | |
macgyveremir | 0:1e4a74c2c16f | 144 | int ret = socket->recv(&c, 1); |
macgyveremir | 0:1e4a74c2c16f | 145 | if (ret > 0) { |
macgyveremir | 0:1e4a74c2c16f | 146 | return (int) c & 255; |
macgyveremir | 0:1e4a74c2c16f | 147 | } else { |
macgyveremir | 0:1e4a74c2c16f | 148 | readable = false; |
macgyveremir | 0:1e4a74c2c16f | 149 | return -1; |
macgyveremir | 0:1e4a74c2c16f | 150 | } |
macgyveremir | 0:1e4a74c2c16f | 151 | } |
macgyveremir | 0:1e4a74c2c16f | 152 | |
macgyveremir | 0:1e4a74c2c16f | 153 | int ClientSocket::read(char *buf, int size) { |
macgyveremir | 0:1e4a74c2c16f | 154 | int req = size; |
macgyveremir | 0:1e4a74c2c16f | 155 | |
macgyveremir | 0:1e4a74c2c16f | 156 | if (preread && size > 0) |
macgyveremir | 0:1e4a74c2c16f | 157 | { |
macgyveremir | 0:1e4a74c2c16f | 158 | preread = false; |
macgyveremir | 0:1e4a74c2c16f | 159 | *buf++ = preread_byte; |
macgyveremir | 0:1e4a74c2c16f | 160 | req--; |
macgyveremir | 0:1e4a74c2c16f | 161 | } |
macgyveremir | 0:1e4a74c2c16f | 162 | |
macgyveremir | 0:1e4a74c2c16f | 163 | while (req > 0) |
macgyveremir | 0:1e4a74c2c16f | 164 | { |
macgyveremir | 0:1e4a74c2c16f | 165 | int got = socket->recv(buf, req); |
macgyveremir | 0:1e4a74c2c16f | 166 | if (got > 0) |
macgyveremir | 0:1e4a74c2c16f | 167 | { |
macgyveremir | 0:1e4a74c2c16f | 168 | buf += got; |
macgyveremir | 0:1e4a74c2c16f | 169 | req -= got; |
macgyveremir | 0:1e4a74c2c16f | 170 | } |
macgyveremir | 0:1e4a74c2c16f | 171 | else |
macgyveremir | 0:1e4a74c2c16f | 172 | { |
macgyveremir | 0:1e4a74c2c16f | 173 | readable = false; |
macgyveremir | 0:1e4a74c2c16f | 174 | break; |
macgyveremir | 0:1e4a74c2c16f | 175 | } |
macgyveremir | 0:1e4a74c2c16f | 176 | } |
macgyveremir | 0:1e4a74c2c16f | 177 | |
macgyveremir | 0:1e4a74c2c16f | 178 | return size - req; |
macgyveremir | 0:1e4a74c2c16f | 179 | } |
macgyveremir | 0:1e4a74c2c16f | 180 | |
macgyveremir | 0:1e4a74c2c16f | 181 | int ClientSocket::scanf(const char* format, ...) { |
macgyveremir | 0:1e4a74c2c16f | 182 | va_list argp; |
macgyveremir | 0:1e4a74c2c16f | 183 | va_start(argp, format); |
macgyveremir | 0:1e4a74c2c16f | 184 | char buf[256]; |
macgyveremir | 0:1e4a74c2c16f | 185 | |
macgyveremir | 0:1e4a74c2c16f | 186 | int len = read(buf, sizeof(buf) - 1); |
macgyveremir | 0:1e4a74c2c16f | 187 | if (len <= 0) |
macgyveremir | 0:1e4a74c2c16f | 188 | return 0; |
macgyveremir | 0:1e4a74c2c16f | 189 | buf[len] = '\0'; |
macgyveremir | 0:1e4a74c2c16f | 190 | |
macgyveremir | 0:1e4a74c2c16f | 191 | int ret = vsscanf(buf, format, argp); |
macgyveremir | 0:1e4a74c2c16f | 192 | va_end(argp); |
macgyveremir | 0:1e4a74c2c16f | 193 | return ret; |
macgyveremir | 0:1e4a74c2c16f | 194 | } |
macgyveremir | 0:1e4a74c2c16f | 195 | |
macgyveremir | 0:1e4a74c2c16f | 196 | int ClientSocket::write(char c) { |
macgyveremir | 0:1e4a74c2c16f | 197 | return write(&c, 1); |
macgyveremir | 0:1e4a74c2c16f | 198 | } |
macgyveremir | 0:1e4a74c2c16f | 199 | |
macgyveremir | 0:1e4a74c2c16f | 200 | int ClientSocket::write(char *buf, int size) { |
macgyveremir | 0:1e4a74c2c16f | 201 | int ret = socket->send(buf, size); |
macgyveremir | 0:1e4a74c2c16f | 202 | if (ret > 0) { |
macgyveremir | 0:1e4a74c2c16f | 203 | return ret; |
macgyveremir | 0:1e4a74c2c16f | 204 | } else { |
macgyveremir | 0:1e4a74c2c16f | 205 | writable = false; |
macgyveremir | 0:1e4a74c2c16f | 206 | return -1; |
macgyveremir | 0:1e4a74c2c16f | 207 | } |
macgyveremir | 0:1e4a74c2c16f | 208 | } |
macgyveremir | 0:1e4a74c2c16f | 209 | |
macgyveremir | 0:1e4a74c2c16f | 210 | int ClientSocket::printf(const char* format, ...) { |
macgyveremir | 0:1e4a74c2c16f | 211 | va_list argp; |
macgyveremir | 0:1e4a74c2c16f | 212 | va_start(argp, format); |
macgyveremir | 0:1e4a74c2c16f | 213 | char buf[256]; |
macgyveremir | 0:1e4a74c2c16f | 214 | |
macgyveremir | 0:1e4a74c2c16f | 215 | int len = vsnprintf(buf, sizeof(buf), format, argp); |
macgyveremir | 0:1e4a74c2c16f | 216 | va_end(argp); |
macgyveremir | 0:1e4a74c2c16f | 217 | return write(buf, len); |
macgyveremir | 0:1e4a74c2c16f | 218 | } |
macgyveremir | 0:1e4a74c2c16f | 219 | |
macgyveremir | 0:1e4a74c2c16f | 220 | void ClientSocket::close() { |
macgyveremir | 0:1e4a74c2c16f | 221 | if (socket) { |
macgyveremir | 0:1e4a74c2c16f | 222 | readable = false; |
macgyveremir | 0:1e4a74c2c16f | 223 | writable = false; |
macgyveremir | 0:1e4a74c2c16f | 224 | socket->resetOnEvent(); |
macgyveremir | 0:1e4a74c2c16f | 225 | socket->close(); |
macgyveremir | 0:1e4a74c2c16f | 226 | delete socket; |
macgyveremir | 0:1e4a74c2c16f | 227 | socket = 0; |
macgyveremir | 0:1e4a74c2c16f | 228 | } |
macgyveremir | 0:1e4a74c2c16f | 229 | } |
macgyveremir | 0:1e4a74c2c16f | 230 | |
macgyveremir | 0:1e4a74c2c16f | 231 | ClientSocket::operator bool() { |
macgyveremir | 0:1e4a74c2c16f | 232 | return connected(); |
macgyveremir | 0:1e4a74c2c16f | 233 | } |
macgyveremir | 0:1e4a74c2c16f | 234 | |
macgyveremir | 0:1e4a74c2c16f | 235 | void ClientSocket::setDebug(bool debug) { |
macgyveremir | 0:1e4a74c2c16f | 236 | this->debug = debug; |
macgyveremir | 0:1e4a74c2c16f | 237 | } |