mbed socket API
Dependents: EthernetInterface EthernetInterface_RSF EthernetInterface EthernetInterface ... more
Deprecated
This is an mbed 2 sockets library. For mbed 5, network sockets have been revised to better support additional network stacks and thread safety here.
Revision 3:e6474399e057, committed 2012-07-25
- Comitter:
- emilmont
- Date:
- Wed Jul 25 14:59:37 2012 +0000
- Parent:
- 2:b227d242f3c7
- Child:
- 4:75988d748e4d
- Commit message:
- Split TCPSocketServer from TCPSocketConnection
Changed in this revision
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Socket.cpp Wed Jul 25 14:59:37 2012 +0000 @@ -0,0 +1,72 @@ +/* Copyright (C) 2012 mbed.org, MIT License + * + * 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 "Socket/Socket.h" +#include <cstring> + +using std::memset; + +Socket::Socket() : _sock_fd(-1) { + +} + +int Socket::init(int type) { + if (_sock_fd != -1) + return -1; + + int fd = lwip_socket(AF_INET, type, 0); + if (fd < 0) + return -1; + + _sock_fd = fd; + return 0; +} + + +void Socket::set_timeout(int timeout) { + _timeout.tv_sec = timeout / 1000; + _timeout.tv_usec = (timeout - (_timeout.tv_sec * 1000)) * 1000; +} + +int Socket::select(fd_set* readset, fd_set* writeset) { + if ((_timeout.tv_sec == 0) && (_timeout.tv_usec == 0)) + return 0; + + FD_ZERO(&_fdSet); + FD_SET(_sock_fd, &_fdSet); + + int ret = lwip_select(FD_SETSIZE, readset, writeset, NULL, &_timeout); + return (ret <= 0 || !FD_ISSET(_sock_fd, &_fdSet)) ? (-1) : (0); +} + +int Socket::wait_readable(void) { + return select(&_fdSet, NULL); +} + +int Socket::wait_writable(void) { + return select(NULL, &_fdSet); +} + +int Socket::close() { + if (_sock_fd < 0) + return -1; + + lwip_close(_sock_fd); + _sock_fd = -1; + + return 0; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Socket.h Wed Jul 25 14:59:37 2012 +0000 @@ -0,0 +1,54 @@ +/* Copyright (C) 2012 mbed.org, MIT License + * + * 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 SOCKET_H_ +#define SOCKET_H_ + +#include "lwip/sockets.h" +#include "lwip/netdb.h" + +//DNS +inline struct hostent *gethostbyname(const char *name) { + return lwip_gethostbyname(name); +} + +inline int gethostbyname_r(const char *name, struct hostent *ret, char *buf, size_t buflen, struct hostent **result, int *h_errnop) { + return lwip_gethostbyname_r(name, ret, buf, buflen, result, h_errnop); +} + +class Socket { +public: + Socket(); + + int close(); + +protected: + int _sock_fd; + int init(int type); + + void set_timeout(int timeout); + int wait_readable(void); + int wait_writable(void); + +private: + // At the moment, we assume a simple single threaded access to the socket + struct timeval _timeout; + fd_set _fdSet; + int select(fd_set* readset, fd_set* writeset); +}; + +#endif /* SOCKET_H_ */
--- a/TCPSocket.cpp Mon Jul 23 11:52:50 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,278 +0,0 @@ -/* Copyright (C) 2012 mbed.org, MIT License - * - * 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 "TCPSocket.h" - -#include <cstring> - -using std::memset; - -TCPSocket::TCPSocket() : m_sock(-1) -{ -} - -TCPSocket::~TCPSocket() -{ - close(); //Don't want to leak -} - -int TCPSocket::connect(char* host, int port, int timeout) -{ - int ret = init(); - if( ret < 0 ) - { - return -1; - } - - //Populate m_remoteHost - std::memset(&m_remoteHost, 0, sizeof(struct sockaddr_in)); - - //Resolve DNS address or populate hard-coded IP address - struct hostent *server = gethostbyname(host); - if(server == NULL) - { - return -1; //Could not resolve address - } - std::memcpy((char*)&m_remoteHost.sin_addr.s_addr, (char*)server->h_addr_list[0], server->h_length); - - m_remoteHost.sin_family = AF_INET; - m_remoteHost.sin_port = htons(port); - - ret = ::connect(m_sock, (const struct sockaddr *)&m_remoteHost, sizeof(m_remoteHost)); - if (ret < 0) - { - close(); - return -1; - } - - return 0; -} - -int TCPSocket::bind(int port) -{ - int ret = init(); - if( ret < 0 ) - { - return -1; - } - - struct sockaddr_in localHost; - std::memset(&localHost, 0, sizeof(localHost)); - - localHost.sin_family = AF_INET; - localHost.sin_port = htons(port); - localHost.sin_addr.s_addr = INADDR_ANY; - - ret = ::bind(m_sock, (const struct sockaddr *)&localHost, sizeof(localHost)); - if (ret < 0) - { - close(); - return -1; - } - - return 0; -} - -int TCPSocket::listen(int max) -{ - if( m_sock < 0 ) - { - return -1; - } - - int ret = ::listen(m_sock, max); - if (ret < 0) - { - close(); - return -1; - } - - return 0; -} - -int TCPSocket::accept(TCPSocket& socket, char** host, int* port, int timeout) -{ - if( m_sock < 0 ) - { - return -1; - } - - //Populate m_remoteHost - std::memset(&socket.m_remoteHost, 0, sizeof(struct sockaddr_in)); - - struct timeval t_val; //t_val will be decremented on each call to select() - t_val.tv_sec = timeout / 1000; - t_val.tv_usec = (timeout - (t_val.tv_sec * 1000)) * 1000; - //Wait for socket to get some connection request (i.e. to be "readable") - //Creating FS set - fd_set socksSet; - FD_ZERO(&socksSet); - FD_SET(m_sock, &socksSet); - int ret = ::select(FD_SETSIZE, &socksSet, NULL, NULL, &t_val); - if(ret <= 0 || !FD_ISSET(m_sock, &socksSet)) - { - return -1; //Timeout - } - - socklen_t newSockRemoteHostLen = sizeof(socket.m_remoteHost); - - ret = ::accept(m_sock, (struct sockaddr*)&socket.m_remoteHost, &newSockRemoteHostLen); - if( ret < 0 ) - { - return -1; //Accept failed - } - - socket.m_sock = ret; //ret is the new socket's fd - socket.m_closedByRemoteHost = false; - - static char hostBuf[16]; - inet_ntoa_r(socket.m_remoteHost.sin_addr, hostBuf, sizeof(hostBuf)); - - *host = hostBuf; - *port = ntohs(socket.m_remoteHost.sin_port); - - return 0; -} - -// -1 if unsuccessful, else number of bytes written -int TCPSocket::send(char* data, int length, int timeout) -{ - if( m_sock < 0 ) - { - return -1; - } - - if( m_closedByRemoteHost ) - { - return 0; - } - - size_t writtenLen = 0; - struct timeval t_val; //t_val will be decremented on each call to select() - t_val.tv_sec = timeout / 1000; - t_val.tv_usec = (timeout - (t_val.tv_sec * 1000)) * 1000; - while(writtenLen < length) - { - //Wait for socket to be writeable - //Creating FS set - fd_set socksSet; - FD_ZERO(&socksSet); - FD_SET(m_sock, &socksSet); - - int ret = ::select(FD_SETSIZE, NULL, &socksSet, NULL, &t_val); - if(ret <= 0 || !FD_ISSET(m_sock, &socksSet)) - { - return writtenLen; //Timeout -- FIXME should we return -1 or writtenLength ? - } - - ret = ::send(m_sock, data + writtenLen, length - writtenLen, 0); - if( ret > 0) - { - writtenLen += ret; - continue; - } - else if( ret == 0 ) - { - m_closedByRemoteHost = true; - return writtenLen; //Connection was closed by remote host -- FIXME how do we signal that the connection was closed ? - } - else - { - return -1; //Connnection error - } - } - - return writtenLen; -} - -// -1 if unsuccessful, else number of bytes received -int TCPSocket::receive(char* data, int length, int timeout) -{ - if( m_sock < 0 ) - { - return -1; - } - - if( m_closedByRemoteHost ) - { - return 0; - } - - size_t readLen = 0; - struct timeval t_val; //t_val will be decremented on each call to select() - t_val.tv_sec = timeout / 1000; - t_val.tv_usec = (timeout - (t_val.tv_sec * 1000)) * 1000; - while(readLen < length) - { - //Wait for socket to be readable - //Creating FS set - fd_set socksSet; - FD_ZERO(&socksSet); - FD_SET(m_sock, &socksSet); - int ret = ::select(FD_SETSIZE, &socksSet, NULL, NULL, &t_val); - if(ret <= 0 || !FD_ISSET(m_sock, &socksSet)) - { - return readLen; //Timeout -- FIXME should we return -1 or writtenLength ? - } - - ret = ::recv(m_sock, data + readLen, length - readLen, 0); - if( ret > 0) - { - readLen += ret; - continue; - } - else if( ret == 0 ) - { - m_closedByRemoteHost = true; - return readLen; //Connection was closed by remote host -- FIXME how do we signal that the connection was closed ? - } - else - { - return -1; //Connnection error - } - } - return readLen; -} - -int TCPSocket::close() -{ - if( m_sock < 0 ) - { - return -1; - } - - ::close(m_sock); - m_sock = -1; - - return 0; -} - -int TCPSocket::init() -{ - if( m_sock != -1 ) - { - return -1; - } - m_sock = ::socket(AF_INET, SOCK_STREAM, 0); //TCP socket - if (m_sock < 0) - { - return -1; //Could not create socket (Out of memory / available descriptors) - } - m_closedByRemoteHost = false; - return 0; -}
--- a/TCPSocket.h Mon Jul 23 11:52:50 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,96 +0,0 @@ -/* Copyright (C) 2012 mbed.org, MIT License - * - * 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 TCPSOCKET_H -#define TCPSOCKET_H - -#include "Socket/socket.h" - -/** -This is a C++ abstraction for TCP networking sockets. -*/ -class TCPSocket -{ - public: - - /** Instantiate a TCP Socket. - */ - TCPSocket(); - - ~TCPSocket(); - - /** Connect the TCP Socket to the following host. - \param host The host to connect to. It can either be an IP Address or a hostname that will be resolved with DNS. - \param port The host's port to connect to. - \param timeout The maximum time in ms during which to try to connect. - \return 0 on success, -1 on failure. - */ - int connect(char* host, int port, int timeout = 0); - - /** Bind a socket to a specific port. - For a listening socket, bind the socket to the following port. The socket will start listening for incoming connections on this port on the call to listen(). - \param port The port to listen for incoming connections on. - \return 0 on success, -1 on failure. - */ - int bind(int port); - - /** Start listening for incoming connections. - \param max The maximum number of connections that can be accepted. - \return 0 on success, -1 on failure. - */ - int listen(int max); - - /** Accept a new connection. - \param socket A socket instance that will handle the incoming connection. - \param host The reference that will point to the client's IP address. - \param port The reference that will point to the client's port. - \param timeout The maximum time in ms during which to wait for an incoming connection. - \return 0 on success, -1 on failure. - */ - int accept(TCPSocket& socket, char** host, int* port, int timeout = 0); - - /** Send data to the remote host. - \param data The buffer to send to the host. - \param length The length of the buffer to send. - \param timeout The maximum amount of time in ms to wait while trying to send the buffer. - \return the number of written bytes on success (>=0) or -1 on failure - */ - int send(char* data, int length, int timeout = 0); - - /** Receive data from the remote host. - \param data The buffer in which to store the data received from the host. - \param length The maximum length of the buffer. - \param timeout The maximum amount of time in ms to wait while trying to receive data. - \return the number of received bytes on success (>=0) or -1 on failure - */ - int receive(char* data, int length, int timeout = 0); - - /** Close the socket. - */ - int close(); - - private: - int init(); - - int m_sock; - bool m_closedByRemoteHost; - struct sockaddr_in m_remoteHost; - -}; - -#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/TCPSocketConnection.cpp Wed Jul 25 14:59:37 2012 +0000 @@ -0,0 +1,146 @@ +/* Copyright (C) 2012 mbed.org, MIT License + * + * 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 "TCPSocketConnection.h" +#include <cstring> + +using std::memset; +using std::memcpy; + +TCPSocketConnection::TCPSocketConnection() : + _closedByRemoteHost(false) { + memset(&_remoteHost, 0, sizeof(struct sockaddr_in)); + _ipAddress[0] = '\0'; +} + +int TCPSocketConnection::connect(char* host, int port) { + if (init(SOCK_STREAM) < 0) + return -1; + + //Resolve DNS address or populate hard-coded IP address + struct hostent *server = gethostbyname(host); + if (server == NULL) + return -1; //Could not resolve address + + memcpy((char*) &_remoteHost.sin_addr.s_addr, + (char*) server->h_addr_list[0], server->h_length); + + _remoteHost.sin_family = AF_INET; + _remoteHost.sin_port = htons(port); + if (lwip_connect(_sock_fd, (const struct sockaddr *) &_remoteHost, sizeof(_remoteHost)) < 0) { + close(); + return -1; + } + + return 0; +} + +int TCPSocketConnection::send(char* data, int length, int timeout) { + if ((_sock_fd < 0) || _closedByRemoteHost) + return -1; + + set_timeout(timeout); + if (wait_writable() != 0) + return -1; + + int n = lwip_send(_sock_fd, data, length, 0); + _closedByRemoteHost = (n == 0); + + return n; +} + +// -1 if unsuccessful, else number of bytes written +int TCPSocketConnection::send_all(char* data, int length, int timeout) { + if ((_sock_fd < 0) || _closedByRemoteHost) + return -1; + + size_t writtenLen = 0; + set_timeout(timeout); + while (writtenLen < length) { + // Wait for socket to be writeable + if (wait_writable() != 0) + return writtenLen; //Timeout -- FIXME should we return -1 or writtenLength ? + + int ret = lwip_send(_sock_fd, data + writtenLen, length - writtenLen, 0); + if (ret > 0) { + writtenLen += ret; + continue; + } else if (ret == 0) { + _closedByRemoteHost = true; + return writtenLen; //Connection was closed by remote host -- FIXME how do we signal that the connection was closed ? + } else { + return -1; //Connnection error + } + } + + return writtenLen; +} + +int TCPSocketConnection::receive(char* data, int length, int timeout) { + if ((_sock_fd < 0) || _closedByRemoteHost) + return -1; + + set_timeout(timeout); + if (wait_readable() != 0) + return -1; + + int n = lwip_recv(_sock_fd, data, length, 0); + _closedByRemoteHost = (n == 0); + + return n; +} + +// -1 if unsuccessful, else number of bytes received +int TCPSocketConnection::receive_all(char* data, int length, int timeout) { + if ((_sock_fd < 0) || _closedByRemoteHost) + return -1; + + size_t readLen = 0; + set_timeout(timeout); + while (readLen < length) { + //Wait for socket to be readable + if (wait_readable() != 0) + return readLen; //Timeout -- FIXME should we return -1 or writtenLength ? + + int ret = lwip_recv(_sock_fd, data + readLen, length - readLen, 0); + if (ret > 0) { + readLen += ret; + } else if (ret == 0) { + _closedByRemoteHost = true; + return readLen; //Connection was closed by remote host -- FIXME how do we signal that the connection was closed ? + } else { + return -1; //Connnection error + } + } + return readLen; +} + +char* TCPSocketConnection::get_address() { + if (_ipAddress[0] == '\0') { + if (_remoteHost.sin_addr.s_addr == 0) + return NULL; + inet_ntoa_r(_remoteHost.sin_addr, _ipAddress, sizeof(_ipAddress)); + } + return _ipAddress; +} +int TCPSocketConnection::get_port() { + return ntohs(_remoteHost.sin_port); +} + +TCPSocketConnection::~TCPSocketConnection() { + close(); //Don't want to leak +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/TCPSocketConnection.h Wed Jul 25 14:59:37 2012 +0000 @@ -0,0 +1,87 @@ +/* Copyright (C) 2012 mbed.org, MIT License + * + * 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 TCPSOCKET_H +#define TCPSOCKET_H + +#include "Socket/Socket.h" + +/** +This is a C++ abstraction for TCP networking sockets. +*/ +class TCPSocketConnection : public Socket { + friend class TCPSocketServer; + +public: + /** Instantiate a TCP Socket. + */ + TCPSocketConnection(); + + ~TCPSocketConnection(); + + /** Connect the TCP Socket to the following host. + \param host The host to connect to. It can either be an IP Address or a hostname that will be resolved with DNS. + \param port The host's port to connect to. + \return 0 on success, -1 on failure. + */ + int connect(char* host, int port); + + /** Send data to the remote host. + \param data The buffer to send to the host. + \param length The length of the buffer to send. + \param timeout The maximum amount of time in ms to wait while trying to send the buffer. + \return the number of written bytes on success (>=0) or -1 on failure + */ + int send(char* data, int length, int timeout=0); + + /** Send data to the remote host. + \param data The buffer to send to the host. + \param length The length of the buffer to send. + \param timeout The maximum amount of time in ms to wait while trying to send the buffer. + \return the number of written bytes on success (>=0) or -1 on failure + */ + int send_all(char* data, int length, int timeout=0); + + /** Receive data from the remote host. + \param data The buffer in which to store the data received from the host. + \param length The maximum length of the buffer. + \param timeout The maximum amount of time in ms to wait while trying to receive data. + \return the number of received bytes on success (>=0) or -1 on failure + */ + int receive(char* data, int length, int timeout=0); + + /** Receive data from the remote host. + \param data The buffer in which to store the data received from the host. + \param length The maximum length of the buffer. + \param timeout The maximum amount of time in ms to wait while trying to receive data. + \return the number of received bytes on success (>=0) or -1 on failure + */ + int receive_all(char* data, int length, int timeout=0); + + char* get_address(); + int get_port(); + +private: + char _ipAddress[16]; + + bool _closedByRemoteHost; + struct sockaddr_in _remoteHost; + +}; + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/TCPSocketServer.cpp Wed Jul 25 14:59:37 2012 +0000 @@ -0,0 +1,79 @@ +/* Copyright (C) 2012 mbed.org, MIT License + * + * 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 "TCPSocketServer.h" + +#include <cstring> + +using std::memset; +using std::memcpy; + +TCPSocketServer::TCPSocketServer() { + +} + +int TCPSocketServer::bind(int port) { + if (init(SOCK_STREAM) < 0) + return -1; + + struct sockaddr_in localHost; + memset(&localHost, 0, sizeof(localHost)); + + localHost.sin_family = AF_INET; + localHost.sin_port = htons(port); + localHost.sin_addr.s_addr = INADDR_ANY; + + if (lwip_bind(_sock_fd, (const struct sockaddr *) &localHost, sizeof(localHost)) < 0) { + close(); + return -1; + } + + return 0; +} + +int TCPSocketServer::listen(int max) { + if (_sock_fd < 0) + return -1; + + if (lwip_listen(_sock_fd, max) < 0) { + close(); + return -1; + } + + return 0; +} + +int TCPSocketServer::accept(TCPSocketConnection& connection, int timeout) { + if (_sock_fd < 0) + return -1; + + set_timeout(timeout); + if (wait_readable() != 0) + return -1; + + socklen_t newSockRemoteHostLen = sizeof(connection._remoteHost); + int fd = lwip_accept(_sock_fd, (struct sockaddr*) &connection._remoteHost, &newSockRemoteHostLen); + if (fd < 0) + return -1; //Accept failed + connection._sock_fd = fd; + + return 0; +} + +TCPSocketServer::~TCPSocketServer() { + close(); //Don't want to leak +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/TCPSocketServer.h Wed Jul 25 14:59:37 2012 +0000 @@ -0,0 +1,52 @@ +/* Copyright (C) 2012 mbed.org, MIT License + * + * 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 TCPSOCKETSERVER_H +#define TCPSOCKETSERVER_H + +#include "Socket/Socket.h" +#include "TCPSocketConnection.h" + +class TCPSocketServer : Socket { + public: + /** Instantiate a TCP Socket. + */ + TCPSocketServer(); + + ~TCPSocketServer(); + + /** Bind a socket to a specific port. + For a listening socket, bind the socket to the following port. The socket will start listening for incoming connections on this port on the call to listen(). + \param port The port to listen for incoming connections on. + \return 0 on success, -1 on failure. + */ + int bind(int port); + + /** Start listening for incoming connections. + \param max The maximum number of connections that can be accepted. + \return 0 on success, -1 on failure. + */ + int listen(int max); + + /** Accept a new connection. + \param socket A socket instance that will handle the incoming connection. + \return 0 on success, -1 on failure. + */ + int accept(TCPSocketConnection& connection, int timeout=0); +}; + +#endif
--- a/UDPSocket.cpp Mon Jul 23 11:52:50 2012 +0000 +++ b/UDPSocket.cpp Wed Jul 25 14:59:37 2012 +0000 @@ -22,183 +22,98 @@ using std::memset; -UDPSocket::UDPSocket() : m_sock(-1) -{ -} - -UDPSocket::~UDPSocket() -{ - close(); //Don't want to leak +UDPSocket::UDPSocket() { } -int UDPSocket::bind(int port) -{ - int ret = init(); - if( ret < 0 ) - { - return -1; - } - - struct sockaddr_in localHost; - std::memset(&localHost, 0, sizeof(localHost)); - - localHost.sin_family = AF_INET; - localHost.sin_port = htons(port); - localHost.sin_addr.s_addr = INADDR_ANY; - - ret = ::bind(m_sock, (const struct sockaddr *)&localHost, sizeof(localHost)); - if (ret < 0) - { - close(); - return -1; - } - - return 0; +// Server initialization +int UDPSocket::bind(int port) { + if (init(SOCK_DGRAM) < 0) + return -1; + + struct sockaddr_in localHost; + std::memset(&localHost, 0, sizeof(localHost)); + + localHost.sin_family = AF_INET; + localHost.sin_port = htons(port); + localHost.sin_addr.s_addr = INADDR_ANY; + + if (lwip_bind(_sock_fd, (const struct sockaddr *) &localHost, sizeof(localHost)) < 0) { + close(); + return -1; + } + + return 0; } // -1 if unsuccessful, else number of bytes written -int UDPSocket::sendTo(char* data, int length, char* host, int port, int timeout) -{ - if( m_sock < 0 ) - { - return -1; - } - - struct sockaddr_in remoteHost; - - //Populate m_remoteHost - std::memset(&remoteHost, 0, sizeof(struct sockaddr_in)); - - //Resolve DNS address or populate hard-coded IP address - struct hostent *server = ::gethostbyname(host); - if(server == NULL) - { - return -1; //Could not resolve address - } - std::memcpy((char*)&remoteHost.sin_addr.s_addr, (char*)server->h_addr_list[0], server->h_length); - - remoteHost.sin_family = AF_INET; - remoteHost.sin_port = htons(port); - - size_t writtenLen = 0; - struct timeval t_val; //t_val will be decremented on each call to select() - t_val.tv_sec = timeout / 1000; - t_val.tv_usec = (timeout - (t_val.tv_sec * 1000)) * 1000; - while(writtenLen < length) - { - //Wait for socket to be writeable - //Creating FS set - fd_set socksSet; - FD_ZERO(&socksSet); - FD_SET(m_sock, &socksSet); - - int ret = ::select(FD_SETSIZE, NULL, &socksSet, NULL, &t_val); - if(ret <= 0 || !FD_ISSET(m_sock, &socksSet)) - { - return writtenLen; //Timeout -- FIXME should we return -1 or writtenLength ? +int UDPSocket::sendTo(char* data, int length, char* host, int port, int timeout) { + if (_sock_fd < 0) + return -1; + + struct sockaddr_in remoteHost; + + //Populate m_remoteHost + std::memset(&remoteHost, 0, sizeof(struct sockaddr_in)); + + //Resolve DNS address or populate hard-coded IP address + struct hostent *server = ::gethostbyname(host); + if (server == NULL) { + return -1; //Could not resolve address } - - ret = ::sendto(m_sock, data + writtenLen, length - writtenLen, 0, (const struct sockaddr *)&remoteHost, sizeof(remoteHost)); - if( ret > 0) - { - writtenLen += ret; - continue; + std::memcpy((char*) &remoteHost.sin_addr.s_addr, + (char*) server->h_addr_list[0], server->h_length); + + remoteHost.sin_family = AF_INET; + remoteHost.sin_port = htons(port); + + size_t writtenLen = 0; + set_timeout(timeout); + while (writtenLen < length) { + //Wait for socket to be writeable + //Creating FS set + if (wait_writable() != 0) + return writtenLen; //Timeout -- FIXME should we return -1 or writtenLength ? + + int ret = lwip_sendto(_sock_fd, data + writtenLen, length - writtenLen, 0, + (const struct sockaddr *) &remoteHost, sizeof(remoteHost)); + if (ret > 0) { + writtenLen += ret; + } else if (ret == 0) { + return writtenLen; //Connection was closed by server -- FIXME how do we signal that the connection was closed ? + } else { + return -1; //Connnection error + } } - else if( ret == 0 ) - { - return writtenLen; //Connection was closed by server -- FIXME how do we signal that the connection was closed ? - } - else - { - return -1; //Connnection error - } - } - - return writtenLen; + + return writtenLen; } // -1 if unsuccessful, else number of bytes received -int UDPSocket::receiveFrom(char* data, int length, char** host, int* port, int timeout) -{ - if( m_sock < 0 ) - { - return -1; - } - - struct sockaddr_in remoteHost; - - //Populate m_remoteHost - std::memset(&remoteHost, 0, sizeof(struct sockaddr_in)); - - socklen_t remoteHostLen = sizeof(remoteHost); - - size_t readLen = 0; - struct timeval t_val; //t_val will be decremented on each call to select() - t_val.tv_sec = timeout / 1000; - t_val.tv_usec = (timeout - (t_val.tv_sec * 1000)) * 1000; - - //No loop here as we don't want to mix packets from different sources - do - { - //Wait for socket to be readable - //Creating FS set - fd_set socksSet; - FD_ZERO(&socksSet); - FD_SET(m_sock, &socksSet); - int ret = ::select(FD_SETSIZE, &socksSet, NULL, NULL, &t_val); - if(ret <= 0 || !FD_ISSET(m_sock, &socksSet)) - { - break; //Timeout -- FIXME should we return -1 or writtenLength ? - } +int UDPSocket::receiveFrom(char* data, int length, char** host, int* port, int timeout) { + if (_sock_fd < 0) + return -1; + + set_timeout(timeout); + if (wait_readable() != 0) + return -1; + + struct sockaddr_in remoteHost; + std::memset(&remoteHost, 0, sizeof(struct sockaddr_in)); - ret = ::recvfrom(m_sock, data + readLen, length - readLen, 0, (struct sockaddr*)&remoteHost, &remoteHostLen); - if( ret > 0) - { - readLen += ret; - } - else if( ret == 0 ) - { - //Connection was closed by server -- FIXME how do we signal that the connection was closed ? - //Continue and populate address - } - else - { - return -1; //Connection error - } - } while(0); - - static char hostBuf[16]; - inet_ntoa_r(remoteHost.sin_addr, hostBuf, sizeof(hostBuf)); - - *host = hostBuf; - *port = ntohs(remoteHost.sin_port); - - return readLen; + socklen_t remoteHostLen = sizeof(remoteHost); + int n = lwip_recvfrom(_sock_fd, data, length, 0, (struct sockaddr*) &remoteHost, &remoteHostLen); + if (n < 0) + return -1; + + static char hostBuf[16]; + inet_ntoa_r(remoteHost.sin_addr, hostBuf, sizeof(hostBuf)); + + *host = hostBuf; + *port = ntohs(remoteHost.sin_port); + + return n; } -int UDPSocket::close() -{ - if( m_sock < 0 ) - { - return -1; - } - - ::close(m_sock); - m_sock = -1; - - return 0; +UDPSocket::~UDPSocket() { + close(); //Don't want to leak } - -int UDPSocket::init() -{ - if( m_sock != -1 ) - { - return -1; - } - m_sock = ::socket(AF_INET, SOCK_DGRAM, 0); //UDP socket - if (m_sock < 0) - { - return -1; //Could not create socket (Out of memory / available descriptors) - } - return 0; -}
--- a/UDPSocket.h Mon Jul 23 11:52:50 2012 +0000 +++ b/UDPSocket.h Wed Jul 25 14:59:37 2012 +0000 @@ -19,23 +19,21 @@ #ifndef UDPSOCKET_H #define UDPSOCKET_H -#include "Socket/socket.h" +#include "Socket/Socket.h" #include <cstdint> /** This is a C++ abstraction for UDP networking sockets. */ -class UDPSocket -{ +class UDPSocket : public Socket { public: - /** Instantiate a UDP Socket. */ UDPSocket(); ~UDPSocket(); - - /** Bind a socket to a specific port. + + /** Bind a UDP Server Socket to a specific port For a listening socket, bind the socket to the following port. \param port The port to listen for incoming connections on, using 0 here will select a random port. \return 0 on success, -1 on failure. @@ -61,16 +59,6 @@ \return the number of received bytes on success (>=0) or -1 on failure */ int receiveFrom(char* data, int length, char** host, int* port, int timeout = 0); - - /** Close the socket. - */ - int close(); - - private: - int init(); - - int m_sock; - }; #endif
--- a/socket.h Mon Jul 23 11:52:50 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,126 +0,0 @@ -#ifndef SOCKET_H_ -#define SOCKET_H_ - -#include "lwip/sockets.h" - -#define OK 0 //No error - -#define NET_FULL 1 //>All available resources are already used -#define NET_EMPTY 2 //>No resource -#define NET_NOTFOUND 3 //>Element cannot be found -#define NET_INVALID 4 //>Invalid -#define NET_CONTEXT 5 //>Called in a wrong context (eg during an interrupt) -#define NET_TIMEOUT 6 //>Timeout -#define NET_UNKNOWN 7 //>Unknown error -#define NET_OVERFLOW 8 //>Overflow -#define NET_PROCESSING 9 //>Command is processing -#define NET_INTERRUPTED 10 //>Current operation has been interrupted -#define NET_MOREINFO 11 //>More info on this error can be retrieved elsewhere (eg in a parameter passed as ptr) -#define NET_ABORT 12 //>Current operation must be aborted -#define NET_DIFF 13 //>Items that should match are different -#define NET_AUTH 14 //>Authentication failed -#define NET_PROTOCOL 15 //>Protocol error -#define NET_OOM 16 //>Out of memory -#define NET_CONN 17 //>Connection error -#define NET_CLOSED 18 //>Connection was closed by remote end -#define NET_TOOSMALL 19 //>Buffer is too small - -inline int accept(int s, struct sockaddr *addr, socklen_t *addrlen) { - return lwip_accept(s, addr, addrlen); -} - -inline int bind(int s, const struct sockaddr *name, socklen_t namelen) { - return lwip_bind(s, name, namelen); -} - -inline int shutdown(int s, int how) { - return lwip_shutdown(s, how); -} - -inline int getsockname (int s, struct sockaddr *name, socklen_t *namelen) { - return lwip_getsockname(s, name, namelen); -} - -inline int getpeername (int s, struct sockaddr *name, socklen_t *namelen) { - return lwip_getpeername(s, name, namelen); -} - -inline int getsockopt (int s, int level, int optname, void *optval, socklen_t *optlen) { - return lwip_getsockopt(s, level, optname, optval, optlen); -} - -inline int setsockopt (int s, int level, int optname, const void *optval, socklen_t optlen) { - return lwip_setsockopt(s, level, optname, optval, optlen); -} - -inline int connect(int s, const struct sockaddr *name, socklen_t namelen) { - return lwip_connect(s, name, namelen); -} - -inline int listen(int s, int backlog) { - return lwip_listen(s, backlog); -} - -inline int recv(int s, void *mem, size_t len, int flags) { - return lwip_recv(s, mem, len, flags); -} - -inline int recvfrom(int s, void *mem, size_t len, int flags, - struct sockaddr *from, socklen_t *fromlen) { - return lwip_recvfrom(s, mem, len, flags, from, fromlen); -} - -inline int send(int s, const void *dataptr, size_t size, int flags) { - return lwip_send(s, dataptr, size, flags); -} - -inline int sendto(int s, const void *dataptr, size_t size, int flags, - const struct sockaddr *to, socklen_t tolen) { - return lwip_sendto(s, dataptr, size, flags, to, tolen); -} - -inline int socket(int domain, int type, int protocol) { - return lwip_socket(domain, type, protocol); -} - -inline int select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset, - struct timeval *timeout) { - return lwip_select(maxfdp1, readset, writeset, exceptset, timeout); -} - -inline int ioctlsocket(int s, long cmd, void *argp) { - return lwip_ioctl(s, cmd, argp); -} - -inline int read(int s, void *mem, size_t len) { - return lwip_read(s, mem, len); -} - -inline int write(int s, const void *dataptr, size_t size) { - return lwip_write(s, dataptr, size); -} - -inline int close(int s) { - return lwip_close(s); -} - -#include "lwip/netdb.h" - -//DNS -inline struct hostent *gethostbyname(const char *name) { - return lwip_gethostbyname(name); -} - -inline int gethostbyname_r(const char *name, struct hostent *ret, char *buf, size_t buflen, struct hostent **result, int *h_errnop) { - return lwip_gethostbyname_r(name, ret, buf, buflen, result, h_errnop); -} - -inline void freeaddrinfo(struct addrinfo *ai) { - return lwip_freeaddrinfo(ai); -} - -inline int getaddrinfo(const char *nodename, const char *servname, const struct addrinfo *hints, struct addrinfo **res) { - return lwip_getaddrinfo(nodename, servname, hints, res); -} - -#endif /* SOCKET_H_ */