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>
47 Log::getInstance()->log("TCP", Log::DEBUG, "Have closed");
51 void TCP::disableTimeout()
56 void TCP::getMAC(char* dest)
60 strcpy(ifr.ifr_name, "eth0");
61 ioctl(sock, SIOCGIFHWADDR, &ifr);
62 memcpy(dest, ifr.ifr_hwaddr.sa_data, 6);
64 //TODO: Get MAC Address for windows
65 PIP_ADAPTER_INFO daptinfo=NULL;
67 GetAdaptersInfo(daptinfo,&size);
68 daptinfo=(PIP_ADAPTER_INFO)new char[size+1];
69 memcpy(dest,"ABCDEF", 6);//Dummy Address
70 sockaddr_in sock_address;
71 int sockname_len=sizeof(sock_address);
72 getsockname(sock,(sockaddr*)&sock_address,&sockname_len);
73 ULONG sockip=sock_address.sin_addr.s_addr;
74 if (GetAdaptersInfo(daptinfo,&size)==ERROR_SUCCESS)
76 PIP_ADAPTER_INFO daptinfo_it=daptinfo;
77 while (daptinfo_it!=NULL)
79 ULONG ipaddress=inet_addr(daptinfo_it->IpAddressList.IpAddress.String);
80 if (ipaddress==sockip)
82 memcpy(dest,daptinfo_it->Address, 6);
85 daptinfo_it=daptinfo_it->Next;
86 if (daptinfo_it==daptinfo) break;
98 int TCP::connectTo(char* host, unsigned short port)
100 #ifdef VOMP_PLATFORM_RASPBERRY
108 sock = socket(PF_INET, SOCK_STREAM, 0);
109 if (sock == -1) return 0;
110 struct sockaddr_in dest_addr;
111 dest_addr.sin_family = AF_INET;
112 dest_addr.sin_port = htons(port);
115 if (!inet_aton(host, &dest_addr.sin_addr))
117 dest_addr.sin_addr.s_addr = inet_addr(host);
118 if (dest_addr.sin_addr.s_addr == INADDR_NONE)
125 memset(&(dest_addr.sin_zero), '\0', 8);
130 snprintf(portstring, 10, "%u", port);
132 struct addrinfo hints;
133 struct addrinfo* res;
134 memset(&hints, 0, sizeof(hints));
135 hints.ai_family = AF_UNSPEC;
136 hints.ai_socktype = SOCK_STREAM;
137 if (getaddrinfo(host, portstring, &hints, &res))
139 //printf("[%s] [%s]\n", host, portstring);
143 sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
144 if (sock == -1) return 0;
152 int oldflags = fcntl (sock, F_GETFL, 0);
153 oldflags |= O_NONBLOCK;
154 fcntl(sock, F_SETFL, oldflags);
156 unsigned long flag=1;
157 ioctlsocket(sock,FIONBIO,&flag);
161 // setReceiveWindow(2048);
163 // ok, how to open a connection in non blocking mode (and therefore have a self set timeout!!)
166 int success = connect(sock, (struct sockaddr *)&dest_addr, sizeof(dest_addr));
168 int success = connect(sock, res->ai_addr, res->ai_addrlen);
173 if (success == 0) // if by some miracle the connection succeeded in no time flat, just return!
179 // first check errno for EINPROGRESS, otherwise it's a fail
180 // this doesn't work?
182 if (errno != EINPROGRESS)
184 int wsalasterr = WSAGetLastError();
185 if ((wsalasterr != WSAEWOULDBLOCK) && (wsalasterr != WSAEINPROGRESS))
193 // now do a timeout wait on writability on the socket
196 struct timeval timeout;
197 FD_ZERO(&connectSet);
198 FD_SET(sock, &connectSet);
201 success = select(sock + 1, NULL, &connectSet, NULL, &timeout);
209 // so the socket became available for writing. Contrary to expectation, this doesn't actually
210 // mean it connected...
212 int soError; // SO_ERROR optval is int
213 socklen_t soErrorSize = sizeof(soError);
216 int gso = getsockopt(sock, SOL_SOCKET, SO_ERROR, reinterpret_cast<char*>(&soError), &soErrorSize);
218 int gso = getsockopt(sock, SOL_SOCKET, SO_ERROR, reinterpret_cast<void*>(&soError), &soErrorSize);
221 if ((gso == 0) && (soError == 0))
234 The full documentation:
237 The socket is non-blocking and the connection canĀ
238 not be completed immediately. It is possible to
239 select(2) or poll(2) for completion by selecting
240 the socket for writing. After select indicates
241 writability, use getsockopt(2) to read the SO_ERROR
242 option at level SOL_SOCKET to determine whether
243 connect completed successfully (SO_ERROR is zero)
244 or unsuccessfully (SO_ERROR is one of the usual
245 error codes listed here, explaining the reason for
250 void TCP::setReceiveWindow(size_t rxBufferSize)
252 // Set receive window
253 // According to docs, optval in setsockopt is a pointer to int unless otherwise noted
254 int rxSize = rxBufferSize;
256 int r = setsockopt(sock, SOL_SOCKET, SO_RCVBUF, reinterpret_cast<char*>(&rxSize), sizeof(size_t));
258 int r = setsockopt(sock, SOL_SOCKET, SO_RCVBUF, reinterpret_cast<void*>(&rxSize), sizeof(size_t));
260 Log::getInstance()->log("TCP", Log::DEBUG, "Set receive window to %i, success(=0): %i", rxBufferSize, r);
263 void TCP::assignSocket(int tsocket)
268 int TCP::isConnected()
273 int TCP::sendData(void* bufR, size_t count)
275 size_t bytes_sent = 0;
278 unsigned char* buf = static_cast<unsigned char*>(bufR);
282 while (bytes_sent < count)
287 this_write = write(sock, buf, count - bytes_sent);
288 // Log::getInstance()->log("TCP", Log::DEBUG, "TCP has written %i bytes", this_write);
289 } while ( (this_write < 0) && (errno == EINTR) );
291 this_write = send(sock,(char*) buf, count- bytes_sent,0);
292 } while ( (this_write == SOCKET_ERROR) && (WSAGetLastError() == WSAEINTR) );
299 bytes_sent += this_write;
308 int TCP::readData(void* targetBuffer, int totalBytes)
310 UCHAR* buffer = reinterpret_cast<UCHAR*>(targetBuffer);
316 struct timeval timeout;
317 struct timeval* passToSelect;
319 if (timeoutEnabled) passToSelect = &timeout;
320 else passToSelect = NULL;
325 FD_SET(sock, &readSet);
328 // Log::getInstance()->log("TCP", Log::DEBUG, "Going to select");
329 success = select(sock + 1, &readSet, NULL, NULL, passToSelect);
330 // Log::getInstance()->log("TCP", Log::DEBUG, "Back from select with success = %i", success);
333 return 0; // error, or timeout
336 thisRead = read(sock, &buffer[bytesRead], totalBytes - bytesRead);
338 thisRead = recv(sock, (char*)&buffer[bytesRead], totalBytes - bytesRead, 0);
340 //Log::getInstance()->log("TCP", Log::DEBUG, "Read %i", thisRead);
343 // if read returns 0 then connection is closed
344 // in non-blocking mode if read is called with no data available, it returns -1
345 // and sets errno to EGAGAIN. but we use select so it wouldn't do that anyway.
346 Log::getInstance()->log("TCP", Log::ERR, "Detected connection closed");
351 bytesRead += thisRead;
352 if (bytesRead == totalBytes)
358 if (++readTries == 1000)
360 Log::getInstance()->log("TCP", Log::ERR, "Too many reads");
367 void TCP::dump(unsigned char* data, ULONG size)
369 printf("Size = %lu\n", size);
376 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",
377 data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
378 data[c+8], data[c+9], data[c+10], data[c+11], data[c+12], data[c+13], data[c+14], data[c+15],
379 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]),
380 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]));
388 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",
389 data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
390 data[c+8], data[c+9], data[c+10], data[c+11], data[c+12], data[c+13], data[c+14],
391 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]),
392 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]));
396 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",
397 data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
398 data[c+8], data[c+9], data[c+10], data[c+11], data[c+12], data[c+13],
399 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]),
400 dcc(data[c+8]), dcc(data[c+9]), dcc(data[c+10]), dcc(data[c+11]), dcc(data[c+12]), dcc(data[c+13]));
404 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",
405 data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
406 data[c+8], data[c+9], data[c+10], data[c+11], data[c+12],
407 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]),
408 dcc(data[c+8]), dcc(data[c+9]), dcc(data[c+10]), dcc(data[c+11]), dcc(data[c+12]));
412 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",
413 data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
414 data[c+8], data[c+9], data[c+10], data[c+11],
415 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]),
416 dcc(data[c+8]), dcc(data[c+9]), dcc(data[c+10]), dcc(data[c+11]));
420 printf(" %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %c%c%c%c%c%c%c%c%c%c%c\n",
421 data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
422 data[c+8], data[c+9], data[c+10],
423 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]),
424 dcc(data[c+8]), dcc(data[c+9]), dcc(data[c+10]));
428 printf(" %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %c%c%c%c%c%c%c%c%c%c\n",
429 data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
430 data[c+8], data[c+9],
431 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]),
432 dcc(data[c+8]), dcc(data[c+9]));
436 printf(" %02X %02X %02X %02X %02X %02X %02X %02X %02X %c%c%c%c%c%c%c%c%c\n",
437 data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
439 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]),
444 printf(" %02X %02X %02X %02X %02X %02X %02X %02X %c%c%c%c%c%c%c%c\n",
445 data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
446 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 printf(" %02X %02X %02X %02X %02X %02X %02X %c%c%c%c%c%c%c\n",
451 data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6],
452 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]));
456 printf(" %02X %02X %02X %02X %02X %02X %c%c%c%c%c%c\n",
457 data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5],
458 dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]), dcc(data[c+5]));
462 printf(" %02X %02X %02X %02X %02X %c%c%c%c%c\n",
463 data[c], data[c+1], data[c+2], data[c+3], data[c+4],
464 dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]));
468 printf(" %02X %02X %02X %02X %c%c%c%c\n",
469 data[c], data[c+1], data[c+2], data[c+3],
470 dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]));
474 printf(" %02X %02X %02X %c%c%c\n",
475 data[c], data[c+1], data[c+2],
476 dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]));
480 printf(" %02X %02X %c%c\n",
482 dcc(data[c]), dcc(data[c+1]));
496 UCHAR TCP::dcc(UCHAR c)
498 if (isspace(c)) return ' ';
499 if (isprint(c)) return c;