]> git.vomp.tv Git - vompclient-marten.git/blob - tcp.cc
Add files for debian package generation
[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   //  Log::getInstance()->log("TCP", Log::DEBUG, "Going to select");
294     success = select(sock + 1, &readSet, NULL, NULL, passToSelect);
295    // Log::getInstance()->log("TCP", Log::DEBUG, "Back from select with success = %i", success);
296     if (success < 1)
297     {
298       return 0;  // error, or timeout
299     }
300 #ifndef WIN32
301     thisRead = read(sock, &buffer[bytesRead], totalBytes - bytesRead);
302 #else
303     thisRead = recv(sock, (char*)&buffer[bytesRead], totalBytes - bytesRead, 0);
304 #endif
305     //Log::getInstance()->log("TCP", Log::DEBUG, "Read %i", thisRead);
306     if (!thisRead)
307     {
308       // if read returns 0 then connection is closed
309       // in non-blocking mode if read is called with no data available, it returns -1
310       // and sets errno to EGAGAIN. but we use select so it wouldn't do that anyway.
311       Log::getInstance()->log("TCP", Log::ERR, "Detected connection closed");
312       CLOSESOCKET(sock);
313       connected = 0;
314       return 0;
315     }
316     bytesRead += thisRead;
317     if (bytesRead == totalBytes)
318     {
319       return 1;
320     }
321     else
322     {
323       if (++readTries == 100)
324       {
325         Log::getInstance()->log("TCP", Log::ERR, "Too many reads");
326         // return 0;
327       }
328     }
329   }
330 }
331
332 void TCP::dump(unsigned char* data, ULONG size)
333 {
334   printf("Size = %lu\n", size);
335
336   ULONG c = 0;
337   while(c < size)
338   {
339     if ((size - c) > 15)
340     {
341       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",
342         data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
343         data[c+8], data[c+9], data[c+10], data[c+11], data[c+12], data[c+13], data[c+14], data[c+15],
344         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]),
345         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]));
346       c += 16;
347     }
348     else
349     {
350       switch (size - c)
351       {
352         case 15:
353           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",
354             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
355             data[c+8], data[c+9], data[c+10], data[c+11], data[c+12], data[c+13], data[c+14],
356             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]),
357             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]));
358           c += 15;
359           break;
360         case 14:
361           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",
362             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
363             data[c+8], data[c+9], data[c+10], data[c+11], data[c+12], data[c+13],
364             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]),
365             dcc(data[c+8]), dcc(data[c+9]), dcc(data[c+10]), dcc(data[c+11]), dcc(data[c+12]), dcc(data[c+13]));
366           c += 14;
367           break;
368         case 13:
369           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",
370             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
371             data[c+8], data[c+9], data[c+10], data[c+11], data[c+12],
372             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]),
373             dcc(data[c+8]), dcc(data[c+9]), dcc(data[c+10]), dcc(data[c+11]), dcc(data[c+12]));
374           c += 13;
375           break;
376         case 12:
377           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",
378             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
379             data[c+8], data[c+9], data[c+10], data[c+11],
380             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]),
381             dcc(data[c+8]), dcc(data[c+9]), dcc(data[c+10]), dcc(data[c+11]));
382           c += 12;
383           break;
384         case 11:
385           printf(" %02X %02X %02X %02X  %02X %02X %02X %02X  %02X %02X %02X                  %c%c%c%c%c%c%c%c%c%c%c\n",
386             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
387             data[c+8], data[c+9], data[c+10],
388             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]),
389             dcc(data[c+8]), dcc(data[c+9]), dcc(data[c+10]));
390           c += 11;
391           break;
392         case 10:
393           printf(" %02X %02X %02X %02X  %02X %02X %02X %02X  %02X %02X                     %c%c%c%c%c%c%c%c%c%c\n",
394             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
395             data[c+8], data[c+9],
396             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]),
397             dcc(data[c+8]), dcc(data[c+9]));
398           c += 10;
399           break;
400         case 9:
401           printf(" %02X %02X %02X %02X  %02X %02X %02X %02X  %02X                        %c%c%c%c%c%c%c%c%c\n",
402             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
403             data[c+8],
404             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]),
405             dcc(data[c+8]));
406           c += 9;
407           break;
408         case 8:
409           printf(" %02X %02X %02X %02X  %02X %02X %02X %02X                            %c%c%c%c%c%c%c%c\n",
410             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
411             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]));
412           c += 8;
413           break;
414         case 7:
415           printf(" %02X %02X %02X %02X  %02X %02X %02X                               %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],
417             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]));
418           c += 7;
419           break;
420         case 6:
421           printf(" %02X %02X %02X %02X  %02X %02X                                  %c%c%c%c%c%c\n",
422             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5],
423             dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]), dcc(data[c+5]));
424           c += 6;
425           break;
426         case 5:
427           printf(" %02X %02X %02X %02X  %02X                                     %c%c%c%c%c\n",
428             data[c], data[c+1], data[c+2], data[c+3], data[c+4],
429             dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]));
430           c += 5;
431           break;
432         case 4:
433           printf(" %02X %02X %02X %02X                                         %c%c%c%c\n",
434             data[c], data[c+1], data[c+2], data[c+3],
435             dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]));
436           c += 4;
437           break;
438         case 3:
439           printf(" %02X %02X %02X                                            %c%c%c\n",
440             data[c], data[c+1], data[c+2],
441             dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]));
442           c += 3;
443           break;
444         case 2:
445           printf(" %02X %02X                                               %c%c\n",
446             data[c], data[c+1],
447             dcc(data[c]), dcc(data[c+1]));
448           c += 2;
449           break;
450         case 1:
451           printf(" %02X                                                  %c\n",
452             data[c],
453             dcc(data[c]));
454           c += 1;
455           break;
456       }
457     }
458   }
459 }
460
461 UCHAR TCP::dcc(UCHAR c)
462 {
463   if (isspace(c)) return ' ';
464   if (isprint(c)) return c;
465   return '.';
466 }