]> git.vomp.tv Git - vompclient.git/blob - tcp.cc
Fix text corruption in channel number display on live tv
[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_PLATTFORM_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;
231   socklen_t soErrorSize = sizeof(soError);
232   int gso = getsockopt(sock, SOL_SOCKET, SO_ERROR,(char*) &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   int r = setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char*)&rxBufferSize, sizeof(size_t));
267   Log::getInstance()->log("TCP", Log::DEBUG, "Set receive window to %i, success(=0): %i", rxBufferSize, r);
268 }
269
270 void TCP::assignSocket(int tsocket)
271 {
272   sock = tsocket;
273 }
274
275 int TCP::isConnected()
276 {
277   return connected;
278 }
279
280 int TCP::sendData(void* bufR, size_t count)
281 {
282   size_t bytes_sent = 0;
283   int this_write;
284
285   unsigned char* buf = (unsigned char*)bufR;
286
287   MUTEX_LOCK(&mutex);
288
289   while (bytes_sent < count)
290   {
291     do
292     {
293 #ifndef WIN32
294       this_write = write(sock, buf, count - bytes_sent);
295 //      Log::getInstance()->log("TCP", Log::DEBUG, "TCP has written %i bytes", this_write);
296     } while ( (this_write < 0) && (errno == EINTR) );
297 #else
298       this_write = send(sock,(char*) buf, count- bytes_sent,0);
299     } while ( (this_write == SOCKET_ERROR) && (WSAGetLastError() == WSAEINTR) );
300 #endif
301     if (this_write <= 0)
302     {
303       MUTEX_UNLOCK(&mutex);
304       return(this_write);
305     }
306     bytes_sent += this_write;
307     buf += this_write;
308   }
309   
310   MUTEX_UNLOCK(&mutex);
311   
312   return(count);
313 }
314
315 int TCP::readData(UCHAR* buffer, int totalBytes)
316 {
317
318   int bytesRead = 0;
319   int thisRead;
320   int readTries = 0;
321   int success;
322   fd_set readSet;
323   struct timeval timeout;
324   struct timeval* passToSelect;
325
326   if (timeoutEnabled) passToSelect = &timeout;
327   else passToSelect = NULL;
328
329   while(1)
330   {
331     FD_ZERO(&readSet);
332     FD_SET(sock, &readSet);
333     timeout.tv_sec = 2;
334     timeout.tv_usec = 0;
335   //  Log::getInstance()->log("TCP", Log::DEBUG, "Going to select");
336     success = select(sock + 1, &readSet, NULL, NULL, passToSelect);
337    // Log::getInstance()->log("TCP", Log::DEBUG, "Back from select with success = %i", success);
338     if (success < 1)
339     {
340       return 0;  // error, or timeout
341     }
342 #ifndef WIN32
343     thisRead = read(sock, &buffer[bytesRead], totalBytes - bytesRead);
344 #else
345     thisRead = recv(sock, (char*)&buffer[bytesRead], totalBytes - bytesRead, 0);
346 #endif
347     //Log::getInstance()->log("TCP", Log::DEBUG, "Read %i", thisRead);
348     if (!thisRead)
349     {
350       // if read returns 0 then connection is closed
351       // in non-blocking mode if read is called with no data available, it returns -1
352       // and sets errno to EGAGAIN. but we use select so it wouldn't do that anyway.
353       Log::getInstance()->log("TCP", Log::ERR, "Detected connection closed");
354       CLOSESOCKET(sock);
355       connected = 0;
356       return 0;
357     }
358     bytesRead += thisRead;
359     if (bytesRead == totalBytes)
360     {
361       return 1;
362     }
363     else
364     {
365       if (++readTries == 1000)
366       {
367         Log::getInstance()->log("TCP", Log::ERR, "Too many reads");
368         return 0;
369       }
370     }
371   }
372 }
373
374 void TCP::dump(unsigned char* data, ULONG size)
375 {
376   printf("Size = %lu\n", size);
377
378   ULONG c = 0;
379   while(c < size)
380   {
381     if ((size - c) > 15)
382     {
383       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",
384         data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
385         data[c+8], data[c+9], data[c+10], data[c+11], data[c+12], data[c+13], data[c+14], data[c+15],
386         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]),
387         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       c += 16;
389     }
390     else
391     {
392       switch (size - c)
393       {
394         case 15:
395           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",
396             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
397             data[c+8], data[c+9], data[c+10], data[c+11], data[c+12], data[c+13], data[c+14],
398             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]),
399             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]));
400           c += 15;
401           break;
402         case 14:
403           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",
404             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
405             data[c+8], data[c+9], data[c+10], data[c+11], data[c+12], data[c+13],
406             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]),
407             dcc(data[c+8]), dcc(data[c+9]), dcc(data[c+10]), dcc(data[c+11]), dcc(data[c+12]), dcc(data[c+13]));
408           c += 14;
409           break;
410         case 13:
411           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",
412             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
413             data[c+8], data[c+9], data[c+10], data[c+11], data[c+12],
414             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]),
415             dcc(data[c+8]), dcc(data[c+9]), dcc(data[c+10]), dcc(data[c+11]), dcc(data[c+12]));
416           c += 13;
417           break;
418         case 12:
419           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",
420             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
421             data[c+8], data[c+9], data[c+10], data[c+11],
422             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]),
423             dcc(data[c+8]), dcc(data[c+9]), dcc(data[c+10]), dcc(data[c+11]));
424           c += 12;
425           break;
426         case 11:
427           printf(" %02X %02X %02X %02X  %02X %02X %02X %02X  %02X %02X %02X                  %c%c%c%c%c%c%c%c%c%c%c\n",
428             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
429             data[c+8], data[c+9], data[c+10],
430             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]),
431             dcc(data[c+8]), dcc(data[c+9]), dcc(data[c+10]));
432           c += 11;
433           break;
434         case 10:
435           printf(" %02X %02X %02X %02X  %02X %02X %02X %02X  %02X %02X                     %c%c%c%c%c%c%c%c%c%c\n",
436             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
437             data[c+8], data[c+9],
438             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]),
439             dcc(data[c+8]), dcc(data[c+9]));
440           c += 10;
441           break;
442         case 9:
443           printf(" %02X %02X %02X %02X  %02X %02X %02X %02X  %02X                        %c%c%c%c%c%c%c%c%c\n",
444             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
445             data[c+8],
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             dcc(data[c+8]));
448           c += 9;
449           break;
450         case 8:
451           printf(" %02X %02X %02X %02X  %02X %02X %02X %02X                            %c%c%c%c%c%c%c%c\n",
452             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
453             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]));
454           c += 8;
455           break;
456         case 7:
457           printf(" %02X %02X %02X %02X  %02X %02X %02X                               %c%c%c%c%c%c%c\n",
458             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6],
459             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]));
460           c += 7;
461           break;
462         case 6:
463           printf(" %02X %02X %02X %02X  %02X %02X                                  %c%c%c%c%c%c\n",
464             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5],
465             dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]), dcc(data[c+5]));
466           c += 6;
467           break;
468         case 5:
469           printf(" %02X %02X %02X %02X  %02X                                     %c%c%c%c%c\n",
470             data[c], data[c+1], data[c+2], data[c+3], data[c+4],
471             dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]));
472           c += 5;
473           break;
474         case 4:
475           printf(" %02X %02X %02X %02X                                         %c%c%c%c\n",
476             data[c], data[c+1], data[c+2], data[c+3],
477             dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]));
478           c += 4;
479           break;
480         case 3:
481           printf(" %02X %02X %02X                                            %c%c%c\n",
482             data[c], data[c+1], data[c+2],
483             dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]));
484           c += 3;
485           break;
486         case 2:
487           printf(" %02X %02X                                               %c%c\n",
488             data[c], data[c+1],
489             dcc(data[c]), dcc(data[c+1]));
490           c += 2;
491           break;
492         case 1:
493           printf(" %02X                                                  %c\n",
494             data[c],
495             dcc(data[c]));
496           c += 1;
497           break;
498       }
499     }
500   }
501 }
502
503 UCHAR TCP::dcc(UCHAR c)
504 {
505   if (isspace(c)) return ' ';
506   if (isprint(c)) return c;
507   return '.';
508 }