A Simple TCP & UDP Socket Library. An update from that of Hiroshi Yamaguchi.
Revision 0:1e4a74c2c16f, committed 2012-05-23
- Comitter:
- macgyveremir
- Date:
- Wed May 23 16:26:44 2012 +0000
- Commit message:
- Fixed dropping of null bytes (0x00) from incoming binary TCP frames
Changed in this revision
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ClientSocket.cpp Wed May 23 16:26:44 2012 +0000 @@ -0,0 +1,237 @@ +/* +Copyright (c) 2011, Senio Networks, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include "SimpleSocket.h" +#include <stdarg.h> + +ClientSocket::ClientSocket(IpAddr ip, TCPSocket *socket, bool debug) + : ip(ip), socket(socket), readable(true), writable(true), preread(false), + state(CONNECTED), debug(debug) { + if (socket) + socket->setOnEvent(this, &ClientSocket::onTCPSocketEvent); +} + +ClientSocket::ClientSocket(IpAddr ip, int port, float timeout, bool debug) + : readable(true), writable(true), preread(false), debug(debug) { + createClientSocket(ip, port, timeout); +} + +ClientSocket::ClientSocket(char *hostname, int port, float timeout, bool debug) + : readable(true), writable(true), preread(false), debug(debug) { + Resolver resolver; + createClientSocket(resolver.resolve(hostname, debug), port, timeout); +} + +ClientSocket::ClientSocket(const ClientSocket& that) { + *this = that; + ::printf("cc called\n"); +} + +void ClientSocket::createClientSocket(IpAddr ip, int port, float timeout) { + this->ip = ip; + socket = new TCPSocket(); + socket->setOnEvent(this, &ClientSocket::onTCPSocketEvent); + SocketError err = socket->connect(Host(ip, port)); + if (!err) { + Timer timer; + timer.start(); + state = CONNECTING; + while (state == CONNECTING && timer.read() < timeout) { + Net::poll(); + if (state == CONNECTED) + return; + wait_us(100); + } + } else + DBG(SocketError(err)); + + writable = false; + state = DISCONNECTED; + socket->resetOnEvent(); + socket->close(); + delete socket; + socket = 0; +} + +IpAddr ClientSocket::getIp() { + return ip; +} + +bool ClientSocket::connected() { + if (socket) + Net::poll(); + + if (!readable && state == DISCONNECTED) + close(); + + return socket != 0; +} + +bool ClientSocket::available() { + if (preread) + return true; + + if (!readable) + Net::poll(); + + if (readable) { + char c; + int ret = socket->recv(&c, 1); + if (ret > 0) + { + preread = true; + preread_byte = c; + return true; + } + else + readable = false; + } + + if (!readable && state == DISCONNECTED) + close(); + + return false; +} + +void ClientSocket::onTCPSocketEvent(TCPSocketEvent e) { + DBG(SocketEvent(e)); + + switch (e) { + case TCPSOCKET_CONNECTED: + state = CONNECTED; + break; + case TCPSOCKET_READABLE: + readable = true; + break; + case TCPSOCKET_WRITEABLE: + writable = true; + break; + case TCPSOCKET_DISCONNECTED: + state = DISCONNECTED; + break; + } +} + +int ClientSocket::read() { + char c; + + if (preread) + { + preread = false; + c = preread_byte; + return c; + } + + int ret = socket->recv(&c, 1); + if (ret > 0) { + return (int) c & 255; + } else { + readable = false; + return -1; + } +} + +int ClientSocket::read(char *buf, int size) { + int req = size; + + if (preread && size > 0) + { + preread = false; + *buf++ = preread_byte; + req--; + } + + while (req > 0) + { + int got = socket->recv(buf, req); + if (got > 0) + { + buf += got; + req -= got; + } + else + { + readable = false; + break; + } + } + + return size - req; +} + +int ClientSocket::scanf(const char* format, ...) { + va_list argp; + va_start(argp, format); + char buf[256]; + + int len = read(buf, sizeof(buf) - 1); + if (len <= 0) + return 0; + buf[len] = '\0'; + + int ret = vsscanf(buf, format, argp); + va_end(argp); + return ret; +} + +int ClientSocket::write(char c) { + return write(&c, 1); +} + +int ClientSocket::write(char *buf, int size) { + int ret = socket->send(buf, size); + if (ret > 0) { + return ret; + } else { + writable = false; + return -1; + } +} + +int ClientSocket::printf(const char* format, ...) { + va_list argp; + va_start(argp, format); + char buf[256]; + + int len = vsnprintf(buf, sizeof(buf), format, argp); + va_end(argp); + return write(buf, len); +} + +void ClientSocket::close() { + if (socket) { + readable = false; + writable = false; + socket->resetOnEvent(); + socket->close(); + delete socket; + socket = 0; + } +} + +ClientSocket::operator bool() { + return connected(); +} + +void ClientSocket::setDebug(bool debug) { + this->debug = debug; +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/DatagramSocket.cpp Wed May 23 16:26:44 2012 +0000 @@ -0,0 +1,136 @@ +/* +Copyright (c) 2011, Senio Networks, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include "EthernetNetIf.h" +#include "SimpleSocket.h" +#include <stdarg.h> + +DatagramSocket::DatagramSocket(int port, bool debug) : bufsize(512), debug(debug) { + host = Host(IpAddr(), port); + createDatagramSocket(); +} + +DatagramSocket::DatagramSocket(Host host, bool debug) : host(host), bufsize(512), debug(debug) { + createDatagramSocket(); +} + +DatagramSocket::DatagramSocket(IpAddr ip, int port, bool debug) : host(ip, port), bufsize(512), debug(debug) { + createDatagramSocket(); +} + +DatagramSocket::~DatagramSocket() { + delete[] buf; +} + +void DatagramSocket::createDatagramSocket() { + udpSocket.setOnEvent(this, &DatagramSocket::onUDPSocketEvent); + UDPSocketErr err = udpSocket.bind(host); + DBG(DatagramError(err)); + buf = new char[bufsize + 1]; +} + +int DatagramSocket::write(char *buf, int length) { + if (length > bufsize) length = bufsize; + this->length = length; + memcpy(this->buf, buf, length); + return length; +} + +int DatagramSocket::printf(const char* format, ...) { + va_list argp; + va_start(argp, format); + int len = vsnprintf(buf, bufsize, format, argp); + va_end(argp); + if (len > 0) + length = len; + return len; +} + +void DatagramSocket::send(Host& host) { + DBG("Host = %d.%d.%d.%d:%d\n", host.getIp()[0], host.getIp()[1], host.getIp()[2], host.getIp()[3], host.getPort()); + Net::poll(); + int err = udpSocket.sendto(buf, length, &host); + DBG(DatagramError((UDPSocketErr) (err < 0 ? err : 0))); +} + +void DatagramSocket::send(IpAddr ip, int port) { + DBG("IP = %d.%d.%d.%d, Port = %d\n", ip[0], ip[1], ip[2], ip[3], port); + Host host(ip, port); + send(host); +} + +void DatagramSocket::send(char *name, int port) { + DBG("Name = %s, Port = %d\n", name, port); + Resolver resolver; + IpAddr ip = resolver.resolve(name, debug); + send(ip, port); +} + +int DatagramSocket::read(char *buf, int size) { + int len = length < size ? length : size; + if (len > 0) + memcpy(buf, this->buf, len); + return len; +} + +int DatagramSocket::scanf(const char* format, ...) { + va_list argp; + va_start(argp, format); + buf[length] = '\0'; + int ret = vsscanf(buf, format, argp); + va_end(argp); + return ret; +} + +int DatagramSocket::receive(Host *host, float timeout) { + timer.reset(); + timer.start(); + readable = false; + length = 0; + + do { + Net::poll(); + if (readable) { + Host host2; + length = udpSocket.recvfrom(buf, bufsize, &host2); + if (length > 0 && host) + *host = host2; + break; + } + } while (timer.read() < timeout); + + return length; +} + +void DatagramSocket::setDebug(bool debug) { + this->debug = debug; +} + +void DatagramSocket::onUDPSocketEvent(UDPSocketEvent e) { + DBG(DatagramEvent(e)); + + switch (e) { + case UDPSOCKET_READABLE: //The only event for now + readable = true; + break; + } +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Debug.h Wed May 23 16:26:44 2012 +0000 @@ -0,0 +1,28 @@ +/* +Copyright (c) 2011, Senio Networks, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef DEBUG_H +#define DEBUG_H + +#define DBG(...) if (debug) { ::printf("%s:%d: ", __FUNCTION__, __LINE__); ::printf(__VA_ARGS__); } else; + +#endif \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/EventsErrors.cpp Wed May 23 16:26:44 2012 +0000 @@ -0,0 +1,141 @@ +/* +Copyright (c) 2011, Senio Networks, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include "SimpleSocket.h" + +SocketEvent::SocketEvent(TCPSocketEvent event) : event(event) {} + +char *SocketEvent::toString() { + switch (event) { + case TCPSOCKET_CONNECTED: + return "TCPSOCKET_CONNECTED: Connected to host.\n"; + case TCPSOCKET_ACCEPT: + return "TCPSOCKET_ACCEPT: Client is connected, must call accept() to get a new Socket.\n"; + case TCPSOCKET_READABLE: + return "TCPSOCKET_READABLE: Data in buf.\n"; + case TCPSOCKET_WRITEABLE: + return "TCPSOCKET_WRITEABLE: Can write data to buf.\n"; + case TCPSOCKET_CONTIMEOUT: + return "TCPSOCKET_CONTIMEOUT: Connection timed out.\n"; + case TCPSOCKET_CONRST: + return "TCPSOCKET_CONRST: Connection was reset by remote host.\n"; + case TCPSOCKET_CONABRT: + return "TCPSOCKET_CONABRT: Connection was aborted.\n"; + case TCPSOCKET_ERROR: + return "TCPSOCKET_ERROR: Unknown error.\n"; + case TCPSOCKET_DISCONNECTED: + return "TCPSOCKET_DISCONNECTED: Disconnected.\n"; + default: + static char buf[32]; + sprintf(buf, "UNKNOWN EVENT (%d).\n", event); + return buf; + } +} + +SocketEvent::operator char *() { + return toString(); +} + +SocketEvent::operator int() { + return event; +} + +SocketError::SocketError(TCPSocketErr err) : err(err) {}; + +char *SocketError::toString() { + switch (err) { + case TCPSOCKET_SETUP: + return "TCPSOCKET_SETUP: TCPSocket not properly configured.\n"; + case TCPSOCKET_TIMEOUT: + return "TCPSOCKET_TIMEOUT: Connection timed out.\n"; + case TCPSOCKET_IF: + return "TCPSOCKET_IF: Interface has problems, does not exist or is not initialized.\n"; + case TCPSOCKET_MEM: + return "TCPSOCKET_MEM: Not enough memory.\n"; + case TCPSOCKET_INUSE: + return "TCPSOCKET_INUSE: Interface/Port is in use.\n"; + case TCPSOCKET_EMPTY: + return "TCPSOCKET_EMPTY: Connections queue is empty.\n"; + case TCPSOCKET_RST: + return "TCPSOCKET_RST: Connection was reset by remote host.\n"; + case TCPSOCKET_OK: + return "TCPSOCKET_OK: Success.\n"; + default: + return "TCPSOCKET unknown error occurred.\n"; + } +} + +SocketError::operator char *() { + return toString(); +} + +SocketError::operator int() { + return err; +} + +DatagramEvent::DatagramEvent(UDPSocketEvent event) : event(event) {} + +char *DatagramEvent::toString() { + switch (event) { + case UDPSOCKET_READABLE: + return "UDPSOCKET_READABLE: Data in buf.\n"; + default: + static char buf[32]; + sprintf(buf, "UNKNOWN EVENT (%d).\n", event); + return buf; + } +} + +DatagramEvent::operator char *() { + return toString(); +} + +DatagramEvent::operator int() { + return event; +} + +DatagramError::DatagramError(UDPSocketErr err) : err(err) {}; + +char *DatagramError::toString() { + switch (err) { + case UDPSOCKET_SETUP: + return "UDPSOCKET_SETUP: UDPSocket not properly configured.\n"; + case UDPSOCKET_IF: + return "UDPSOCKET_IF: Interface has problems, does not exist or is not initialized.\n"; + case UDPSOCKET_MEM: + return "UDPSOCKET_MEM: Not enough memory.\n"; + case UDPSOCKET_INUSE: + return "UDPSOCKET_INUSE: Interface/Port is in use.\n"; + case UDPSOCKET_OK: + return "UDPSOCKET_OK: Success.\n"; + default: + return "UDPSOCKET unknown error occurred.\n"; + } +} + +DatagramError::operator char *() { + return toString(); +} + +DatagramError::operator int() { + return err; +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Resolver.cpp Wed May 23 16:26:44 2012 +0000 @@ -0,0 +1,49 @@ +/* +Copyright (c) 2011, Senio Networks, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include "SimpleSocket.h" + +Resolver::Resolver() {} + +IpAddr Resolver::resolve(char *name, bool debug) { + IpAddr ip; + DNSRequest request; + + if (request.resolve(name) == DNS_OK) { + replied = false; + request.setOnReply(this, &Resolver::onReply); + while (!replied) + Net::poll(); + if (reply == DNS_FOUND) + request.getResult(&ip); + } + + DBG("%s -> %d.%d.%d.%d\n", name, ip[0], ip[1], ip[2], ip[3]); + + return ip; +} + + +void Resolver::onReply(DNSReply reply) { + replied = true; + this->reply = reply; +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ServerSocket.cpp Wed May 23 16:26:44 2012 +0000 @@ -0,0 +1,75 @@ +/* +Copyright (c) 2011, Senio Networks, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include "SimpleSocket.h" + +ServerSocket::ServerSocket(int port, bool debug) + : accepted(false), debug(debug) { + ssocket.setOnEvent(this, &ServerSocket::onTCPSocketEvent); + + SocketError bindErr = ssocket.bind(Host(IpAddr(), port)); + DBG("Init bind... %s\n", bindErr.toString()); + + SocketError listenErr = ssocket.listen(); + DBG("Init listen... %s\n", listenErr.toString()); +} + +void ServerSocket::onTCPSocketEvent(TCPSocketEvent e) { + DBG(SocketEvent(e)); + + switch (e) { + case TCPSOCKET_ACCEPT: + accepted = true; + break; + case TCPSOCKET_DISCONNECTED: + ssocket.close(); + break; + } +} + +ClientSocket ServerSocket::accept(float timeout) { + TCPSocket* socket = 0; + Host host; + timer.reset(); + timer.start(); + + do { + Net::poll(); + if (accepted) { + accepted = false; + SocketError err = ssocket.accept(&host, &socket); + if (!err) { + IpAddr ip = host.getIp(); + DBG("TCP connection from %d.%d.%d.%d\n", ip[0], ip[1], ip[2], ip[3]); + break; + } else { + DBG("accept error:%s\n", err.toString()); + } + } + } while (timer.read() < timeout); + + return ClientSocket(host.getIp(), socket, debug); +} + +void ServerSocket::setDebug(bool debug) { + this->debug = debug; +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SimpleSocket.h Wed May 23 16:26:44 2012 +0000 @@ -0,0 +1,490 @@ +/* +Copyright (c) 2011, Senio Networks, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef SIMPLE_SOCKET_H +#define SIMPLE_SOCKET_H + +#include "mbed.h" +#include "TCPSocket.h" +#include "UDPSocket.h" +#include "DNSRequest.h" +#include "Debug.h" + +/** + * wrapper class of TCPSocketEvent + */ +class SocketEvent { +public: + /** + * creates a SocketEvent wrapper object. + * + * @param event TCP socket event number + */ + SocketEvent(TCPSocketEvent event); + + /** + * @returns a string representation of the event + */ + char *toString(); + + /** + * an operator overloading for toString() + */ + operator char *(); + + /** + * an operator overloading for TCP socket event number + */ + operator int(); + +private: + TCPSocketEvent event; +}; + +/** + * wrapper class of TCPSocketErr + */ +class SocketError { +public: + /** + * creates a SocketError wrapper object. + * + * @param err TCP socket error number + */ + SocketError(TCPSocketErr err); + + /** + * @returns a string representation of the error + */ + char *toString(); + + /** + * an operator overloading for toString(). + */ + operator char *(); + + /** + * an operator overloading for TCP socket error number. + */ + operator int(); + +private: + TCPSocketErr err; +}; + +/** + * wrapper class of UDPSocketEvent + */ +class DatagramEvent { +public: + /** + * creates a DatagramEvent wrapper object. + * + * @param event UDP socket event number + */ + DatagramEvent(UDPSocketEvent event); + + /** + * @returns a string representation of the event + */ + char *toString(); + + /** + * an operator overloading for toString() + */ + operator char *(); + + /** + * an operator overloading for UDP socket event number + */ + operator int(); + +private: + UDPSocketEvent event; +}; + +/** + * wrapper class of UDPSocketErr + */ +class DatagramError { +public: + /** + * creates a DatagramError wrapper object. + * + * @param err UDP socket error number + */ + DatagramError(UDPSocketErr err); + + /** + * @returns a string representation of the error + */ + char *toString(); + + /** + * an operator overloading for toString(). + */ + operator char *(); + + /** + * an operator overloading for UDP socket error number. + */ + operator int(); + +private: + UDPSocketErr err; +}; + +/** + * client socket class for communication endpoint + */ +class ClientSocket { + friend class ServerSocket; + +public: + /** + * creates a ClientSocket object. + * + * @param ip IP address of the socket + * @param port port number of the socket + * @param timeout max waiting time until connected + * @param debug set true to display debugging information + */ + ClientSocket(IpAddr ip, int port, float timeout = 60, bool debug = false); + + /** + * creates a ClientSocket object. + * + * @param hostname domain/host name of the socket + * @param port port number of the socket + * @param timeout max waiting time until connected + * @param debug set true to display debugging information + */ + ClientSocket(char *hostname, int port, float timeout = 60, bool debug = false); + + + /** + * copy constructor + */ + ClientSocket(const ClientSocket& that); + + /** + * gets the IP address. + * + * @returns IP address of the socket + */ + IpAddr getIp(); + + /** + * gets the connection status. + * + * @returns true if connected, false otherwise + */ + bool connected(); + + /** + * tests if input data available or not. + * + * @returns true if incomming data available, false otherwise + */ + bool available(); + + /** + * reads a char. + * + * @returns a char from the socket input stream, or -1 if no data available + */ + int read(); + + /** + * reads data into the specified buffer. + * + * @param buf input buffer + * @param size size of the buffer + * + * @returns the size of the data read + */ + int read(char *buf, int size); + + /** + * scans input stream according to the specified format string. + * + * @params format scanf format string, corresponding arguments follow + * + * @returns number of input items assigned + */ + int scanf(const char *format, ...); + + /** + * writes a char to the output stream. + * + * @param c a char to be written to the socket output stream + * + * @returns positive int if succeeded, or -1 if failed + */ + int write(char c); + + /** + * writes an array of chars to the output stream. + * + * @param buf an array of chars to be written to the socket output stream + * @param size number of chars in the array + * + * @returns number of chars written, or -1 if failed + */ + int write(char *buf, int size); + + /** + * prints the data to the socket output stream according to the specified format string. + * + * @param format printf format string, corresponding arguments follow + * + * @returns number of chars written, or -1 if failed + */ + int printf(const char *format, ...); + + /** + * closes the connection. + */ + void close(); + + /** + * sets debug mode. + * + * @param debug true to display debugging information + */ + void setDebug(bool debug); + + /** + * an operator shorthand for connected() + */ + operator bool(); + +private: + enum ConnectionState {CONNECTING, CONNECTED, DISCONNECTED}; + IpAddr ip; + TCPSocket *socket; + bool readable; + bool writable; + bool preread; + char preread_byte; + ConnectionState state; + bool disconnected; + bool debug; + + ClientSocket(IpAddr ip, TCPSocket *socket, bool debug = false); + void createClientSocket(IpAddr ip, int port, float timeout); + void onTCPSocketEvent(TCPSocketEvent e); +}; + +/** + * server socket class for handling incoming communication requests + */ +class ServerSocket { +public: + /** + * creates a ServerSocket object. + * + * @param port port for server socket + * @param debug set true to run in debug mode + */ + ServerSocket(int port, bool debug = false); + + /** + * waits for a client to connect. + * + * @param timeout max time (in msec) for waiting for clients to connect + * + * @returns a socket to talk with the connecting client or a disconnected socket if timed out + */ + ClientSocket accept(float timeout = 5.0); + + /** + * sets debug mode. + * + * @param debug true to run in debug mode, false to normal mode + */ + void setDebug(bool debug); + +private: + TCPSocket ssocket; + bool accepted; + Timer timer; + bool debug; + + void onTCPSocketEvent(TCPSocketEvent e); +}; + +/** + * datagram socket class for UDP + */ +class DatagramSocket { +public: + /** + * creates a DatagramSocket object with the specified port number. + * + * @param port port for datagram socket + * @param debug set true to run in debug mode + */ + DatagramSocket(int port = 0, bool debug = false); + + /** + * creates a DatagramSocket object with the specified host. + * + * @param host host for datagram socket + * @param debug set true to run in debug mode + */ + DatagramSocket(Host host, bool debug = false); + + /** + * creates a DatagramSocket object with the specified ip address and port number. + * + * @param ip address for datagram socket + * @param port port for datagram socket + * @param debug set true to run in debug mode + */ + DatagramSocket(IpAddr ip, int port, bool debug = false); + + /** + * destructor for DatagramSocket. + */ + ~DatagramSocket(); + + /** + * writes data to the socket + * + * @param buf buffer for data to be written + * @param length data length contained in the buffer + * + * @returns number of chars written + */ + int write(char *buf, int length); + + /** + * prints data to the socket according to the specified format string. + * + * @param format printf format string, corresponding arguments follow + * + * @returns number of chars written + */ + int printf(const char* format, ...); + + /** + * sends data packet to the specified host. + * + * @param host destination of this packet to be sent + */ + void send(Host& host); + + /** + * sends data packet to the specified IP address and port. + * + * @param ip destination IP address of the data packet + * @param port destination port number of the data packet + */ + void send(IpAddr ip, int port); + + /** + * sends data packet to the destination of specified name and port. + * + * @param name destination host name of the data packet + * @param port destination port number of the data packet + */ + void send(char *name, int port); + + /** + * reads data packet from the datagram socket. + * + * @param buf buffer to store data + * @param size size of the buf + * + * @returns number of bytes actually stored + */ + int read(char *buf, int size); + + /** + * scans data according to the specified format string. + * + * @param format scanf format string, corresponding arguments follow + * + * @returns number of input items assigned + */ + int scanf(const char* format, ...); + + /** + * receives data packet. + * + * @param host pointer to the Host object to store the host info, if specified + * @param timeout maximum waiting time before data packet comes in + * + * @returns number of bytes received + */ + int receive(Host *host = 0, float timeout = 5.0); + + /** + * sets debug mode. + * + * @param debug true to run in debug mode, false to normal mode + */ + void setDebug(bool debug); + +private: + Host host; + UDPSocket udpSocket; + Timer timer; + bool readable; + int length; + int bufsize; + char *buf; + bool debug; + + void createDatagramSocket(); + void onUDPSocketEvent(UDPSocketEvent e); +}; + +/** + * a simple DNS resolver + */ +class Resolver { +public: + /** + * creates a Resolver object + */ + Resolver(); + + /** + * resolves the specified domain/host name and returns its IP address. + * + * @param name domain/host name to be resolved or IP address in "nnn.nnn.nnn.nnn" format + * @param debug true to display debugging information + * + * @returns resolved IP address object + */ + IpAddr resolve(char *name, bool debug = false); + +private: + bool replied; + DNSReply reply; + + void onReply(DNSReply reply); +}; + +#endif \ No newline at end of file