2 Copyright 2004-2019 Chris Tallon
3 Copyright 2003-2004 University Of Bradford
5 This file is part of VOMP.
7 VOMP is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 VOMP is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with VOMP; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26 #include <sys/types.h>
27 #include <sys/socket.h>
36 #define MUTEX_LOCK(mutex) pthread_mutex_lock(mutex)
37 #define MUTEX_UNLOCK(mutex) pthread_mutex_unlock(mutex)
39 #define MUTEX_LOCK(mutex) WaitForSingleObject(*(mutex), INFINITE )
40 #define MUTEX_UNLOCK(mutex) ReleaseMutex(*(mutex))
50 pthread_mutex_init(&mutex, NULL);
52 mutex=CreateMutex(NULL,FALSE,NULL);
61 Log::getInstance()->log("TCP", Log::DEBUG, "Have closed");
69 void TCP::disableTimeout()
74 void TCP::getMAC(char* dest)
78 strcpy(ifr.ifr_name, "eth0");
79 ioctl(sock, SIOCGIFHWADDR, &ifr);
80 memcpy(dest, ifr.ifr_hwaddr.sa_data, 6);
82 //TODO: Get MAC Address for windows
83 PIP_ADAPTER_INFO daptinfo=NULL;
85 GetAdaptersInfo(daptinfo,&size);
86 daptinfo=(PIP_ADAPTER_INFO)new char[size+1];
87 memcpy(dest,"ABCDEF", 6);//Dummy Address
88 sockaddr_in sock_address;
89 int sockname_len=sizeof(sock_address);
90 getsockname(sock,(sockaddr*)&sock_address,&sockname_len);
91 ULONG sockip=sock_address.sin_addr.s_addr;
92 if (GetAdaptersInfo(daptinfo,&size)==ERROR_SUCCESS)
94 PIP_ADAPTER_INFO daptinfo_it=daptinfo;
95 while (daptinfo_it!=NULL)
97 ULONG ipaddress=inet_addr(daptinfo_it->IpAddressList.IpAddress.String);
98 if (ipaddress==sockip)
100 memcpy(dest,daptinfo_it->Address, 6);
103 daptinfo_it=daptinfo_it->Next;
104 if (daptinfo_it==daptinfo) break;
116 int TCP::connectTo(char* host, unsigned short port)
118 #ifdef VOMP_PLATFORM_RASPBERRY
126 sock = socket(PF_INET, SOCK_STREAM, 0);
127 if (sock == -1) return 0;
128 struct sockaddr_in dest_addr;
129 dest_addr.sin_family = AF_INET;
130 dest_addr.sin_port = htons(port);
133 if (!inet_aton(host, &dest_addr.sin_addr))
135 dest_addr.sin_addr.s_addr = inet_addr(host);
136 if (dest_addr.sin_addr.s_addr == INADDR_NONE)
143 memset(&(dest_addr.sin_zero), '\0', 8);
148 snprintf(portstring, 10, "%u", port);
150 struct addrinfo hints;
151 struct addrinfo* res;
152 memset(&hints, 0, sizeof(hints));
153 hints.ai_family = AF_UNSPEC;
154 hints.ai_socktype = SOCK_STREAM;
155 if (getaddrinfo(host, portstring, &hints, &res))
157 //printf("[%s] [%s]\n", host, portstring);
161 sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
162 if (sock == -1) return 0;
170 int oldflags = fcntl (sock, F_GETFL, 0);
171 oldflags |= O_NONBLOCK;
172 fcntl(sock, F_SETFL, oldflags);
174 unsigned long flag=1;
175 ioctlsocket(sock,FIONBIO,&flag);
179 // setReceiveWindow(2048);
181 // ok, how to open a connection in non blocking mode (and therefore have a self set timeout!!)
184 int success = connect(sock, (struct sockaddr *)&dest_addr, sizeof(dest_addr));
186 int success = connect(sock, res->ai_addr, res->ai_addrlen);
191 if (success == 0) // if by some miracle the connection succeeded in no time flat, just return!
197 // first check errno for EINPROGRESS, otherwise it's a fail
198 // this doesn't work?
200 if (errno != EINPROGRESS)
202 int wsalasterr = WSAGetLastError();
203 if ((wsalasterr != WSAEWOULDBLOCK) && (wsalasterr != WSAEINPROGRESS))
211 // now do a timeout wait on writability on the socket
214 struct timeval timeout;
215 FD_ZERO(&connectSet);
216 FD_SET(sock, &connectSet);
219 success = select(sock + 1, NULL, &connectSet, NULL, &timeout);
227 // so the socket became available for writing. Contrary to expectation, this doesn't actually
228 // mean it connected...
230 int soError; // SO_ERROR optval is int
231 socklen_t soErrorSize = sizeof(soError);
234 int gso = getsockopt(sock, SOL_SOCKET, SO_ERROR, reinterpret_cast<char*>(&soError), &soErrorSize);
236 int gso = getsockopt(sock, SOL_SOCKET, SO_ERROR, reinterpret_cast<void*>(&soError), &soErrorSize);
239 if ((gso == 0) && (soError == 0))
252 The full documentation:
255 The socket is non-blocking and the connection canĀ
256 not be completed immediately. It is possible to
257 select(2) or poll(2) for completion by selecting
258 the socket for writing. After select indicates
259 writability, use getsockopt(2) to read the SO_ERROR
260 option at level SOL_SOCKET to determine whether
261 connect completed successfully (SO_ERROR is zero)
262 or unsuccessfully (SO_ERROR is one of the usual
263 error codes listed here, explaining the reason for
268 void TCP::setReceiveWindow(size_t rxBufferSize)
270 // Set receive window
271 // According to docs, optval in setsockopt is a pointer to int unless otherwise noted
272 int rxSize = rxBufferSize;
274 int r = setsockopt(sock, SOL_SOCKET, SO_RCVBUF, reinterpret_cast<char*>(&rxSize), sizeof(size_t));
276 int r = setsockopt(sock, SOL_SOCKET, SO_RCVBUF, reinterpret_cast<void*>(&rxSize), sizeof(size_t));
278 Log::getInstance()->log("TCP", Log::DEBUG, "Set receive window to %i, success(=0): %i", rxBufferSize, r);
281 void TCP::assignSocket(int tsocket)
286 int TCP::isConnected()
291 int TCP::sendData(void* bufR, size_t count)
293 size_t bytes_sent = 0;
296 unsigned char* buf = static_cast<unsigned char*>(bufR);
300 while (bytes_sent < count)
305 this_write = write(sock, buf, count - bytes_sent);
306 // Log::getInstance()->log("TCP", Log::DEBUG, "TCP has written %i bytes", this_write);
307 } while ( (this_write < 0) && (errno == EINTR) );
309 this_write = send(sock,(char*) buf, count- bytes_sent,0);
310 } while ( (this_write == SOCKET_ERROR) && (WSAGetLastError() == WSAEINTR) );
314 MUTEX_UNLOCK(&mutex);
317 bytes_sent += this_write;
321 MUTEX_UNLOCK(&mutex);
326 int TCP::readData(void* targetBuffer, int totalBytes)
328 UCHAR* buffer = reinterpret_cast<UCHAR*>(targetBuffer);
334 struct timeval timeout;
335 struct timeval* passToSelect;
337 if (timeoutEnabled) passToSelect = &timeout;
338 else passToSelect = NULL;
343 FD_SET(sock, &readSet);
346 // Log::getInstance()->log("TCP", Log::DEBUG, "Going to select");
347 success = select(sock + 1, &readSet, NULL, NULL, passToSelect);
348 // Log::getInstance()->log("TCP", Log::DEBUG, "Back from select with success = %i", success);
351 return 0; // error, or timeout
354 thisRead = read(sock, &buffer[bytesRead], totalBytes - bytesRead);
356 thisRead = recv(sock, (char*)&buffer[bytesRead], totalBytes - bytesRead, 0);
358 //Log::getInstance()->log("TCP", Log::DEBUG, "Read %i", thisRead);
361 // if read returns 0 then connection is closed
362 // in non-blocking mode if read is called with no data available, it returns -1
363 // and sets errno to EGAGAIN. but we use select so it wouldn't do that anyway.
364 Log::getInstance()->log("TCP", Log::ERR, "Detected connection closed");
369 bytesRead += thisRead;
370 if (bytesRead == totalBytes)
376 if (++readTries == 1000)
378 Log::getInstance()->log("TCP", Log::ERR, "Too many reads");
385 void TCP::dump(unsigned char* data, ULONG size)
387 printf("Size = %lu\n", size);
394 printf(" %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c\n",
395 data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
396 data[c+8], data[c+9], data[c+10], data[c+11], data[c+12], data[c+13], data[c+14], data[c+15],
397 dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]), dcc(data[c+5]), dcc(data[c+6]), dcc(data[c+7]),
398 dcc(data[c+8]), dcc(data[c+9]), dcc(data[c+10]), dcc(data[c+11]), dcc(data[c+12]), dcc(data[c+13]), dcc(data[c+14]), dcc(data[c+15]));
406 printf(" %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %c%c%c%c%c%c%c%c%c%c%c%c%c%c%c\n",
407 data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
408 data[c+8], data[c+9], data[c+10], data[c+11], data[c+12], data[c+13], data[c+14],
409 dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]), dcc(data[c+5]), dcc(data[c+6]), dcc(data[c+7]),
410 dcc(data[c+8]), dcc(data[c+9]), dcc(data[c+10]), dcc(data[c+11]), dcc(data[c+12]), dcc(data[c+13]), dcc(data[c+14]));
414 printf(" %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %c%c%c%c%c%c%c%c%c%c%c%c%c%c\n",
415 data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
416 data[c+8], data[c+9], data[c+10], data[c+11], data[c+12], data[c+13],
417 dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]), dcc(data[c+5]), dcc(data[c+6]), dcc(data[c+7]),
418 dcc(data[c+8]), dcc(data[c+9]), dcc(data[c+10]), dcc(data[c+11]), dcc(data[c+12]), dcc(data[c+13]));
422 printf(" %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %c%c%c%c%c%c%c%c%c%c%c%c%c\n",
423 data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
424 data[c+8], data[c+9], data[c+10], data[c+11], data[c+12],
425 dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]), dcc(data[c+5]), dcc(data[c+6]), dcc(data[c+7]),
426 dcc(data[c+8]), dcc(data[c+9]), dcc(data[c+10]), dcc(data[c+11]), dcc(data[c+12]));
430 printf(" %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %c%c%c%c%c%c%c%c%c%c%c%c\n",
431 data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
432 data[c+8], data[c+9], data[c+10], data[c+11],
433 dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]), dcc(data[c+5]), dcc(data[c+6]), dcc(data[c+7]),
434 dcc(data[c+8]), dcc(data[c+9]), dcc(data[c+10]), dcc(data[c+11]));
438 printf(" %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %c%c%c%c%c%c%c%c%c%c%c\n",
439 data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
440 data[c+8], data[c+9], data[c+10],
441 dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]), dcc(data[c+5]), dcc(data[c+6]), dcc(data[c+7]),
442 dcc(data[c+8]), dcc(data[c+9]), dcc(data[c+10]));
446 printf(" %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %c%c%c%c%c%c%c%c%c%c\n",
447 data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
448 data[c+8], data[c+9],
449 dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]), dcc(data[c+5]), dcc(data[c+6]), dcc(data[c+7]),
450 dcc(data[c+8]), dcc(data[c+9]));
454 printf(" %02X %02X %02X %02X %02X %02X %02X %02X %02X %c%c%c%c%c%c%c%c%c\n",
455 data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
457 dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]), dcc(data[c+5]), dcc(data[c+6]), dcc(data[c+7]),
462 printf(" %02X %02X %02X %02X %02X %02X %02X %02X %c%c%c%c%c%c%c%c\n",
463 data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
464 dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]), dcc(data[c+5]), dcc(data[c+6]), dcc(data[c+7]));
468 printf(" %02X %02X %02X %02X %02X %02X %02X %c%c%c%c%c%c%c\n",
469 data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6],
470 dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]), dcc(data[c+5]), dcc(data[c+6]));
474 printf(" %02X %02X %02X %02X %02X %02X %c%c%c%c%c%c\n",
475 data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5],
476 dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]), dcc(data[c+5]));
480 printf(" %02X %02X %02X %02X %02X %c%c%c%c%c\n",
481 data[c], data[c+1], data[c+2], data[c+3], data[c+4],
482 dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]));
486 printf(" %02X %02X %02X %02X %c%c%c%c\n",
487 data[c], data[c+1], data[c+2], data[c+3],
488 dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]));
492 printf(" %02X %02X %02X %c%c%c\n",
493 data[c], data[c+1], data[c+2],
494 dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]));
498 printf(" %02X %02X %c%c\n",
500 dcc(data[c]), dcc(data[c+1]));
514 UCHAR TCP::dcc(UCHAR c)
516 if (isspace(c)) return ' ';
517 if (isprint(c)) return c;