]> git.vomp.tv Git - vompclient.git/blob - tcp.cc
NTSC support, needs testing
[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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20 */
21
22 #include "tcp.h"
23
24 TCP::TCP()
25 {
26   sock = 0;
27   connected = 0;
28   timeoutEnabled = 1;
29 }
30
31 TCP::~TCP()
32 {
33   if (connected)
34   {
35     close(sock);
36     Log::getInstance()->log("TCP", Log::DEBUG, "Have closed");
37   }
38 }
39
40 void TCP::disableTimeout()
41 {
42   timeoutEnabled = 0;
43 }
44
45 int TCP::connectTo(char* host, unsigned short port)
46 {
47   sock = socket(PF_INET, SOCK_STREAM, 0);
48   if (sock == -1) return 0;
49
50   struct sockaddr_in dest_addr;
51   dest_addr.sin_family = AF_INET;
52   dest_addr.sin_port = htons(port);
53
54   if (!inet_aton(host, &dest_addr.sin_addr))
55   {
56     close(sock);
57     return 0;
58   }
59
60   memset(&(dest_addr.sin_zero), '\0', 8);
61
62   // set non blocking
63   int oldflags = fcntl (sock, F_GETFL, 0);
64   oldflags |= O_NONBLOCK;
65   fcntl(sock, F_SETFL, oldflags);
66
67   // ok, how to open a connection in non blocking mode (and therefore have a self set timeout!!)
68
69   int success = connect(sock, (struct sockaddr *)&dest_addr, sizeof(struct sockaddr));
70
71   if (success == 0)  // if by some miracle the connection succeeded in no time flat, just return!
72   {
73     connected = 1;
74     return 1;
75   }
76
77   // first check errno for EINPROGRESS, otherwise it's a fail
78   // this doesn't work?
79   if (errno != EINPROGRESS)
80   {
81     close(sock);
82     return 0;
83   }
84
85   // now do a timeout wait on writability on the socket
86
87   fd_set connectSet;
88   struct timeval timeout;
89   FD_ZERO(&connectSet);
90   FD_SET(sock, &connectSet);
91   timeout.tv_sec = 10;
92   timeout.tv_usec = 0;
93   success = select(sock + 1, NULL, &connectSet, NULL, &timeout);
94   if (success < 1)
95   {
96     // timeout or error
97     close(sock);
98     return 0;
99   }
100
101   // so the socket became available for writing. Contrary to expectation, this doesn't actually
102   // mean it connected...
103
104   int soError;
105   socklen_t soErrorSize = sizeof(soError);
106   int gso = getsockopt(sock, SOL_SOCKET, SO_ERROR, &soError, &soErrorSize);
107
108   if ((gso == 0) && (soError == 0))
109   {
110     // success!
111     connected = 1;
112     return 1;
113   }
114   else
115   {
116     close(sock);
117     return 0;
118   }
119
120 /*
121 The full documentation:
122
123        EINPROGRESS
124               The  socket is non-blocking and the connection canĀ­
125               not be completed immediately.  It  is  possible  to
126               select(2)  or  poll(2)  for completion by selecting
127               the socket  for  writing.  After  select  indicates
128               writability, use getsockopt(2) to read the SO_ERROR
129               option at level  SOL_SOCKET  to  determine  whether
130               connect  completed  successfully (SO_ERROR is zero)
131               or unsuccessfully (SO_ERROR is  one  of  the  usual
132               error  codes listed here, explaining the reason for
133               the failure).
134 */
135 }
136
137 void TCP::assignSocket(int tsocket)
138 {
139   sock = tsocket;
140 }
141
142 int TCP::isConnected()
143 {
144   return connected;
145 }
146
147 int TCP::sendPacket(void* bufR, size_t count)
148 {
149   size_t bytes_sent = 0;
150   int this_write;
151   int temp_write;
152
153   unsigned char* buf = (unsigned char*)bufR;
154
155   while (bytes_sent < count)
156   {
157     do
158     {
159       temp_write = this_write = write(sock, buf, count - bytes_sent);
160 //      Log::getInstance()->log("TCP", Log::DEBUG, "TCP has written %i bytes", temp_write);
161     } while ( (this_write < 0) && (errno == EINTR) );
162
163
164     if (this_write <= 0)
165     {
166       return(this_write);
167     }
168     bytes_sent += this_write;
169     buf += this_write;
170   }
171   return(count);
172 }
173
174 UCHAR* TCP::receivePacket()
175 {
176   ULONG packetLength;
177   int success;
178
179   success = readData((UCHAR*)&packetLength, sizeof(int));
180   if (!success) return NULL;
181
182   packetLength = ntohl(packetLength);
183
184   if (packetLength > 200000)
185   {
186     Log::getInstance()->log("TCP", Log::ERR, "Received packet > 200000");
187     return NULL;
188   }
189   if (packetLength == 0)
190   {
191     Log::getInstance()->log("TCP", Log::ERR, "Received packet len = 0");
192     return NULL;
193   }
194
195   UCHAR* buffer = (UCHAR*) malloc(packetLength);
196
197   success = readData(buffer, packetLength);
198
199   if (!success)
200   {
201     Log::getInstance()->log("TCP", Log::ERR, "readData failed");
202     free(buffer);
203     close(sock);
204     connected = 0;
205     return NULL;
206   }
207
208   dataLength = packetLength;
209   return buffer;
210 }
211
212 int TCP::getDataLength()
213 {
214   return dataLength;
215 }
216
217 int TCP::readData(UCHAR* buffer, int totalBytes)
218 {
219
220   int bytesRead = 0;
221   int thisRead;
222   int readTries = 0;
223   int success;
224   fd_set readSet;
225   struct timeval timeout;
226   struct timeval* passToSelect;
227
228   if (timeoutEnabled) passToSelect = &timeout;
229   else passToSelect = NULL;
230
231   while(1)
232   {
233     FD_ZERO(&readSet);
234     FD_SET(sock, &readSet);
235     timeout.tv_sec = 10;
236     timeout.tv_usec = 0;
237     success = select(sock + 1, &readSet, NULL, NULL, passToSelect);
238     if (success < 1)
239     {
240       Log::getInstance()->log("TCP", Log::ERR, "Error or timeout");
241       return 0;  // error, or timeout
242     }
243
244     thisRead = read(sock, &buffer[bytesRead], totalBytes - bytesRead);
245     if (!thisRead)
246     {
247       // if read returns 0 then connection is closed
248       // in non-blocking mode if read is called with no data available, it returns -1
249       // and sets errno to EGAGAIN. but we use select so it wouldn't do that anyway.
250       Log::getInstance()->log("TCP", Log::ERR, "Detected connection closed");
251       connected = 0;
252       return 0;
253     }
254     bytesRead += thisRead;
255
256     if (bytesRead == totalBytes)
257     {
258       return 1;
259     }
260     else
261     {
262       if (++readTries == 100)
263       {
264         Log::getInstance()->log("TCP", Log::ERR, "Too many reads");
265         return 0;
266       }
267     }
268   }
269 }
270
271 void TCP::dump(unsigned char* data, ULONG size)
272 {
273   printf("Size = %lu\n", size);
274
275   ULONG c = 0;
276   while(c < size)
277   {
278     if ((size - c) > 15)
279     {
280       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",
281         data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
282         data[c+8], data[c+9], data[c+10], data[c+11], data[c+12], data[c+13], data[c+14], data[c+15],
283         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]),
284         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]));
285       c += 16;
286     }
287     else
288     {
289       switch (size - c)
290       {
291         case 15:
292           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",
293             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
294             data[c+8], data[c+9], data[c+10], data[c+11], data[c+12], data[c+13], data[c+14],
295             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]),
296             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]));
297           c += 15;
298           break;
299         case 14:
300           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",
301             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
302             data[c+8], data[c+9], data[c+10], data[c+11], data[c+12], data[c+13],
303             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]),
304             dcc(data[c+8]), dcc(data[c+9]), dcc(data[c+10]), dcc(data[c+11]), dcc(data[c+12]), dcc(data[c+13]));
305           c += 14;
306           break;
307         case 13:
308           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",
309             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
310             data[c+8], data[c+9], data[c+10], data[c+11], data[c+12],
311             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]),
312             dcc(data[c+8]), dcc(data[c+9]), dcc(data[c+10]), dcc(data[c+11]), dcc(data[c+12]));
313           c += 13;
314           break;
315         case 12:
316           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",
317             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
318             data[c+8], data[c+9], data[c+10], data[c+11],
319             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]),
320             dcc(data[c+8]), dcc(data[c+9]), dcc(data[c+10]), dcc(data[c+11]));
321           c += 12;
322           break;
323         case 11:
324           printf(" %02X %02X %02X %02X  %02X %02X %02X %02X  %02X %02X %02X                  %c%c%c%c%c%c%c%c%c%c%c\n",
325             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
326             data[c+8], data[c+9], data[c+10],
327             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]),
328             dcc(data[c+8]), dcc(data[c+9]), dcc(data[c+10]));
329           c += 11;
330           break;
331         case 10:
332           printf(" %02X %02X %02X %02X  %02X %02X %02X %02X  %02X %02X                     %c%c%c%c%c%c%c%c%c%c\n",
333             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
334             data[c+8], data[c+9],
335             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]),
336             dcc(data[c+8]), dcc(data[c+9]));
337           c += 10;
338           break;
339         case 9:
340           printf(" %02X %02X %02X %02X  %02X %02X %02X %02X  %02X                        %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],
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]));
345           c += 9;
346           break;
347         case 8:
348           printf(" %02X %02X %02X %02X  %02X %02X %02X %02X                            %c%c%c%c%c%c%c%c\n",
349             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
350             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]));
351           c += 8;
352           break;
353         case 7:
354           printf(" %02X %02X %02X %02X  %02X %02X %02X                               %c%c%c%c%c%c%c\n",
355             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6],
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]));
357           c += 7;
358           break;
359         case 6:
360           printf(" %02X %02X %02X %02X  %02X %02X                                  %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],
362             dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]), dcc(data[c+5]));
363           c += 6;
364           break;
365         case 5:
366           printf(" %02X %02X %02X %02X  %02X                                     %c%c%c%c%c\n",
367             data[c], data[c+1], data[c+2], data[c+3], data[c+4],
368             dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]));
369           c += 5;
370           break;
371         case 4:
372           printf(" %02X %02X %02X %02X                                         %c%c%c%c\n",
373             data[c], data[c+1], data[c+2], data[c+3],
374             dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]));
375           c += 4;
376           break;
377         case 3:
378           printf(" %02X %02X %02X                                            %c%c%c\n",
379             data[c], data[c+1], data[c+2],
380             dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]));
381           c += 3;
382           break;
383         case 2:
384           printf(" %02X %02X                                               %c%c\n",
385             data[c], data[c+1],
386             dcc(data[c]), dcc(data[c+1]));
387           c += 2;
388           break;
389         case 1:
390           printf(" %02X                                                  %c\n",
391             data[c],
392             dcc(data[c]));
393           c += 1;
394           break;
395       }
396     }
397   }
398 }
399
400 UCHAR TCP::dcc(UCHAR c)
401 {
402   if (isspace(c)) return ' ';
403   if (isprint(c)) return c;
404   return '.';
405 }