Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 7508 was 7440, checked in by bensch, 18 years ago

orxonox/trunk: merged the Signal-Handler-Branche back to the TRUNK

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