]> git.vomp.tv Git - vompclient.git/blob - tcp.cc
Add Winsock2.h to tcp.cc for Windows
[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 #define IPV 6
119
120
121 #if IPV == 4
122
123   sock = socket(PF_INET, SOCK_STREAM, 0);
124   if (sock == -1) return 0;
125   struct sockaddr_in dest_addr;
126   dest_addr.sin_family = AF_INET;
127   dest_addr.sin_port = htons(port);
128
129 #ifndef WIN32
130   if (!inet_aton(host, &dest_addr.sin_addr))
131 #else
132   dest_addr.sin_addr.s_addr = inet_addr(host);
133   if (dest_addr.sin_addr.s_addr == INADDR_NONE)
134 #endif
135   {
136     CLOSESOCKET(sock);
137     return 0;
138   }
139
140   memset(&(dest_addr.sin_zero), '\0', 8);
141
142 #elif IPV == 6
143
144   char portstring[10];
145   snprintf(portstring, 10, "%u", port);
146
147   struct addrinfo hints;
148   struct addrinfo* res;
149   memset(&hints, 0, sizeof(hints));
150   hints.ai_family = AF_UNSPEC;
151   hints.ai_socktype = SOCK_STREAM;
152   if (getaddrinfo(host, portstring, &hints, &res))
153   {
154     //printf("[%s] [%s]\n", host, portstring);
155     return 0;
156   }
157
158   sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
159   if (sock == -1) return 0;
160
161 #endif
162
163
164
165   // set non blocking
166 #ifndef WIN32
167   int oldflags = fcntl (sock, F_GETFL, 0);
168   oldflags |= O_NONBLOCK;
169   fcntl(sock, F_SETFL, oldflags);
170 #else
171   unsigned long flag=1;
172   ioctlsocket(sock,FIONBIO,&flag);
173
174 #endif
175
176 //  setReceiveWindow(2048);
177
178   // ok, how to open a connection in non blocking mode (and therefore have a self set timeout!!)
179
180 #if IPV == 4
181   int success = connect(sock, (struct sockaddr *)&dest_addr, sizeof(dest_addr));
182 #elif IPV == 6
183   int success = connect(sock, res->ai_addr, res->ai_addrlen);
184   freeaddrinfo(res);
185 #endif
186
187
188   if (success == 0)  // if by some miracle the connection succeeded in no time flat, just return!
189   {
190     connected = 1;
191     return 1;
192   }
193
194   // first check errno for EINPROGRESS, otherwise it's a fail
195   // this doesn't work?
196 #ifndef WIN32
197   if (errno != EINPROGRESS)
198 #else
199   int wsalasterr = WSAGetLastError();
200   if ((wsalasterr != WSAEWOULDBLOCK) && (wsalasterr != WSAEINPROGRESS))
201 #endif
202   {
203     CLOSESOCKET(sock);
204
205     return 0;
206   }
207
208   // now do a timeout wait on writability on the socket
209
210   fd_set connectSet;
211   struct timeval timeout;
212   FD_ZERO(&connectSet);
213   FD_SET(sock, &connectSet);
214   timeout.tv_sec = 10;
215   timeout.tv_usec = 0;
216   success = select(sock + 1, NULL, &connectSet, NULL, &timeout);
217   if (success < 1)
218   {
219     // timeout or error
220     CLOSESOCKET(sock);
221     return 0;
222   }
223
224   // so the socket became available for writing. Contrary to expectation, this doesn't actually
225   // mean it connected...
226
227   int soError;
228   socklen_t soErrorSize = sizeof(soError);
229   int gso = getsockopt(sock, SOL_SOCKET, SO_ERROR,(char*) &soError, &soErrorSize);
230
231   if ((gso == 0) && (soError == 0))
232   {
233     // success!
234     connected = 1;
235     return 1;
236   }
237   else
238   {
239     CLOSESOCKET(sock);
240     return 0;
241   }
242
243 /*
244 The full documentation:
245
246        EINPROGRESS
247               The  socket is non-blocking and the connection canĀ­
248               not be completed immediately.  It  is  possible  to
249               select(2)  or  poll(2)  for completion by selecting
250               the socket  for  writing.  After  select  indicates
251               writability, use getsockopt(2) to read the SO_ERROR
252               option at level  SOL_SOCKET  to  determine  whether
253               connect  completed  successfully (SO_ERROR is zero)
254               or unsuccessfully (SO_ERROR is  one  of  the  usual
255               error  codes listed here, explaining the reason for
256               the failure).
257 */
258 }
259
260 void TCP::setReceiveWindow(size_t rxBufferSize)
261 {
262   // Set receive window
263   int r = setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char*)&rxBufferSize, sizeof(size_t));
264   Log::getInstance()->log("TCP", Log::DEBUG, "Set receive window to %i, success(=0): %i", rxBufferSize, r);
265 }
266
267 void TCP::assignSocket(int tsocket)
268 {
269   sock = tsocket;
270 }
271
272 int TCP::isConnected()
273 {
274   return connected;
275 }
276
277 int TCP::sendData(void* bufR, size_t count)
278 {
279   size_t bytes_sent = 0;
280   int this_write;
281
282   unsigned char* buf = (unsigned char*)bufR;
283
284   MUTEX_LOCK(&mutex);
285
286   while (bytes_sent < count)
287   {
288     do
289     {
290 #ifndef WIN32
291       this_write = write(sock, buf, count - bytes_sent);
292 //      Log::getInstance()->log("TCP", Log::DEBUG, "TCP has written %i bytes", this_write);
293     } while ( (this_write < 0) && (errno == EINTR) );
294 #else
295       this_write = send(sock,(char*) buf, count- bytes_sent,0);
296     } while ( (this_write == SOCKET_ERROR) && (WSAGetLastError() == WSAEINTR) );
297 #endif
298     if (this_write <= 0)
299     {
300       MUTEX_UNLOCK(&mutex);
301       return(this_write);
302     }
303     bytes_sent += this_write;
304     buf += this_write;
305   }
306   
307   MUTEX_UNLOCK(&mutex);
308   
309   return(count);
310 }
311
312 int TCP::readData(UCHAR* buffer, int totalBytes)
313 {
314
315   int bytesRead = 0;
316   int thisRead;
317   int readTries = 0;
318   int success;
319   fd_set readSet;
320   struct timeval timeout;
321   struct timeval* passToSelect;
322
323   if (timeoutEnabled) passToSelect = &timeout;
324   else passToSelect = NULL;
325
326   while(1)
327   {
328     FD_ZERO(&readSet);
329     FD_SET(sock, &readSet);
330     timeout.tv_sec = 2;
331     timeout.tv_usec = 0;
332   //  Log::getInstance()->log("TCP", Log::DEBUG, "Going to select");
333     success = select(sock + 1, &readSet, NULL, NULL, passToSelect);
334    // Log::getInstance()->log("TCP", Log::DEBUG, "Back from select with success = %i", success);
335     if (success < 1)
336     {
337       return 0;  // error, or timeout
338     }
339 #ifndef WIN32
340     thisRead = read(sock, &buffer[bytesRead], totalBytes - bytesRead);
341 #else
342     thisRead = recv(sock, (char*)&buffer[bytesRead], totalBytes - bytesRead, 0);
343 #endif
344     //Log::getInstance()->log("TCP", Log::DEBUG, "Read %i", thisRead);
345     if (!thisRead)
346     {
347       // if read returns 0 then connection is closed
348       // in non-blocking mode if read is called with no data available, it returns -1
349       // and sets errno to EGAGAIN. but we use select so it wouldn't do that anyway.
350       Log::getInstance()->log("TCP", Log::ERR, "Detected connection closed");
351       CLOSESOCKET(sock);
352       connected = 0;
353       return 0;
354     }
355     bytesRead += thisRead;
356     if (bytesRead == totalBytes)
357     {
358       return 1;
359     }
360     else
361     {
362       if (++readTries == 1000)
363       {
364         Log::getInstance()->log("TCP", Log::ERR, "Too many reads");
365         return 0;
366       }
367     }
368   }
369 }
370
371 void TCP::dump(unsigned char* data, ULONG size)
372 {
373   printf("Size = %lu\n", size);
374
375   ULONG c = 0;
376   while(c < size)
377   {
378     if ((size - c) > 15)
379     {
380       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",
381         data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
382         data[c+8], data[c+9], data[c+10], data[c+11], data[c+12], data[c+13], data[c+14], data[c+15],
383         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]),
384         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]));
385       c += 16;
386     }
387     else
388     {
389       switch (size - c)
390       {
391         case 15:
392           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",
393             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
394             data[c+8], data[c+9], data[c+10], data[c+11], data[c+12], data[c+13], data[c+14],
395             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]),
396             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]));
397           c += 15;
398           break;
399         case 14:
400           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",
401             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
402             data[c+8], data[c+9], data[c+10], data[c+11], data[c+12], data[c+13],
403             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]),
404             dcc(data[c+8]), dcc(data[c+9]), dcc(data[c+10]), dcc(data[c+11]), dcc(data[c+12]), dcc(data[c+13]));
405           c += 14;
406           break;
407         case 13:
408           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",
409             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
410             data[c+8], data[c+9], data[c+10], data[c+11], data[c+12],
411             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]),
412             dcc(data[c+8]), dcc(data[c+9]), dcc(data[c+10]), dcc(data[c+11]), dcc(data[c+12]));
413           c += 13;
414           break;
415         case 12:
416           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",
417             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
418             data[c+8], data[c+9], data[c+10], data[c+11],
419             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]),
420             dcc(data[c+8]), dcc(data[c+9]), dcc(data[c+10]), dcc(data[c+11]));
421           c += 12;
422           break;
423         case 11:
424           printf(" %02X %02X %02X %02X  %02X %02X %02X %02X  %02X %02X %02X                  %c%c%c%c%c%c%c%c%c%c%c\n",
425             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
426             data[c+8], data[c+9], data[c+10],
427             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]),
428             dcc(data[c+8]), dcc(data[c+9]), dcc(data[c+10]));
429           c += 11;
430           break;
431         case 10:
432           printf(" %02X %02X %02X %02X  %02X %02X %02X %02X  %02X %02X                     %c%c%c%c%c%c%c%c%c%c\n",
433             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
434             data[c+8], data[c+9],
435             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]),
436             dcc(data[c+8]), dcc(data[c+9]));
437           c += 10;
438           break;
439         case 9:
440           printf(" %02X %02X %02X %02X  %02X %02X %02X %02X  %02X                        %c%c%c%c%c%c%c%c%c\n",
441             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
442             data[c+8],
443             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             dcc(data[c+8]));
445           c += 9;
446           break;
447         case 8:
448           printf(" %02X %02X %02X %02X  %02X %02X %02X %02X                            %c%c%c%c%c%c%c%c\n",
449             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
450             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]));
451           c += 8;
452           break;
453         case 7:
454           printf(" %02X %02X %02X %02X  %02X %02X %02X                               %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],
456             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]));
457           c += 7;
458           break;
459         case 6:
460           printf(" %02X %02X %02X %02X  %02X %02X                                  %c%c%c%c%c%c\n",
461             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5],
462             dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]), dcc(data[c+5]));
463           c += 6;
464           break;
465         case 5:
466           printf(" %02X %02X %02X %02X  %02X                                     %c%c%c%c%c\n",
467             data[c], data[c+1], data[c+2], data[c+3], data[c+4],
468             dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]));
469           c += 5;
470           break;
471         case 4:
472           printf(" %02X %02X %02X %02X                                         %c%c%c%c\n",
473             data[c], data[c+1], data[c+2], data[c+3],
474             dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]));
475           c += 4;
476           break;
477         case 3:
478           printf(" %02X %02X %02X                                            %c%c%c\n",
479             data[c], data[c+1], data[c+2],
480             dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]));
481           c += 3;
482           break;
483         case 2:
484           printf(" %02X %02X                                               %c%c\n",
485             data[c], data[c+1],
486             dcc(data[c]), dcc(data[c+1]));
487           c += 2;
488           break;
489         case 1:
490           printf(" %02X                                                  %c\n",
491             data[c],
492             dcc(data[c]));
493           c += 1;
494           break;
495       }
496     }
497   }
498 }
499
500 UCHAR TCP::dcc(UCHAR c)
501 {
502   if (isspace(c)) return ' ';
503   if (isprint(c)) return c;
504   return '.';
505 }