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