Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: orxonox.OLD/branches/network/src/lib/network/network_socket.cc @ 6592

Last change on this file since 6592 was 6582, checked in by rennerc, 19 years ago

added warning when sending big packets

File size: 10.2 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
99 */
[6139]100NetworkSocket::~NetworkSocket( )
[5542]101{
[6139]102  this->terminateThread = true;
[5592]103  /* Quit SDL_net */
[5624]104  // NOTE: what if other instances of NetworkSocket running?
[5592]105  SDLNet_Quit();
106  PRINTF(5)("SDL_net shutdown\n");
[5625]107
[5630]108  SDL_DestroyMutex(incomingBufferMutex);
109  SDL_DestroyMutex(outgoingBufferMutex);
110  SDL_DestroyMutex(socketMutex);
[6139]111  SDL_DestroyMutex(threadTerminationMutex);
[5542]112}
113
114/**
[5624]115 * This function establishes a TCP/UDP connection to a given server (function argument).
116 * It is called by the NetworkStream. It creates a TCP/UDP socket for the connection.
117 * @param ip
118 */
[5804]119void NetworkSocket::connectToServer(IPaddress ip)
[5542]120{
[5624]121  //check if not already connected or listening
122  if (tcpSocket)
123  {
124    PRINTF(1)("NetworkSocket::listen: tcpSocket!=NULL! maybe you already called listen or connectToServer or did not call disconnectServer()!");
125  }
[5577]126
[5592]127  /* Connect to the host and port contained in ip using a TCP connection. */
128  tcpSocket = SDLNet_TCP_Open(&ip);
129  if(!tcpSocket)
130  {
[5577]131    PRINTF(1)("SDLNet_TCP_Open: %s\n", SDLNet_GetError());
132    return;
[5592]133  }
[5577]134
[6139]135  readThread = SDL_CreateThread(thread_read, (void*)this);
136  writeThread = SDL_CreateThread(thread_write, (void*)this);
[5542]137}
138
[5624]139
[5542]140/**
[5565]141 * DTears down a TCP/UDP connection.
[5542]142 */
143void NetworkSocket::disconnectServer( )
144{
[5624]145  terminateThread = true;
[5592]146  /* Close the connection */
[5625]147
[5630]148  SDL_mutexP(socketMutex);
[5592]149  SDLNet_TCP_Close(tcpSocket);
[5624]150  tcpSocket = NULL;
[5630]151  SDL_mutexV(socketMutex);
[5542]152}
153
[5624]154
[5542]155/**
[5624]156 * This function writes some bytes (data) to the network connection (if the connection is already
157 * estabilhed) otherwise it just does nothing (silently discarding the data). And writes some
158 * warnings
159 * @param data: pointer to the data to send
160 * @param length: n bytes to send
161 * @return the number successfully written bytes
162 */
163int NetworkSocket::writeBytes(byte * data, int length)
[5542]164{
[6139]165  PRINTF(5)("NetworkSocket::writeBytes()\n");
[5630]166#ifdef _USE_OUTGOING_BUFFER
[5625]167
[5630]168#define min(a,b) (a<b)?a:b
169  int nbytes = min(_OUTGOING_BUFFER_SIZE - outgoingBufferLength, length);
170#undef min
171
172  if (!tcpSocket || data==NULL || nbytes<=0)
173    return 0;
174
175  SDL_mutexP(outgoingBufferMutex);
176
177  memcpy(outgoingBuffer + outgoingBufferLength, data, nbytes);
178  outgoingBufferLength += nbytes;
[5804]179
[5630]180  SDL_mutexV(outgoingBufferMutex);
181
[5805]182
[5630]183  return nbytes;
184#else
185  SDL_mutexP(socketMutex);
186
[5624]187  if (!tcpSocket || data==NULL)
188    return 0;
189
190  int res = SDLNet_TCP_Send(tcpSocket, data, length);
191
[5630]192  SDL_mutexV(socketMutex);
[5625]193
[5624]194  if (res<length)
195    PRINTF(1)("SDLNet_TCP_Send: %s\n", SDLNet_GetError());
[5628]196
197  return res;
[5630]198#endif
[5542]199}
200
[5624]201/**
202 * Reads in the bytes from the network interface and passes it to the NetworkStream.
203 * This function must internaly be implemented/connected as a thread, since the read
204 * functions of many network libraries are blocking an would therefore block the whole
205 * program.
206 * From outside, the thread shouldn't be accessible at all.
207 * @param data: pointer to memory, big enough to store length bytes
208 * @param length: n bytes to read
209 * @return the number successfully read bytes. -1 on error. may be less than length!
210 */
[5614]211int NetworkSocket::readBytes(byte * data, int length)
[5542]212{
[6139]213  PRINTF(5)("NetworkSocket::readBytes()\n");
[5625]214  if (data==NULL)
[5624]215    return 0;
216
[5630]217  int nbytes = (length<incomingBufferLength) ? length : incomingBufferLength;
[5624]218
[5808]219
[5630]220  //printf("readBytes: nbytes = %d; length=%d; incomingBufferLength=%d\n", nbytes, length, incomingBufferLength);
221
[5624]222  // just in case ...
223  if (nbytes<0)
224    return -1;
225
226  if (nbytes==0)
227      return 0;
228
[5630]229  SDL_mutexP(incomingBufferMutex);
[5624]230
[5630]231  memcpy(data, incomingBuffer, nbytes);
[5624]232
233  //important: use memmove because the memory areas may overlap
[5630]234  memmove(incomingBuffer, incomingBuffer+nbytes, incomingBufferLength-nbytes);
235  incomingBufferLength -= nbytes;
[5624]236
[5630]237  SDL_mutexV(incomingBufferMutex);
[5624]238
239  return nbytes;
[5542]240}
[5624]241
242/**
[5725]243 * Reads in the bytes form the network interface and passes it to the NetworkStream.
244 * It only reads the bytes if there are enough bytes in our buffer.
245 * @param data: pointer to memory, big enough to store length bytes
246 * @param length: n bytes to read
247 * @return the number successfully read bytes. -1 on error. 0 if there are not enough bytes in our buffer.
248 */
[5729]249int NetworkSocket::readBlock(byte * data, int length)
[5725]250{
[5804]251  printf("NetworkSocket: got %i bytes, NetworkStream requested %i bytes\n", this->incomingBufferLength, length);
[5725]252  if (incomingBufferLength >= length)
253    return readBytes(data, length);
254  else return 0;
255}
256
[5624]257
258/**
259 * used to create a thread to read from socket
260 * @param data: pointer to NetworkSocket
261 */
262int NetworkSocket::thread_read( void * data )
263{
264  int nbytesread = 0;
265  int nbytestoread = 0;
266  char buffer[_LOCAL_BUFFER_SIZE];
267  NetworkSocket * self = (NetworkSocket*)data;
268
[6139]269  self->thread_read_running = true;
270
[5624]271  while (!self->terminateThread)
272  {
273#define min(a,b) (a<b)?a:b
[5630]274    nbytestoread = min(_INCOMING_BUFFER_SIZE - self->incomingBufferLength, _LOCAL_BUFFER_SIZE);
275#undef min
[5624]276
[5628]277    //if buffer is full
[6139]278    if (nbytestoread<=0 || !self->tcpSocket)
[5628]279    {
280      SDL_Delay(_MSECONDS_SLEEP_FULL_BUFFER);
281      continue;
282    }
283
[5624]284    nbytesread = SDLNet_TCP_Recv(self->tcpSocket, buffer, nbytestoread);
285
[5630]286    SDL_mutexP(self->incomingBufferMutex);
[5624]287
288    if (nbytesread<=0)
289    {
[6139]290      if (nbytesread<0)
291        printf("SDLNet_TCP_Recv: %s\n", SDLNet_GetError());
[5625]292
[5630]293      SDL_mutexP(self->socketMutex);
[5625]294
[5624]295      SDLNet_TCP_Close(self->tcpSocket);
296      self->tcpSocket = NULL;
[5625]297
[5630]298      SDL_mutexV(self->socketMutex);
299      SDL_mutexV(self->incomingBufferMutex);
[6139]300      continue;
[5624]301    }
302
[5630]303    //printf("thread_read: nbytesread=%d\n", nbytesread);
[5624]304
[5630]305    memcpy(self->incomingBuffer+self->incomingBufferLength, buffer, nbytesread);
306    self->incomingBufferLength += nbytesread;
307
308    SDL_mutexV(self->incomingBufferMutex);
[5624]309  }
310
[6139]311  SDL_mutexP(self->threadTerminationMutex);
312  self->thread_read_running = false;
313
314  if ( !self->thread_write_running )
315  {
316    //delete self;
317    SDL_mutexV(self->threadTerminationMutex);
318  }
319  else
320  {
321    SDL_mutexV(self->threadTerminationMutex);
322  }
323
324
325  PRINTF(0)("QUIT READ THREAD\n");
[5624]326  return 0;
327}
328
[5630]329int NetworkSocket::thread_write( void * data )
330{
331  int nbyteswrite = 0;
332  int nbytestowrite = 0;
333  char buffer[_LOCAL_BUFFER_SIZE];
334  NetworkSocket * self = (NetworkSocket*)data;
[5624]335
[6139]336  self->thread_write_running = true;
337
[5630]338  while (!self->terminateThread)
339  {
340#define min(a,b) (a<b)?a:b
341    nbytestowrite = min(self->outgoingBufferLength, _LOCAL_BUFFER_SIZE);
342#undef min
[5628]343
[5805]344//     printf("thread_write nbytes=%d listening=%d\n", nbytestowrite, (int)self->_isListening);
[5630]345
346    //if buffer is full
[6139]347    if (nbytestowrite<=0 || !self->tcpSocket)
[5630]348    {
349      SDL_Delay(_MSECONDS_SLEEP_EMPTY_BUFFER);
350      continue;
351    }
352
353    SDL_mutexP(self->outgoingBufferMutex);
354
355    //printf("a\n");
356
357    memcpy(buffer, self->outgoingBuffer, nbytestowrite);
358    self->outgoingBufferLength -= nbytestowrite;
359    memmove(self->outgoingBuffer, self->outgoingBuffer+nbytestowrite, self->outgoingBufferLength);
360
361    SDL_mutexV(self->outgoingBufferMutex);
362
363    nbyteswrite = SDLNet_TCP_Send(self->tcpSocket, buffer, nbytestowrite);
364
365    if (nbyteswrite<=0)
366    {
[5737]367      printf("SDLNet_TCP_Recv: %s\n", SDLNet_GetError());
[5630]368
369      SDL_mutexP(self->socketMutex);
370
371      SDLNet_TCP_Close(self->tcpSocket);
372      self->tcpSocket = NULL;
373
374      SDL_mutexV(self->socketMutex);
[6139]375      continue;
[5630]376    }
377
378  }
379
[6139]380  SDL_mutexP(self->threadTerminationMutex);
381  self->thread_write_running = false;
382
383  if ( !self->thread_read_running )
384  {
385    //delete self;
386    SDL_mutexV(self->threadTerminationMutex);
387  }
388  else
389  {
390    SDL_mutexV(self->threadTerminationMutex);
391  }
392
393
394  PRINTF(0)("QUIT WRITE THREAD\n");
[5630]395  return 0;
396}
397
[5996]398bool NetworkSocket::writePacket( byte * data, int length )
399{
[6582]400  PRINTF(5)("NetworkSocket::writePacket() size=%d\n", length);
[5996]401
[6582]402  if ( length > 1024 )
403  PRINTF(2)("WARNING SENDING BIG PACKET SIZE = %d\n", length);
404
[6341]405  byte blen[INTSIZE];
[5996]406
[6341]407  Converter::intToByteArray( length, blen, INTSIZE );
408
409  writeBytes(blen, INTSIZE);
[5996]410  writeBytes(data, length);
411}
412
413int NetworkSocket::readPacket( byte * data, int maxLength )
414{
[6139]415  PRINTF(5)("NetworkSocket::readPacket()\n");
[6341]416  if (incomingBufferLength<INTSIZE)
[5996]417  {
418    return 0;
419  }
420
[6341]421  int blen;
422  Converter::byteArrayToInt( incomingBuffer, &blen );
[5996]423
424  if (blen>maxLength)
425  {
426    PRINTF(1)("Buffersize is too small (%d) for packet (%d)\n", maxLength, blen);
427    return 0;
428  }
429
430  if (blen>incomingBufferLength)
431  {
432    return 0;
433  }
434
[6341]435  byte t[INTSIZE];
436  readBytes(t, INTSIZE);
[5996]437  int res = readBytes(data, blen);
438
439  if (res!=blen)
440    return -1;
441  else
442    return blen;
443
444}
445
446
Note: See TracBrowser for help on using the repository browser.