yo

Fork of Socket by mbed official

Committer:
emilmont
Date:
Mon Jul 23 11:52:50 2012 +0000
Revision:
2:b227d242f3c7
Parent:
1:8080965f5d76
tidyup

Who changed what in which revision?

UserRevisionLine numberNew contents of line
donatien 0:1f77255a22f5 1 /* Copyright (C) 2012 mbed.org, MIT License
donatien 0:1f77255a22f5 2 *
donatien 0:1f77255a22f5 3 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
donatien 0:1f77255a22f5 4 * and associated documentation files (the "Software"), to deal in the Software without restriction,
donatien 0:1f77255a22f5 5 * including without limitation the rights to use, copy, modify, merge, publish, distribute,
donatien 0:1f77255a22f5 6 * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
donatien 0:1f77255a22f5 7 * furnished to do so, subject to the following conditions:
donatien 0:1f77255a22f5 8 *
donatien 0:1f77255a22f5 9 * The above copyright notice and this permission notice shall be included in all copies or
donatien 0:1f77255a22f5 10 * substantial portions of the Software.
donatien 0:1f77255a22f5 11 *
donatien 0:1f77255a22f5 12 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
donatien 0:1f77255a22f5 13 * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
donatien 0:1f77255a22f5 14 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
donatien 0:1f77255a22f5 15 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
donatien 0:1f77255a22f5 16 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
donatien 0:1f77255a22f5 17 */
donatien 0:1f77255a22f5 18
donatien 0:1f77255a22f5 19 #include "TCPSocket.h"
donatien 0:1f77255a22f5 20
donatien 0:1f77255a22f5 21 #include <cstring>
donatien 0:1f77255a22f5 22
donatien 0:1f77255a22f5 23 using std::memset;
donatien 0:1f77255a22f5 24
donatien 0:1f77255a22f5 25 TCPSocket::TCPSocket() : m_sock(-1)
donatien 0:1f77255a22f5 26 {
donatien 0:1f77255a22f5 27 }
donatien 0:1f77255a22f5 28
donatien 0:1f77255a22f5 29 TCPSocket::~TCPSocket()
donatien 0:1f77255a22f5 30 {
donatien 0:1f77255a22f5 31 close(); //Don't want to leak
donatien 0:1f77255a22f5 32 }
donatien 0:1f77255a22f5 33
donatien 0:1f77255a22f5 34 int TCPSocket::connect(char* host, int port, int timeout)
donatien 0:1f77255a22f5 35 {
donatien 0:1f77255a22f5 36 int ret = init();
donatien 0:1f77255a22f5 37 if( ret < 0 )
donatien 0:1f77255a22f5 38 {
donatien 0:1f77255a22f5 39 return -1;
donatien 0:1f77255a22f5 40 }
donatien 0:1f77255a22f5 41
donatien 0:1f77255a22f5 42 //Populate m_remoteHost
donatien 0:1f77255a22f5 43 std::memset(&m_remoteHost, 0, sizeof(struct sockaddr_in));
donatien 0:1f77255a22f5 44
donatien 0:1f77255a22f5 45 //Resolve DNS address or populate hard-coded IP address
emilmont 2:b227d242f3c7 46 struct hostent *server = gethostbyname(host);
donatien 0:1f77255a22f5 47 if(server == NULL)
donatien 0:1f77255a22f5 48 {
donatien 0:1f77255a22f5 49 return -1; //Could not resolve address
donatien 0:1f77255a22f5 50 }
donatien 0:1f77255a22f5 51 std::memcpy((char*)&m_remoteHost.sin_addr.s_addr, (char*)server->h_addr_list[0], server->h_length);
donatien 0:1f77255a22f5 52
donatien 0:1f77255a22f5 53 m_remoteHost.sin_family = AF_INET;
donatien 0:1f77255a22f5 54 m_remoteHost.sin_port = htons(port);
donatien 0:1f77255a22f5 55
donatien 0:1f77255a22f5 56 ret = ::connect(m_sock, (const struct sockaddr *)&m_remoteHost, sizeof(m_remoteHost));
donatien 0:1f77255a22f5 57 if (ret < 0)
donatien 0:1f77255a22f5 58 {
donatien 0:1f77255a22f5 59 close();
donatien 0:1f77255a22f5 60 return -1;
donatien 0:1f77255a22f5 61 }
donatien 0:1f77255a22f5 62
donatien 0:1f77255a22f5 63 return 0;
donatien 0:1f77255a22f5 64 }
donatien 0:1f77255a22f5 65
donatien 0:1f77255a22f5 66 int TCPSocket::bind(int port)
donatien 0:1f77255a22f5 67 {
donatien 0:1f77255a22f5 68 int ret = init();
donatien 0:1f77255a22f5 69 if( ret < 0 )
donatien 0:1f77255a22f5 70 {
donatien 0:1f77255a22f5 71 return -1;
donatien 0:1f77255a22f5 72 }
donatien 0:1f77255a22f5 73
donatien 0:1f77255a22f5 74 struct sockaddr_in localHost;
donatien 0:1f77255a22f5 75 std::memset(&localHost, 0, sizeof(localHost));
donatien 0:1f77255a22f5 76
donatien 0:1f77255a22f5 77 localHost.sin_family = AF_INET;
donatien 0:1f77255a22f5 78 localHost.sin_port = htons(port);
donatien 0:1f77255a22f5 79 localHost.sin_addr.s_addr = INADDR_ANY;
donatien 0:1f77255a22f5 80
donatien 0:1f77255a22f5 81 ret = ::bind(m_sock, (const struct sockaddr *)&localHost, sizeof(localHost));
donatien 0:1f77255a22f5 82 if (ret < 0)
donatien 0:1f77255a22f5 83 {
donatien 0:1f77255a22f5 84 close();
donatien 0:1f77255a22f5 85 return -1;
donatien 0:1f77255a22f5 86 }
donatien 0:1f77255a22f5 87
donatien 0:1f77255a22f5 88 return 0;
donatien 0:1f77255a22f5 89 }
donatien 0:1f77255a22f5 90
donatien 0:1f77255a22f5 91 int TCPSocket::listen(int max)
donatien 0:1f77255a22f5 92 {
donatien 0:1f77255a22f5 93 if( m_sock < 0 )
donatien 0:1f77255a22f5 94 {
donatien 0:1f77255a22f5 95 return -1;
donatien 0:1f77255a22f5 96 }
donatien 0:1f77255a22f5 97
donatien 0:1f77255a22f5 98 int ret = ::listen(m_sock, max);
donatien 0:1f77255a22f5 99 if (ret < 0)
donatien 0:1f77255a22f5 100 {
donatien 0:1f77255a22f5 101 close();
donatien 0:1f77255a22f5 102 return -1;
donatien 0:1f77255a22f5 103 }
donatien 0:1f77255a22f5 104
donatien 0:1f77255a22f5 105 return 0;
donatien 0:1f77255a22f5 106 }
donatien 0:1f77255a22f5 107
donatien 0:1f77255a22f5 108 int TCPSocket::accept(TCPSocket& socket, char** host, int* port, int timeout)
donatien 0:1f77255a22f5 109 {
donatien 0:1f77255a22f5 110 if( m_sock < 0 )
donatien 0:1f77255a22f5 111 {
donatien 0:1f77255a22f5 112 return -1;
donatien 0:1f77255a22f5 113 }
donatien 0:1f77255a22f5 114
donatien 0:1f77255a22f5 115 //Populate m_remoteHost
donatien 0:1f77255a22f5 116 std::memset(&socket.m_remoteHost, 0, sizeof(struct sockaddr_in));
donatien 0:1f77255a22f5 117
donatien 0:1f77255a22f5 118 struct timeval t_val; //t_val will be decremented on each call to select()
donatien 0:1f77255a22f5 119 t_val.tv_sec = timeout / 1000;
donatien 0:1f77255a22f5 120 t_val.tv_usec = (timeout - (t_val.tv_sec * 1000)) * 1000;
donatien 0:1f77255a22f5 121 //Wait for socket to get some connection request (i.e. to be "readable")
donatien 0:1f77255a22f5 122 //Creating FS set
donatien 0:1f77255a22f5 123 fd_set socksSet;
donatien 0:1f77255a22f5 124 FD_ZERO(&socksSet);
donatien 0:1f77255a22f5 125 FD_SET(m_sock, &socksSet);
donatien 0:1f77255a22f5 126 int ret = ::select(FD_SETSIZE, &socksSet, NULL, NULL, &t_val);
donatien 0:1f77255a22f5 127 if(ret <= 0 || !FD_ISSET(m_sock, &socksSet))
donatien 0:1f77255a22f5 128 {
donatien 0:1f77255a22f5 129 return -1; //Timeout
donatien 0:1f77255a22f5 130 }
donatien 0:1f77255a22f5 131
donatien 0:1f77255a22f5 132 socklen_t newSockRemoteHostLen = sizeof(socket.m_remoteHost);
donatien 0:1f77255a22f5 133
donatien 0:1f77255a22f5 134 ret = ::accept(m_sock, (struct sockaddr*)&socket.m_remoteHost, &newSockRemoteHostLen);
donatien 0:1f77255a22f5 135 if( ret < 0 )
donatien 0:1f77255a22f5 136 {
donatien 0:1f77255a22f5 137 return -1; //Accept failed
donatien 0:1f77255a22f5 138 }
donatien 0:1f77255a22f5 139
donatien 0:1f77255a22f5 140 socket.m_sock = ret; //ret is the new socket's fd
donatien 0:1f77255a22f5 141 socket.m_closedByRemoteHost = false;
donatien 0:1f77255a22f5 142
donatien 0:1f77255a22f5 143 static char hostBuf[16];
donatien 0:1f77255a22f5 144 inet_ntoa_r(socket.m_remoteHost.sin_addr, hostBuf, sizeof(hostBuf));
donatien 0:1f77255a22f5 145
donatien 0:1f77255a22f5 146 *host = hostBuf;
donatien 0:1f77255a22f5 147 *port = ntohs(socket.m_remoteHost.sin_port);
donatien 0:1f77255a22f5 148
donatien 0:1f77255a22f5 149 return 0;
donatien 0:1f77255a22f5 150 }
donatien 0:1f77255a22f5 151
donatien 0:1f77255a22f5 152 // -1 if unsuccessful, else number of bytes written
donatien 1:8080965f5d76 153 int TCPSocket::send(char* data, int length, int timeout)
donatien 0:1f77255a22f5 154 {
donatien 0:1f77255a22f5 155 if( m_sock < 0 )
donatien 0:1f77255a22f5 156 {
donatien 0:1f77255a22f5 157 return -1;
donatien 0:1f77255a22f5 158 }
donatien 0:1f77255a22f5 159
donatien 0:1f77255a22f5 160 if( m_closedByRemoteHost )
donatien 0:1f77255a22f5 161 {
donatien 0:1f77255a22f5 162 return 0;
donatien 0:1f77255a22f5 163 }
donatien 0:1f77255a22f5 164
donatien 0:1f77255a22f5 165 size_t writtenLen = 0;
donatien 0:1f77255a22f5 166 struct timeval t_val; //t_val will be decremented on each call to select()
donatien 0:1f77255a22f5 167 t_val.tv_sec = timeout / 1000;
donatien 0:1f77255a22f5 168 t_val.tv_usec = (timeout - (t_val.tv_sec * 1000)) * 1000;
donatien 0:1f77255a22f5 169 while(writtenLen < length)
donatien 0:1f77255a22f5 170 {
donatien 0:1f77255a22f5 171 //Wait for socket to be writeable
donatien 0:1f77255a22f5 172 //Creating FS set
donatien 0:1f77255a22f5 173 fd_set socksSet;
donatien 0:1f77255a22f5 174 FD_ZERO(&socksSet);
donatien 0:1f77255a22f5 175 FD_SET(m_sock, &socksSet);
donatien 0:1f77255a22f5 176
donatien 0:1f77255a22f5 177 int ret = ::select(FD_SETSIZE, NULL, &socksSet, NULL, &t_val);
donatien 0:1f77255a22f5 178 if(ret <= 0 || !FD_ISSET(m_sock, &socksSet))
donatien 0:1f77255a22f5 179 {
donatien 0:1f77255a22f5 180 return writtenLen; //Timeout -- FIXME should we return -1 or writtenLength ?
donatien 0:1f77255a22f5 181 }
donatien 0:1f77255a22f5 182
donatien 0:1f77255a22f5 183 ret = ::send(m_sock, data + writtenLen, length - writtenLen, 0);
donatien 0:1f77255a22f5 184 if( ret > 0)
donatien 0:1f77255a22f5 185 {
donatien 0:1f77255a22f5 186 writtenLen += ret;
donatien 0:1f77255a22f5 187 continue;
donatien 0:1f77255a22f5 188 }
donatien 0:1f77255a22f5 189 else if( ret == 0 )
donatien 0:1f77255a22f5 190 {
donatien 0:1f77255a22f5 191 m_closedByRemoteHost = true;
donatien 0:1f77255a22f5 192 return writtenLen; //Connection was closed by remote host -- FIXME how do we signal that the connection was closed ?
donatien 0:1f77255a22f5 193 }
donatien 0:1f77255a22f5 194 else
donatien 0:1f77255a22f5 195 {
donatien 0:1f77255a22f5 196 return -1; //Connnection error
donatien 0:1f77255a22f5 197 }
donatien 0:1f77255a22f5 198 }
donatien 0:1f77255a22f5 199
donatien 0:1f77255a22f5 200 return writtenLen;
donatien 0:1f77255a22f5 201 }
donatien 0:1f77255a22f5 202
donatien 0:1f77255a22f5 203 // -1 if unsuccessful, else number of bytes received
donatien 1:8080965f5d76 204 int TCPSocket::receive(char* data, int length, int timeout)
donatien 0:1f77255a22f5 205 {
donatien 0:1f77255a22f5 206 if( m_sock < 0 )
donatien 0:1f77255a22f5 207 {
donatien 0:1f77255a22f5 208 return -1;
donatien 0:1f77255a22f5 209 }
donatien 0:1f77255a22f5 210
donatien 0:1f77255a22f5 211 if( m_closedByRemoteHost )
donatien 0:1f77255a22f5 212 {
donatien 0:1f77255a22f5 213 return 0;
donatien 0:1f77255a22f5 214 }
donatien 0:1f77255a22f5 215
donatien 0:1f77255a22f5 216 size_t readLen = 0;
donatien 0:1f77255a22f5 217 struct timeval t_val; //t_val will be decremented on each call to select()
donatien 0:1f77255a22f5 218 t_val.tv_sec = timeout / 1000;
donatien 0:1f77255a22f5 219 t_val.tv_usec = (timeout - (t_val.tv_sec * 1000)) * 1000;
donatien 0:1f77255a22f5 220 while(readLen < length)
donatien 0:1f77255a22f5 221 {
donatien 0:1f77255a22f5 222 //Wait for socket to be readable
donatien 0:1f77255a22f5 223 //Creating FS set
donatien 0:1f77255a22f5 224 fd_set socksSet;
donatien 0:1f77255a22f5 225 FD_ZERO(&socksSet);
donatien 0:1f77255a22f5 226 FD_SET(m_sock, &socksSet);
donatien 0:1f77255a22f5 227 int ret = ::select(FD_SETSIZE, &socksSet, NULL, NULL, &t_val);
donatien 0:1f77255a22f5 228 if(ret <= 0 || !FD_ISSET(m_sock, &socksSet))
donatien 0:1f77255a22f5 229 {
donatien 0:1f77255a22f5 230 return readLen; //Timeout -- FIXME should we return -1 or writtenLength ?
donatien 0:1f77255a22f5 231 }
donatien 0:1f77255a22f5 232
donatien 0:1f77255a22f5 233 ret = ::recv(m_sock, data + readLen, length - readLen, 0);
donatien 0:1f77255a22f5 234 if( ret > 0)
donatien 0:1f77255a22f5 235 {
donatien 0:1f77255a22f5 236 readLen += ret;
donatien 0:1f77255a22f5 237 continue;
donatien 0:1f77255a22f5 238 }
donatien 0:1f77255a22f5 239 else if( ret == 0 )
donatien 0:1f77255a22f5 240 {
donatien 0:1f77255a22f5 241 m_closedByRemoteHost = true;
donatien 0:1f77255a22f5 242 return readLen; //Connection was closed by remote host -- FIXME how do we signal that the connection was closed ?
donatien 0:1f77255a22f5 243 }
donatien 0:1f77255a22f5 244 else
donatien 0:1f77255a22f5 245 {
donatien 0:1f77255a22f5 246 return -1; //Connnection error
donatien 0:1f77255a22f5 247 }
donatien 0:1f77255a22f5 248 }
donatien 0:1f77255a22f5 249 return readLen;
donatien 0:1f77255a22f5 250 }
donatien 0:1f77255a22f5 251
donatien 0:1f77255a22f5 252 int TCPSocket::close()
donatien 0:1f77255a22f5 253 {
donatien 0:1f77255a22f5 254 if( m_sock < 0 )
donatien 0:1f77255a22f5 255 {
donatien 0:1f77255a22f5 256 return -1;
donatien 0:1f77255a22f5 257 }
donatien 0:1f77255a22f5 258
donatien 0:1f77255a22f5 259 ::close(m_sock);
donatien 0:1f77255a22f5 260 m_sock = -1;
donatien 0:1f77255a22f5 261
donatien 0:1f77255a22f5 262 return 0;
donatien 0:1f77255a22f5 263 }
donatien 0:1f77255a22f5 264
donatien 0:1f77255a22f5 265 int TCPSocket::init()
donatien 0:1f77255a22f5 266 {
donatien 0:1f77255a22f5 267 if( m_sock != -1 )
donatien 0:1f77255a22f5 268 {
donatien 0:1f77255a22f5 269 return -1;
donatien 0:1f77255a22f5 270 }
donatien 0:1f77255a22f5 271 m_sock = ::socket(AF_INET, SOCK_STREAM, 0); //TCP socket
donatien 0:1f77255a22f5 272 if (m_sock < 0)
donatien 0:1f77255a22f5 273 {
donatien 0:1f77255a22f5 274 return -1; //Could not create socket (Out of memory / available descriptors)
donatien 0:1f77255a22f5 275 }
donatien 0:1f77255a22f5 276 m_closedByRemoteHost = false;
donatien 0:1f77255a22f5 277 return 0;
donatien 0:1f77255a22f5 278 }