]> git.vomp.tv Git - vompclient.git/blob - tcp.cc
Compile fix for MVP re: location change of hmsf
[vompclient.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
242   unsigned char* buf = (unsigned char*)bufR;
243
244   MUTEX_LOCK(&mutex);
245
246   while (bytes_sent < count)
247   {
248     do
249     {
250 #ifndef WIN32
251       this_write = write(sock, buf, count - bytes_sent);
252 //      Log::getInstance()->log("TCP", Log::DEBUG, "TCP has written %i bytes", this_write);
253     } while ( (this_write < 0) && (errno == EINTR) );
254 #else
255       this_write = send(sock,(char*) buf, count- bytes_sent,0);
256     } while ( (this_write == SOCKET_ERROR) && (WSAGetLastError() == WSAEINTR) );
257 #endif
258     if (this_write <= 0)
259     {
260       MUTEX_UNLOCK(&mutex);
261       return(this_write);
262     }
263     bytes_sent += this_write;
264     buf += this_write;
265   }
266   
267   MUTEX_UNLOCK(&mutex);
268   
269   return(count);
270 }
271
272 int TCP::readData(UCHAR* buffer, int totalBytes)
273 {
274
275   int bytesRead = 0;
276   int thisRead;
277   int readTries = 0;
278   int success;
279   fd_set readSet;
280   struct timeval timeout;
281   struct timeval* passToSelect;
282
283   if (timeoutEnabled) passToSelect = &timeout;
284   else passToSelect = NULL;
285
286   while(1)
287   {
288     FD_ZERO(&readSet);
289     FD_SET(sock, &readSet);
290     timeout.tv_sec = 2;
291     timeout.tv_usec = 0;
292   //  Log::getInstance()->log("TCP", Log::DEBUG, "Going to select");
293     success = select(sock + 1, &readSet, NULL, NULL, passToSelect);
294    // Log::getInstance()->log("TCP", Log::DEBUG, "Back from select with success = %i", success);
295     if (success < 1)
296     {
297       return 0;  // error, or timeout
298     }
299 #ifndef WIN32
300     thisRead = read(sock, &buffer[bytesRead], totalBytes - bytesRead);
301 #else
302     thisRead = recv(sock, (char*)&buffer[bytesRead], totalBytes - bytesRead, 0);
303 #endif
304     //Log::getInstance()->log("TCP", Log::DEBUG, "Read %i", thisRead);
305     if (!thisRead)
306     {
307       // if read returns 0 then connection is closed
308       // in non-blocking mode if read is called with no data available, it returns -1
309       // and sets errno to EGAGAIN. but we use select so it wouldn't do that anyway.
310       Log::getInstance()->log("TCP", Log::ERR, "Detected connection closed");
311       CLOSESOCKET(sock);
312       connected = 0;
313       return 0;
314     }
315     bytesRead += thisRead;
316     if (bytesRead == totalBytes)
317     {
318       return 1;
319     }
320     else
321     {
322       if (++readTries == 1000)
323       {
324         Log::getInstance()->log("TCP", Log::ERR, "Too many reads");
325         return 0;
326       }
327     }
328   }
329 }
330
331 void TCP::dump(unsigned char* data, ULONG size)
332 {
333   printf("Size = %lu\n", size);
334
335   ULONG c = 0;
336   while(c < size)
337   {
338     if ((size - c) > 15)
339     {
340       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",
341         data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
342         data[c+8], data[c+9], data[c+10], data[c+11], data[c+12], data[c+13], data[c+14], data[c+15],
343         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]),
344         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]));
345       c += 16;
346     }
347     else
348     {
349       switch (size - c)
350       {
351         case 15:
352           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",
353             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
354             data[c+8], data[c+9], data[c+10], data[c+11], data[c+12], data[c+13], data[c+14],
355             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]),
356             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]));
357           c += 15;
358           break;
359         case 14:
360           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",
361             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
362             data[c+8], data[c+9], data[c+10], data[c+11], data[c+12], data[c+13],
363             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]),
364             dcc(data[c+8]), dcc(data[c+9]), dcc(data[c+10]), dcc(data[c+11]), dcc(data[c+12]), dcc(data[c+13]));
365           c += 14;
366           break;
367         case 13:
368           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",
369             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
370             data[c+8], data[c+9], data[c+10], data[c+11], data[c+12],
371             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]),
372             dcc(data[c+8]), dcc(data[c+9]), dcc(data[c+10]), dcc(data[c+11]), dcc(data[c+12]));
373           c += 13;
374           break;
375         case 12:
376           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",
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],
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]));
381           c += 12;
382           break;
383         case 11:
384           printf(" %02X %02X %02X %02X  %02X %02X %02X %02X  %02X %02X %02X                  %c%c%c%c%c%c%c%c%c%c%c\n",
385             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
386             data[c+8], data[c+9], data[c+10],
387             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]),
388             dcc(data[c+8]), dcc(data[c+9]), dcc(data[c+10]));
389           c += 11;
390           break;
391         case 10:
392           printf(" %02X %02X %02X %02X  %02X %02X %02X %02X  %02X %02X                     %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],
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]));
397           c += 10;
398           break;
399         case 9:
400           printf(" %02X %02X %02X %02X  %02X %02X %02X %02X  %02X                        %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],
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]));
405           c += 9;
406           break;
407         case 8:
408           printf(" %02X %02X %02X %02X  %02X %02X %02X %02X                            %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             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           c += 8;
412           break;
413         case 7:
414           printf(" %02X %02X %02X %02X  %02X %02X %02X                               %c%c%c%c%c%c%c\n",
415             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6],
416             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]));
417           c += 7;
418           break;
419         case 6:
420           printf(" %02X %02X %02X %02X  %02X %02X                                  %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],
422             dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]), dcc(data[c+5]));
423           c += 6;
424           break;
425         case 5:
426           printf(" %02X %02X %02X %02X  %02X                                     %c%c%c%c%c\n",
427             data[c], data[c+1], data[c+2], data[c+3], data[c+4],
428             dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]));
429           c += 5;
430           break;
431         case 4:
432           printf(" %02X %02X %02X %02X                                         %c%c%c%c\n",
433             data[c], data[c+1], data[c+2], data[c+3],
434             dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]));
435           c += 4;
436           break;
437         case 3:
438           printf(" %02X %02X %02X                                            %c%c%c\n",
439             data[c], data[c+1], data[c+2],
440             dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]));
441           c += 3;
442           break;
443         case 2:
444           printf(" %02X %02X                                               %c%c\n",
445             data[c], data[c+1],
446             dcc(data[c]), dcc(data[c+1]));
447           c += 2;
448           break;
449         case 1:
450           printf(" %02X                                                  %c\n",
451             data[c],
452             dcc(data[c]));
453           c += 1;
454           break;
455       }
456     }
457   }
458 }
459
460 UCHAR TCP::dcc(UCHAR c)
461 {
462   if (isspace(c)) return ' ';
463   if (isprint(c)) return c;
464   return '.';
465 }