Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: orxonox.OLD/trunk/src/lib/network/network_socket.cc @ 6275

Last change on this file since 6275 was 6139, checked in by patrick, 19 years ago

trunk: merged branche network with trunk using command: svn merge -r5999:HEAD, conflicts resolved in favor of the trunk bla

File size: 10.1 KB
Line 
1/*
2   orxonox - the future of 3D-vertical-scrollers
3
4   Copyright (C) 2004 orx
5
6   This program is free software; you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation; either version 2, or (at your option)
9   any later version.
10
11### File Specific:
12   main-programmer: Christoph Renner, David Hasenfratz
13   co-programmer:
14*/
15
16
17
18/* this is for debug output. It just says, that all calls to PRINT() belong to the DEBUG_MODULE_NETWORK module
19   For more information refere to https://www.orxonox.net/cgi-bin/trac.cgi/wiki/DebugOutput
20*/
21#define DEBUG_MODULE_NETWORK
22
23
24/* include your own header */
25#include "network_socket.h"
26
27/* header for debug output */
28#include "debug.h"
29
30/**
31 * Default constructor
32 */
33NetworkSocket::NetworkSocket()
34{
35  this->init();
36}
37
38/**
39 * Constructor to connect directly
40 */
41NetworkSocket::NetworkSocket(IPaddress ip)
42{
43  this->init();
44  connectToServer(ip);
45}
46
47
48NetworkSocket::NetworkSocket( TCPsocket sock )
49{
50  this->init();
51  this->tcpSocket = sock;
52
53  readThread = SDL_CreateThread(thread_read, (void*)this);
54  writeThread = SDL_CreateThread(thread_write, (void*)this);
55}
56
57void NetworkSocket::init()
58{
59  /* set the class id for the base object */
60  this->setClassID(CL_NETWORK_SOCKET, "NetworkSocket");
61
62  tcpSocket = NULL;
63  incomingBufferLength = 0;
64  outgoingBufferLength = 0;
65
66  readThread = NULL;
67  writeThread = NULL;
68
69
70  thread_write_running = false;
71  thread_read_running = false;
72
73  incomingBufferMutex = SDL_CreateMutex();
74  outgoingBufferMutex = SDL_CreateMutex();
75
76
77  socketMutex = SDL_CreateMutex();
78  terminateThread = false;
79
80  /* Init SDL_net */
81  //NOTE: do we need to call SDLNet_Init for all instances?
82  if(SDLNet_Init()==-1)
83  {
84    PRINTF(1)("SDLNet_Init: %s\n", SDLNet_GetError());
85    return;
86  }
87  else
88    PRINTF(5)("SDL_net initialized\n");
89
90  PRINTF(0)("NetworkSocket created\n");
91
92}
93
94
95
96/**
97 * Default destructor
98 */
99NetworkSocket::~NetworkSocket( )
100{
101  this->terminateThread = true;
102  /* Quit SDL_net */
103  // NOTE: what if other instances of NetworkSocket running?
104  SDLNet_Quit();
105  PRINTF(5)("SDL_net shutdown\n");
106
107  SDL_DestroyMutex(incomingBufferMutex);
108  SDL_DestroyMutex(outgoingBufferMutex);
109  SDL_DestroyMutex(socketMutex);
110  SDL_DestroyMutex(threadTerminationMutex);
111}
112
113/**
114 * This function establishes a TCP/UDP connection to a given server (function argument).
115 * It is called by the NetworkStream. It creates a TCP/UDP socket for the connection.
116 * @param ip
117 */
118void NetworkSocket::connectToServer(IPaddress ip)
119{
120  //check if not already connected or listening
121  if (tcpSocket)
122  {
123    PRINTF(1)("NetworkSocket::listen: tcpSocket!=NULL! maybe you already called listen or connectToServer or did not call disconnectServer()!");
124  }
125
126  /* Connect to the host and port contained in ip using a TCP connection. */
127  tcpSocket = SDLNet_TCP_Open(&ip);
128  if(!tcpSocket)
129  {
130    PRINTF(1)("SDLNet_TCP_Open: %s\n", SDLNet_GetError());
131    return;
132  }
133
134  readThread = SDL_CreateThread(thread_read, (void*)this);
135  writeThread = SDL_CreateThread(thread_write, (void*)this);
136}
137
138
139/**
140 * DTears down a TCP/UDP connection.
141 */
142void NetworkSocket::disconnectServer( )
143{
144  terminateThread = true;
145  /* Close the connection */
146
147  SDL_mutexP(socketMutex);
148  SDLNet_TCP_Close(tcpSocket);
149  tcpSocket = NULL;
150  SDL_mutexV(socketMutex);
151}
152
153
154/**
155 * This function writes some bytes (data) to the network connection (if the connection is already
156 * estabilhed) otherwise it just does nothing (silently discarding the data). And writes some
157 * warnings
158 * @param data: pointer to the data to send
159 * @param length: n bytes to send
160 * @return the number successfully written bytes
161 */
162int NetworkSocket::writeBytes(byte * data, int length)
163{
164  PRINTF(5)("NetworkSocket::writeBytes()\n");
165#ifdef _USE_OUTGOING_BUFFER
166
167#define min(a,b) (a<b)?a:b
168  int nbytes = min(_OUTGOING_BUFFER_SIZE - outgoingBufferLength, length);
169#undef min
170
171  if (!tcpSocket || data==NULL || nbytes<=0)
172    return 0;
173
174  SDL_mutexP(outgoingBufferMutex);
175
176  memcpy(outgoingBuffer + outgoingBufferLength, data, nbytes);
177  outgoingBufferLength += nbytes;
178
179  SDL_mutexV(outgoingBufferMutex);
180
181
182  return nbytes;
183#else
184  SDL_mutexP(socketMutex);
185
186  if (!tcpSocket || data==NULL)
187    return 0;
188
189  int res = SDLNet_TCP_Send(tcpSocket, data, length);
190
191  SDL_mutexV(socketMutex);
192
193  if (res<length)
194    PRINTF(1)("SDLNet_TCP_Send: %s\n", SDLNet_GetError());
195
196  return res;
197#endif
198}
199
200/**
201 * Reads in the bytes from the network interface and passes it to the NetworkStream.
202 * This function must internaly be implemented/connected as a thread, since the read
203 * functions of many network libraries are blocking an would therefore block the whole
204 * program.
205 * From outside, the thread shouldn't be accessible at all.
206 * @param data: pointer to memory, big enough to store length bytes
207 * @param length: n bytes to read
208 * @return the number successfully read bytes. -1 on error. may be less than length!
209 */
210int NetworkSocket::readBytes(byte * data, int length)
211{
212  PRINTF(5)("NetworkSocket::readBytes()\n");
213  if (data==NULL)
214    return 0;
215
216  int nbytes = (length<incomingBufferLength) ? length : incomingBufferLength;
217
218
219  //printf("readBytes: nbytes = %d; length=%d; incomingBufferLength=%d\n", nbytes, length, incomingBufferLength);
220
221  // just in case ...
222  if (nbytes<0)
223    return -1;
224
225  if (nbytes==0)
226      return 0;
227
228  SDL_mutexP(incomingBufferMutex);
229
230  memcpy(data, incomingBuffer, nbytes);
231
232  //important: use memmove because the memory areas may overlap
233  memmove(incomingBuffer, incomingBuffer+nbytes, incomingBufferLength-nbytes);
234  incomingBufferLength -= nbytes;
235
236  SDL_mutexV(incomingBufferMutex);
237
238  return nbytes;
239}
240
241/**
242 * Reads in the bytes form the network interface and passes it to the NetworkStream.
243 * It only reads the bytes if there are enough bytes in our buffer.
244 * @param data: pointer to memory, big enough to store length bytes
245 * @param length: n bytes to read
246 * @return the number successfully read bytes. -1 on error. 0 if there are not enough bytes in our buffer.
247 */
248int NetworkSocket::readBlock(byte * data, int length)
249{
250  printf("NetworkSocket: got %i bytes, NetworkStream requested %i bytes\n", this->incomingBufferLength, length);
251  if (incomingBufferLength >= length)
252    return readBytes(data, length);
253  else return 0;
254}
255
256
257/**
258 * used to create a thread to read from socket
259 * @param data: pointer to NetworkSocket
260 */
261int NetworkSocket::thread_read( void * data )
262{
263  int nbytesread = 0;
264  int nbytestoread = 0;
265  char buffer[_LOCAL_BUFFER_SIZE];
266  NetworkSocket * self = (NetworkSocket*)data;
267
268  self->thread_read_running = true;
269
270  while (!self->terminateThread)
271  {
272#define min(a,b) (a<b)?a:b
273    nbytestoread = min(_INCOMING_BUFFER_SIZE - self->incomingBufferLength, _LOCAL_BUFFER_SIZE);
274#undef min
275
276    //if buffer is full
277    if (nbytestoread<=0 || !self->tcpSocket)
278    {
279      SDL_Delay(_MSECONDS_SLEEP_FULL_BUFFER);
280      continue;
281    }
282
283    nbytesread = SDLNet_TCP_Recv(self->tcpSocket, buffer, nbytestoread);
284
285    SDL_mutexP(self->incomingBufferMutex);
286
287    if (nbytesread<=0)
288    {
289      if (nbytesread<0)
290        printf("SDLNet_TCP_Recv: %s\n", SDLNet_GetError());
291
292      SDL_mutexP(self->socketMutex);
293
294      SDLNet_TCP_Close(self->tcpSocket);
295      self->tcpSocket = NULL;
296
297      SDL_mutexV(self->socketMutex);
298      SDL_mutexV(self->incomingBufferMutex);
299      continue;
300    }
301
302    //printf("thread_read: nbytesread=%d\n", nbytesread);
303
304    memcpy(self->incomingBuffer+self->incomingBufferLength, buffer, nbytesread);
305    self->incomingBufferLength += nbytesread;
306
307    SDL_mutexV(self->incomingBufferMutex);
308  }
309
310  SDL_mutexP(self->threadTerminationMutex);
311  self->thread_read_running = false;
312
313  if ( !self->thread_write_running )
314  {
315    //delete self;
316    SDL_mutexV(self->threadTerminationMutex);
317  }
318  else
319  {
320    SDL_mutexV(self->threadTerminationMutex);
321  }
322
323
324  PRINTF(0)("QUIT READ THREAD\n");
325  return 0;
326}
327
328int NetworkSocket::thread_write( void * data )
329{
330  int nbyteswrite = 0;
331  int nbytestowrite = 0;
332  char buffer[_LOCAL_BUFFER_SIZE];
333  NetworkSocket * self = (NetworkSocket*)data;
334
335  self->thread_write_running = true;
336
337  while (!self->terminateThread)
338  {
339#define min(a,b) (a<b)?a:b
340    nbytestowrite = min(self->outgoingBufferLength, _LOCAL_BUFFER_SIZE);
341#undef min
342
343//     printf("thread_write nbytes=%d listening=%d\n", nbytestowrite, (int)self->_isListening);
344
345    //if buffer is full
346    if (nbytestowrite<=0 || !self->tcpSocket)
347    {
348      SDL_Delay(_MSECONDS_SLEEP_EMPTY_BUFFER);
349      continue;
350    }
351
352    SDL_mutexP(self->outgoingBufferMutex);
353
354    //printf("a\n");
355
356    memcpy(buffer, self->outgoingBuffer, nbytestowrite);
357    self->outgoingBufferLength -= nbytestowrite;
358    memmove(self->outgoingBuffer, self->outgoingBuffer+nbytestowrite, self->outgoingBufferLength);
359
360    SDL_mutexV(self->outgoingBufferMutex);
361
362    nbyteswrite = SDLNet_TCP_Send(self->tcpSocket, buffer, nbytestowrite);
363
364    if (nbyteswrite<=0)
365    {
366      printf("SDLNet_TCP_Recv: %s\n", SDLNet_GetError());
367
368      SDL_mutexP(self->socketMutex);
369
370      SDLNet_TCP_Close(self->tcpSocket);
371      self->tcpSocket = NULL;
372
373      SDL_mutexV(self->socketMutex);
374      continue;
375    }
376
377  }
378
379  SDL_mutexP(self->threadTerminationMutex);
380  self->thread_write_running = false;
381
382  if ( !self->thread_read_running )
383  {
384    //delete self;
385    SDL_mutexV(self->threadTerminationMutex);
386  }
387  else
388  {
389    SDL_mutexV(self->threadTerminationMutex);
390  }
391
392
393  PRINTF(0)("QUIT WRITE THREAD\n");
394  return 0;
395}
396
397bool NetworkSocket::writePacket( byte * data, int length )
398{
399  PRINTF(5)("NetworkSocket::writePacket()\n");
400  if (length>255)
401  {
402    PRINTF(1)("Packet length > 255!\n");
403    return false;
404  }
405
406  byte blen = length;
407
408  writeBytes(&blen, 1);
409  writeBytes(data, length);
410}
411
412int NetworkSocket::readPacket( byte * data, int maxLength )
413{
414  PRINTF(5)("NetworkSocket::readPacket()\n");
415  if (incomingBufferLength<1)
416  {
417    return 0;
418  }
419
420  byte blen = incomingBuffer[0];
421
422  if (blen>maxLength)
423  {
424    PRINTF(1)("Buffersize is too small (%d) for packet (%d)\n", maxLength, blen);
425    return 0;
426  }
427
428  if (blen>incomingBufferLength)
429  {
430    return 0;
431  }
432
433  readBytes(&blen, 1);
434  int res = readBytes(data, blen);
435
436  if (res!=blen)
437    return -1;
438  else
439    return blen;
440
441}
442
443
Note: See TracBrowser for help on using the repository browser.