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