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.
Diff: UDPSocket.cpp
- Revision:
- 0:1f77255a22f5
- Child:
- 1:8080965f5d76
diff -r 000000000000 -r 1f77255a22f5 UDPSocket.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/UDPSocket.cpp Tue Jun 26 13:16:26 2012 +0000 @@ -0,0 +1,205 @@ +/* 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 "UDPSocket.h" +#include "bsd_socket.h" + +#include <cstring> + +using std::memset; + +UDPSocket::UDPSocket() : m_sock(-1) +{ +} + +UDPSocket::~UDPSocket() +{ + close(); //Don't want to leak +} + +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; +} + +// -1 if unsuccessful, else number of bytes written +int UDPSocket::sendTo(uint8_t* 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 ? + } + + ret = ::sendto(m_sock, data + writtenLen, length - writtenLen, 0, (const struct sockaddr *)&remoteHost, sizeof(remoteHost)); + if( ret > 0) + { + writtenLen += ret; + continue; + } + 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; +} + +// -1 if unsuccessful, else number of bytes received +int UDPSocket::receiveFrom(uint8_t* 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 ? + } + + 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; +} + +int UDPSocket::close() +{ + if( m_sock < 0 ) + { + return -1; + } + + ::close(m_sock); + m_sock = -1; + + return 0; +} + +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; +}