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