]> git.vomp.tv Git - vompclient.git/blob - tcp.cc
Change WSelectList option data to void*. About 65 CWFs
[vompclient.git] / tcp.cc
1 /*
2     Copyright 2004-2019 Chris Tallon
3     Copyright 2003-2004 University Of Bradford
4
5     This file is part of VOMP.
6
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.
11
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.
16
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.
20 */
21
22 #ifdef WIN32
23 #include <WinSock2.h>
24 #include <Iphlpapi.h>
25 #else
26 #include <sys/types.h>
27 #include <sys/socket.h>
28 #include <netdb.h>
29 #endif
30
31 #include "log.h"
32
33 #include "tcp.h"
34
35 #ifndef WIN32
36 #define MUTEX_LOCK(mutex) pthread_mutex_lock(mutex)
37 #define MUTEX_UNLOCK(mutex) pthread_mutex_unlock(mutex)
38 #else
39 #define MUTEX_LOCK(mutex) WaitForSingleObject(*(mutex), INFINITE )
40 #define MUTEX_UNLOCK(mutex) ReleaseMutex(*(mutex))
41 #endif
42
43 TCP::TCP()
44 {
45   sock = 0;
46   connected = 0;
47   timeoutEnabled = 1;
48
49 #ifndef WIN32
50   pthread_mutex_init(&mutex, NULL);
51 #else
52   mutex=CreateMutex(NULL,FALSE,NULL);
53 #endif
54 }
55
56 TCP::~TCP()
57 {
58   if (connected)
59   {
60     CLOSESOCKET(sock);
61     Log::getInstance()->log("TCP", Log::DEBUG, "Have closed");
62   }
63
64 #ifdef WIN32
65   CloseHandle(mutex);
66 #endif  
67 }
68
69 void TCP::disableTimeout()
70 {
71   timeoutEnabled = 0;
72 }
73
74 void TCP::getMAC(char* dest)
75 {
76 #ifndef WIN32
77   struct ifreq ifr;
78   strcpy(ifr.ifr_name, "eth0");
79   ioctl(sock, SIOCGIFHWADDR, &ifr);
80   memcpy(dest, ifr.ifr_hwaddr.sa_data, 6);
81 #else
82   //TODO: Get MAC Address for windows
83   PIP_ADAPTER_INFO daptinfo=NULL;
84   DWORD size=0;
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)
93   {
94     PIP_ADAPTER_INFO daptinfo_it=daptinfo;
95     while (daptinfo_it!=NULL)
96     {
97       ULONG ipaddress=inet_addr(daptinfo_it->IpAddressList.IpAddress.String);
98       if (ipaddress==sockip)
99       { //Is it our MAC?
100         memcpy(dest,daptinfo_it->Address, 6);
101         break;
102       }
103       daptinfo_it=daptinfo_it->Next;
104       if (daptinfo_it==daptinfo) break;
105     }
106   }
107   else
108   {
109     // Marten?
110   }
111
112   delete [] daptinfo;
113 #endif
114 }
115
116 int TCP::connectTo(char* host, unsigned short port)
117 {
118 #ifdef VOMP_PLATFORM_RASPBERRY
119 #define IPV 6
120 #else
121 #define IPV 4
122 #endif
123
124 #if IPV == 4
125
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);
131
132 #ifndef WIN32
133   if (!inet_aton(host, &dest_addr.sin_addr))
134 #else
135   dest_addr.sin_addr.s_addr = inet_addr(host);
136   if (dest_addr.sin_addr.s_addr == INADDR_NONE)
137 #endif
138   {
139     CLOSESOCKET(sock);
140     return 0;
141   }
142
143   memset(&(dest_addr.sin_zero), '\0', 8);
144
145 #elif IPV == 6
146
147   char portstring[10];
148   snprintf(portstring, 10, "%u", port);
149
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))
156   {
157     //printf("[%s] [%s]\n", host, portstring);
158     return 0;
159   }
160
161   sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
162   if (sock == -1) return 0;
163
164 #endif
165
166
167
168   // set non blocking
169 #ifndef WIN32
170   int oldflags = fcntl (sock, F_GETFL, 0);
171   oldflags |= O_NONBLOCK;
172   fcntl(sock, F_SETFL, oldflags);
173 #else
174   unsigned long flag=1;
175   ioctlsocket(sock,FIONBIO,&flag);
176
177 #endif
178
179 //  setReceiveWindow(2048);
180
181   // ok, how to open a connection in non blocking mode (and therefore have a self set timeout!!)
182
183 #if IPV == 4
184   int success = connect(sock, (struct sockaddr *)&dest_addr, sizeof(dest_addr));
185 #elif IPV == 6
186   int success = connect(sock, res->ai_addr, res->ai_addrlen);
187   freeaddrinfo(res);
188 #endif
189
190
191   if (success == 0)  // if by some miracle the connection succeeded in no time flat, just return!
192   {
193     connected = 1;
194     return 1;
195   }
196
197   // first check errno for EINPROGRESS, otherwise it's a fail
198   // this doesn't work?
199 #ifndef WIN32
200   if (errno != EINPROGRESS)
201 #else
202   int wsalasterr = WSAGetLastError();
203   if ((wsalasterr != WSAEWOULDBLOCK) && (wsalasterr != WSAEINPROGRESS))
204 #endif
205   {
206     CLOSESOCKET(sock);
207
208     return 0;
209   }
210
211   // now do a timeout wait on writability on the socket
212
213   fd_set connectSet;
214   struct timeval timeout;
215   FD_ZERO(&connectSet);
216   FD_SET(sock, &connectSet);
217   timeout.tv_sec = 10;
218   timeout.tv_usec = 0;
219   success = select(sock + 1, NULL, &connectSet, NULL, &timeout);
220   if (success < 1)
221   {
222     // timeout or error
223     CLOSESOCKET(sock);
224     return 0;
225   }
226
227   // so the socket became available for writing. Contrary to expectation, this doesn't actually
228   // mean it connected...
229
230   int soError; // SO_ERROR optval is int
231   socklen_t soErrorSize = sizeof(soError);
232   int gso = getsockopt(sock, SOL_SOCKET, SO_ERROR, reinterpret_cast<void*>(&soError), &soErrorSize);
233
234   if ((gso == 0) && (soError == 0))
235   {
236     // success!
237     connected = 1;
238     return 1;
239   }
240   else
241   {
242     CLOSESOCKET(sock);
243     return 0;
244   }
245
246 /*
247 The full documentation:
248
249        EINPROGRESS
250               The  socket is non-blocking and the connection canĀ­
251               not be completed immediately.  It  is  possible  to
252               select(2)  or  poll(2)  for completion by selecting
253               the socket  for  writing.  After  select  indicates
254               writability, use getsockopt(2) to read the SO_ERROR
255               option at level  SOL_SOCKET  to  determine  whether
256               connect  completed  successfully (SO_ERROR is zero)
257               or unsuccessfully (SO_ERROR is  one  of  the  usual
258               error  codes listed here, explaining the reason for
259               the failure).
260 */
261 }
262
263 void TCP::setReceiveWindow(size_t rxBufferSize)
264 {
265   // Set receive window
266   // According to docs, optval in setsockopt is a pointer to int unless otherwise noted
267   int rxSize = rxBufferSize;
268   int r = setsockopt(sock, SOL_SOCKET, SO_RCVBUF, reinterpret_cast<void*>(&rxSize), sizeof(size_t));
269   Log::getInstance()->log("TCP", Log::DEBUG, "Set receive window to %i, success(=0): %i", rxBufferSize, r);
270 }
271
272 void TCP::assignSocket(int tsocket)
273 {
274   sock = tsocket;
275 }
276
277 int TCP::isConnected()
278 {
279   return connected;
280 }
281
282 int TCP::sendData(void* bufR, size_t count)
283 {
284   size_t bytes_sent = 0;
285   int this_write;
286
287   unsigned char* buf = static_cast<unsigned char*>(bufR);
288
289   MUTEX_LOCK(&mutex);
290
291   while (bytes_sent < count)
292   {
293     do
294     {
295 #ifndef WIN32
296       this_write = write(sock, buf, count - bytes_sent);
297 //      Log::getInstance()->log("TCP", Log::DEBUG, "TCP has written %i bytes", this_write);
298     } while ( (this_write < 0) && (errno == EINTR) );
299 #else
300       this_write = send(sock,(char*) buf, count- bytes_sent,0);
301     } while ( (this_write == SOCKET_ERROR) && (WSAGetLastError() == WSAEINTR) );
302 #endif
303     if (this_write <= 0)
304     {
305       MUTEX_UNLOCK(&mutex);
306       return(this_write);
307     }
308     bytes_sent += this_write;
309     buf += this_write;
310   }
311   
312   MUTEX_UNLOCK(&mutex);
313   
314   return(count);
315 }
316
317 int TCP::readData(UCHAR* buffer, int totalBytes)
318 {
319
320   int bytesRead = 0;
321   int thisRead;
322   int readTries = 0;
323   int success;
324   fd_set readSet;
325   struct timeval timeout;
326   struct timeval* passToSelect;
327
328   if (timeoutEnabled) passToSelect = &timeout;
329   else passToSelect = NULL;
330
331   while(1)
332   {
333     FD_ZERO(&readSet);
334     FD_SET(sock, &readSet);
335     timeout.tv_sec = 2;
336     timeout.tv_usec = 0;
337   //  Log::getInstance()->log("TCP", Log::DEBUG, "Going to select");
338     success = select(sock + 1, &readSet, NULL, NULL, passToSelect);
339    // Log::getInstance()->log("TCP", Log::DEBUG, "Back from select with success = %i", success);
340     if (success < 1)
341     {
342       return 0;  // error, or timeout
343     }
344 #ifndef WIN32
345     thisRead = read(sock, &buffer[bytesRead], totalBytes - bytesRead);
346 #else
347     thisRead = recv(sock, (char*)&buffer[bytesRead], totalBytes - bytesRead, 0);
348 #endif
349     //Log::getInstance()->log("TCP", Log::DEBUG, "Read %i", thisRead);
350     if (!thisRead)
351     {
352       // if read returns 0 then connection is closed
353       // in non-blocking mode if read is called with no data available, it returns -1
354       // and sets errno to EGAGAIN. but we use select so it wouldn't do that anyway.
355       Log::getInstance()->log("TCP", Log::ERR, "Detected connection closed");
356       CLOSESOCKET(sock);
357       connected = 0;
358       return 0;
359     }
360     bytesRead += thisRead;
361     if (bytesRead == totalBytes)
362     {
363       return 1;
364     }
365     else
366     {
367       if (++readTries == 1000)
368       {
369         Log::getInstance()->log("TCP", Log::ERR, "Too many reads");
370         return 0;
371       }
372     }
373   }
374 }
375
376 void TCP::dump(unsigned char* data, ULONG size)
377 {
378   printf("Size = %lu\n", size);
379
380   ULONG c = 0;
381   while(c < size)
382   {
383     if ((size - c) > 15)
384     {
385       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",
386         data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
387         data[c+8], data[c+9], data[c+10], data[c+11], data[c+12], data[c+13], data[c+14], data[c+15],
388         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]),
389         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]));
390       c += 16;
391     }
392     else
393     {
394       switch (size - c)
395       {
396         case 15:
397           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",
398             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
399             data[c+8], data[c+9], data[c+10], data[c+11], data[c+12], data[c+13], data[c+14],
400             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]),
401             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]));
402           c += 15;
403           break;
404         case 14:
405           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",
406             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
407             data[c+8], data[c+9], data[c+10], data[c+11], data[c+12], data[c+13],
408             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]),
409             dcc(data[c+8]), dcc(data[c+9]), dcc(data[c+10]), dcc(data[c+11]), dcc(data[c+12]), dcc(data[c+13]));
410           c += 14;
411           break;
412         case 13:
413           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",
414             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
415             data[c+8], data[c+9], data[c+10], data[c+11], data[c+12],
416             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]),
417             dcc(data[c+8]), dcc(data[c+9]), dcc(data[c+10]), dcc(data[c+11]), dcc(data[c+12]));
418           c += 13;
419           break;
420         case 12:
421           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",
422             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
423             data[c+8], data[c+9], data[c+10], data[c+11],
424             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]),
425             dcc(data[c+8]), dcc(data[c+9]), dcc(data[c+10]), dcc(data[c+11]));
426           c += 12;
427           break;
428         case 11:
429           printf(" %02X %02X %02X %02X  %02X %02X %02X %02X  %02X %02X %02X                  %c%c%c%c%c%c%c%c%c%c%c\n",
430             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
431             data[c+8], data[c+9], data[c+10],
432             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]),
433             dcc(data[c+8]), dcc(data[c+9]), dcc(data[c+10]));
434           c += 11;
435           break;
436         case 10:
437           printf(" %02X %02X %02X %02X  %02X %02X %02X %02X  %02X %02X                     %c%c%c%c%c%c%c%c%c%c\n",
438             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
439             data[c+8], data[c+9],
440             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]),
441             dcc(data[c+8]), dcc(data[c+9]));
442           c += 10;
443           break;
444         case 9:
445           printf(" %02X %02X %02X %02X  %02X %02X %02X %02X  %02X                        %c%c%c%c%c%c%c%c%c\n",
446             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
447             data[c+8],
448             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]),
449             dcc(data[c+8]));
450           c += 9;
451           break;
452         case 8:
453           printf(" %02X %02X %02X %02X  %02X %02X %02X %02X                            %c%c%c%c%c%c%c%c\n",
454             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
455             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]));
456           c += 8;
457           break;
458         case 7:
459           printf(" %02X %02X %02X %02X  %02X %02X %02X                               %c%c%c%c%c%c%c\n",
460             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6],
461             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]));
462           c += 7;
463           break;
464         case 6:
465           printf(" %02X %02X %02X %02X  %02X %02X                                  %c%c%c%c%c%c\n",
466             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5],
467             dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]), dcc(data[c+5]));
468           c += 6;
469           break;
470         case 5:
471           printf(" %02X %02X %02X %02X  %02X                                     %c%c%c%c%c\n",
472             data[c], data[c+1], data[c+2], data[c+3], data[c+4],
473             dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]));
474           c += 5;
475           break;
476         case 4:
477           printf(" %02X %02X %02X %02X                                         %c%c%c%c\n",
478             data[c], data[c+1], data[c+2], data[c+3],
479             dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]));
480           c += 4;
481           break;
482         case 3:
483           printf(" %02X %02X %02X                                            %c%c%c\n",
484             data[c], data[c+1], data[c+2],
485             dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]));
486           c += 3;
487           break;
488         case 2:
489           printf(" %02X %02X                                               %c%c\n",
490             data[c], data[c+1],
491             dcc(data[c]), dcc(data[c+1]));
492           c += 2;
493           break;
494         case 1:
495           printf(" %02X                                                  %c\n",
496             data[c],
497             dcc(data[c]));
498           c += 1;
499           break;
500       }
501     }
502   }
503 }
504
505 UCHAR TCP::dcc(UCHAR c)
506 {
507   if (isspace(c)) return ' ';
508   if (isprint(c)) return c;
509   return '.';
510 }