]> git.vomp.tv Git - vompclient.git/blob - tcpold.cc
Rename TCP class to TCPOld
[vompclient.git] / tcpold.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 "tcpold.h"
34
35 TCPOld::TCPOld()
36 {
37   sock = 0;
38   connected = 0;
39   timeoutEnabled = 1;
40 }
41
42 TCPOld::~TCPOld()
43 {
44   if (connected)
45   {
46     CLOSESOCKET(sock);
47     Log::getInstance()->log("TCPOld", Log::DEBUG, "Have closed");
48   }
49 }
50
51 void TCPOld::disableTimeout()
52 {
53   timeoutEnabled = 0;
54 }
55
56 void TCPOld::getMAC(UCHAR* dest)
57 {
58 #ifndef WIN32
59   struct ifreq ifr;
60   strcpy(ifr.ifr_name, "eth0");
61   ioctl(sock, SIOCGIFHWADDR, &ifr);
62   memcpy(dest, ifr.ifr_hwaddr.sa_data, 6);
63 #else
64   //TODO: Get MAC Address for windows
65   PIP_ADAPTER_INFO daptinfo=NULL;
66   DWORD size=0;
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)
75   {
76     PIP_ADAPTER_INFO daptinfo_it=daptinfo;
77     while (daptinfo_it!=NULL)
78     {
79       ULONG ipaddress=inet_addr(daptinfo_it->IpAddressList.IpAddress.String);
80       if (ipaddress==sockip)
81       { //Is it our MAC?
82         memcpy(dest,daptinfo_it->Address, 6);
83         break;
84       }
85       daptinfo_it=daptinfo_it->Next;
86       if (daptinfo_it==daptinfo) break;
87     }
88   }
89   else
90   {
91     // Marten?
92   }
93
94   delete [] daptinfo;
95 #endif
96 }
97
98 int TCPOld::connectTo(char* host, unsigned short port)
99 {
100 #ifdef VOMP_PLATFORM_RASPBERRY
101 #define IPV 6
102 #else
103 #define IPV 4
104 #endif
105
106 #if IPV == 4
107
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);
113
114 #ifndef WIN32
115   if (!inet_aton(host, &dest_addr.sin_addr))
116 #else
117   dest_addr.sin_addr.s_addr = inet_addr(host);
118   if (dest_addr.sin_addr.s_addr == INADDR_NONE)
119 #endif
120   {
121     CLOSESOCKET(sock);
122     return 0;
123   }
124
125   memset(&(dest_addr.sin_zero), '\0', 8);
126
127 #elif IPV == 6
128
129   char portstring[10];
130   snprintf(portstring, 10, "%u", port);
131
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))
138   {
139     //printf("[%s] [%s]\n", host, portstring);
140     return 0;
141   }
142
143   sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
144   if (sock == -1) return 0;
145
146 #endif
147
148
149
150   // set non blocking
151 #ifndef WIN32
152   int oldflags = fcntl (sock, F_GETFL, 0);
153   oldflags |= O_NONBLOCK;
154   fcntl(sock, F_SETFL, oldflags);
155 #else
156   unsigned long flag=1;
157   ioctlsocket(sock,FIONBIO,&flag);
158
159 #endif
160
161 //  setReceiveWindow(2048);
162
163   // ok, how to open a connection in non blocking mode (and therefore have a self set timeout!!)
164
165 #if IPV == 4
166   int success = connect(sock, (struct sockaddr *)&dest_addr, sizeof(dest_addr));
167 #elif IPV == 6
168   int success = connect(sock, res->ai_addr, res->ai_addrlen);
169   freeaddrinfo(res);
170 #endif
171
172
173   if (success == 0)  // if by some miracle the connection succeeded in no time flat, just return!
174   {
175     connected = 1;
176     return 1;
177   }
178
179   // first check errno for EINPROGRESS, otherwise it's a fail
180   // this doesn't work?
181 #ifndef WIN32
182   if (errno != EINPROGRESS)
183 #else
184   int wsalasterr = WSAGetLastError();
185   if ((wsalasterr != WSAEWOULDBLOCK) && (wsalasterr != WSAEINPROGRESS))
186 #endif
187   {
188     CLOSESOCKET(sock);
189
190     return 0;
191   }
192
193   // now do a timeout wait on writability on the socket
194
195   fd_set connectSet;
196   struct timeval timeout;
197   FD_ZERO(&connectSet);
198   FD_SET(sock, &connectSet);
199   timeout.tv_sec = 10;
200   timeout.tv_usec = 0;
201   success = select(sock + 1, NULL, &connectSet, NULL, &timeout);
202   if (success < 1)
203   {
204     // timeout or error
205     CLOSESOCKET(sock);
206     return 0;
207   }
208
209   // so the socket became available for writing. Contrary to expectation, this doesn't actually
210   // mean it connected...
211
212   int soError; // SO_ERROR optval is int
213   socklen_t soErrorSize = sizeof(soError);
214
215 #ifdef WIN32
216   int gso = getsockopt(sock, SOL_SOCKET, SO_ERROR, reinterpret_cast<char*>(&soError), &soErrorSize);
217 #else
218   int gso = getsockopt(sock, SOL_SOCKET, SO_ERROR, reinterpret_cast<void*>(&soError), &soErrorSize);
219 #endif
220
221   if ((gso == 0) && (soError == 0))
222   {
223     // success!
224     connected = 1;
225     return 1;
226   }
227   else
228   {
229     CLOSESOCKET(sock);
230     return 0;
231   }
232
233 /*
234 The full documentation:
235
236        EINPROGRESS
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
246               the failure).
247 */
248 }
249
250 void TCPOld::setReceiveWindow(size_t rxBufferSize)
251 {
252   // Set receive window
253   // According to docs, optval in setsockopt is a pointer to int unless otherwise noted
254   int rxSize = rxBufferSize;
255 #ifdef WIN32
256   int r = setsockopt(sock, SOL_SOCKET, SO_RCVBUF, reinterpret_cast<char*>(&rxSize), sizeof(size_t));
257 #else
258   int r = setsockopt(sock, SOL_SOCKET, SO_RCVBUF, reinterpret_cast<void*>(&rxSize), sizeof(size_t));
259 #endif
260   Log::getInstance()->log("TCPOld", Log::DEBUG, "Set receive window to %i, success(=0): %i", rxBufferSize, r);
261 }
262
263 void TCPOld::assignSocket(int tsocket)
264 {
265   sock = tsocket;
266 }
267
268 int TCPOld::isConnected()
269 {
270   return connected;
271 }
272
273 int TCPOld::sendData(void* bufR, size_t count)
274 {
275   size_t bytes_sent = 0;
276   int this_write;
277
278   unsigned char* buf = static_cast<unsigned char*>(bufR);
279
280   mutex.lock();
281
282   while (bytes_sent < count)
283   {
284     do
285     {
286 #ifndef WIN32
287       this_write = write(sock, buf, count - bytes_sent);
288 //      Log::getInstance()->log("TCPOld", Log::DEBUG, "TCPOld has written %i bytes", this_write);
289     } while ( (this_write < 0) && (errno == EINTR) );
290 #else
291       this_write = send(sock,(char*) buf, count- bytes_sent,0);
292     } while ( (this_write == SOCKET_ERROR) && (WSAGetLastError() == WSAEINTR) );
293 #endif
294     if (this_write <= 0)
295     {
296       mutex.unlock();
297       return(this_write);
298     }
299     bytes_sent += this_write;
300     buf += this_write;
301   }
302   
303   mutex.unlock();
304   
305   return(count);
306 }
307
308 int TCPOld::readData(void* targetBuffer, int totalBytes)
309 {
310   UCHAR* buffer = reinterpret_cast<UCHAR*>(targetBuffer);
311   int bytesRead = 0;
312   int thisRead;
313   int readTries = 0;
314   int success;
315   fd_set readSet;
316   struct timeval timeout;
317   struct timeval* passToSelect;
318
319   if (timeoutEnabled) passToSelect = &timeout;
320   else passToSelect = NULL;
321
322   while(1)
323   {
324     FD_ZERO(&readSet);
325     FD_SET(sock, &readSet);
326     timeout.tv_sec = 2;
327     timeout.tv_usec = 0;
328   //  Log::getInstance()->log("TCPOld", Log::DEBUG, "Going to select");
329     success = select(sock + 1, &readSet, NULL, NULL, passToSelect);
330    // Log::getInstance()->log("TCPOld", Log::DEBUG, "Back from select with success = %i", success);
331     if (success < 1)
332     {
333       return 0;  // error, or timeout
334     }
335 #ifndef WIN32
336     thisRead = read(sock, &buffer[bytesRead], totalBytes - bytesRead);
337 #else
338     thisRead = recv(sock, (char*)&buffer[bytesRead], totalBytes - bytesRead, 0);
339 #endif
340     //Log::getInstance()->log("TCPOld", Log::DEBUG, "Read %i", thisRead);
341     if (!thisRead)
342     {
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("TCPOld", Log::ERR, "Detected connection closed");
347       CLOSESOCKET(sock);
348       connected = 0;
349       return 0;
350     }
351     bytesRead += thisRead;
352     if (bytesRead == totalBytes)
353     {
354       return 1;
355     }
356     else
357     {
358       if (++readTries == 1000)
359       {
360         Log::getInstance()->log("TCPOld", Log::ERR, "Too many reads");
361         return 0;
362       }
363     }
364   }
365 }
366
367 void TCPOld::dump(unsigned char* data, ULONG size)
368 {
369   printf("Size = %lu\n", size);
370
371   ULONG c = 0;
372   while(c < size)
373   {
374     if ((size - c) > 15)
375     {
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]));
381       c += 16;
382     }
383     else
384     {
385       switch (size - c)
386       {
387         case 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]));
393           c += 15;
394           break;
395         case 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]));
401           c += 14;
402           break;
403         case 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]));
409           c += 13;
410           break;
411         case 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]));
417           c += 12;
418           break;
419         case 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]));
425           c += 11;
426           break;
427         case 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]));
433           c += 10;
434           break;
435         case 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],
438             data[c+8],
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]),
440             dcc(data[c+8]));
441           c += 9;
442           break;
443         case 8:
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]));
447           c += 8;
448           break;
449         case 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]));
453           c += 7;
454           break;
455         case 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]));
459           c += 6;
460           break;
461         case 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]));
465           c += 5;
466           break;
467         case 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]));
471           c += 4;
472           break;
473         case 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]));
477           c += 3;
478           break;
479         case 2:
480           printf(" %02X %02X                                               %c%c\n",
481             data[c], data[c+1],
482             dcc(data[c]), dcc(data[c+1]));
483           c += 2;
484           break;
485         case 1:
486           printf(" %02X                                                  %c\n",
487             data[c],
488             dcc(data[c]));
489           c += 1;
490           break;
491       }
492     }
493   }
494 }
495
496 UCHAR TCPOld::dcc(UCHAR c)
497 {
498   if (isspace(c)) return ' ';
499   if (isprint(c)) return c;
500   return '.';
501 }