Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 6222 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
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
23
24/* include your own header */
25#include "network_socket.h"
26
[5565]27/* header for debug output */
28#include "debug.h"
[5542]29
30/**
31 * Default constructor
32 */
33NetworkSocket::NetworkSocket()
[5565]34{
[5808]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
[5996]48NetworkSocket::NetworkSocket( TCPsocket sock )
49{
50  this->init();
51  this->tcpSocket = sock;
52
[6139]53  readThread = SDL_CreateThread(thread_read, (void*)this);
54  writeThread = SDL_CreateThread(thread_write, (void*)this);
[5996]55}
56
[5808]57void NetworkSocket::init()
58{
[5592]59  /* set the class id for the base object */
60  this->setClassID(CL_NETWORK_SOCKET, "NetworkSocket");
[5542]61
[5624]62  tcpSocket = NULL;
[5630]63  incomingBufferLength = 0;
64  outgoingBufferLength = 0;
[5624]65
[6139]66  readThread = NULL;
67  writeThread = NULL;
68
69
70  thread_write_running = false;
71  thread_read_running = false;
72
[5630]73  incomingBufferMutex = SDL_CreateMutex();
74  outgoingBufferMutex = SDL_CreateMutex();
[6139]75
76
[5630]77  socketMutex = SDL_CreateMutex();
[5624]78  terminateThread = false;
79
[5592]80  /* Init SDL_net */
[5624]81  //NOTE: do we need to call SDLNet_Init for all instances?
[5592]82  if(SDLNet_Init()==-1)
83  {
84    PRINTF(1)("SDLNet_Init: %s\n", SDLNet_GetError());
[5565]85    return;
[5592]86  }
87  else
88    PRINTF(5)("SDL_net initialized\n");
[5565]89
[5606]90  PRINTF(0)("NetworkSocket created\n");
91
[5565]92}
93
[5996]94
95
[5542]96/**
97 * Default destructor
98 */
[6139]99NetworkSocket::~NetworkSocket( )
[5542]100{
[6139]101  this->terminateThread = true;
[5592]102  /* Quit SDL_net */
[5624]103  // NOTE: what if other instances of NetworkSocket running?
[5592]104  SDLNet_Quit();
105  PRINTF(5)("SDL_net shutdown\n");
[5625]106
[5630]107  SDL_DestroyMutex(incomingBufferMutex);
108  SDL_DestroyMutex(outgoingBufferMutex);
109  SDL_DestroyMutex(socketMutex);
[6139]110  SDL_DestroyMutex(threadTerminationMutex);
[5542]111}
112
113/**
[5624]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 */
[5804]118void NetworkSocket::connectToServer(IPaddress ip)
[5542]119{
[5624]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  }
[5577]125
[5592]126  /* Connect to the host and port contained in ip using a TCP connection. */
127  tcpSocket = SDLNet_TCP_Open(&ip);
128  if(!tcpSocket)
129  {
[5577]130    PRINTF(1)("SDLNet_TCP_Open: %s\n", SDLNet_GetError());
131    return;
[5592]132  }
[5577]133
[6139]134  readThread = SDL_CreateThread(thread_read, (void*)this);
135  writeThread = SDL_CreateThread(thread_write, (void*)this);
[5542]136}
137
[5624]138
[5542]139/**
[5565]140 * DTears down a TCP/UDP connection.
[5542]141 */
142void NetworkSocket::disconnectServer( )
143{
[5624]144  terminateThread = true;
[5592]145  /* Close the connection */
[5625]146
[5630]147  SDL_mutexP(socketMutex);
[5592]148  SDLNet_TCP_Close(tcpSocket);
[5624]149  tcpSocket = NULL;
[5630]150  SDL_mutexV(socketMutex);
[5542]151}
152
[5624]153
[5542]154/**
[5624]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)
[5542]163{
[6139]164  PRINTF(5)("NetworkSocket::writeBytes()\n");
[5630]165#ifdef _USE_OUTGOING_BUFFER
[5625]166
[5630]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;
[5804]178
[5630]179  SDL_mutexV(outgoingBufferMutex);
180
[5805]181
[5630]182  return nbytes;
183#else
184  SDL_mutexP(socketMutex);
185
[5624]186  if (!tcpSocket || data==NULL)
187    return 0;
188
189  int res = SDLNet_TCP_Send(tcpSocket, data, length);
190
[5630]191  SDL_mutexV(socketMutex);
[5625]192
[5624]193  if (res<length)
194    PRINTF(1)("SDLNet_TCP_Send: %s\n", SDLNet_GetError());
[5628]195
196  return res;
[5630]197#endif
[5542]198}
199
[5624]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 */
[5614]210int NetworkSocket::readBytes(byte * data, int length)
[5542]211{
[6139]212  PRINTF(5)("NetworkSocket::readBytes()\n");
[5625]213  if (data==NULL)
[5624]214    return 0;
215
[5630]216  int nbytes = (length<incomingBufferLength) ? length : incomingBufferLength;
[5624]217
[5808]218
[5630]219  //printf("readBytes: nbytes = %d; length=%d; incomingBufferLength=%d\n", nbytes, length, incomingBufferLength);
220
[5624]221  // just in case ...
222  if (nbytes<0)
223    return -1;
224
225  if (nbytes==0)
226      return 0;
227
[5630]228  SDL_mutexP(incomingBufferMutex);
[5624]229
[5630]230  memcpy(data, incomingBuffer, nbytes);
[5624]231
232  //important: use memmove because the memory areas may overlap
[5630]233  memmove(incomingBuffer, incomingBuffer+nbytes, incomingBufferLength-nbytes);
234  incomingBufferLength -= nbytes;
[5624]235
[5630]236  SDL_mutexV(incomingBufferMutex);
[5624]237
238  return nbytes;
[5542]239}
[5624]240
241/**
[5725]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 */
[5729]248int NetworkSocket::readBlock(byte * data, int length)
[5725]249{
[5804]250  printf("NetworkSocket: got %i bytes, NetworkStream requested %i bytes\n", this->incomingBufferLength, length);
[5725]251  if (incomingBufferLength >= length)
252    return readBytes(data, length);
253  else return 0;
254}
255
[5624]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
[6139]268  self->thread_read_running = true;
269
[5624]270  while (!self->terminateThread)
271  {
272#define min(a,b) (a<b)?a:b
[5630]273    nbytestoread = min(_INCOMING_BUFFER_SIZE - self->incomingBufferLength, _LOCAL_BUFFER_SIZE);
274#undef min
[5624]275
[5628]276    //if buffer is full
[6139]277    if (nbytestoread<=0 || !self->tcpSocket)
[5628]278    {
279      SDL_Delay(_MSECONDS_SLEEP_FULL_BUFFER);
280      continue;
281    }
282
[5624]283    nbytesread = SDLNet_TCP_Recv(self->tcpSocket, buffer, nbytestoread);
284
[5630]285    SDL_mutexP(self->incomingBufferMutex);
[5624]286
287    if (nbytesread<=0)
288    {
[6139]289      if (nbytesread<0)
290        printf("SDLNet_TCP_Recv: %s\n", SDLNet_GetError());
[5625]291
[5630]292      SDL_mutexP(self->socketMutex);
[5625]293
[5624]294      SDLNet_TCP_Close(self->tcpSocket);
295      self->tcpSocket = NULL;
[5625]296
[5630]297      SDL_mutexV(self->socketMutex);
298      SDL_mutexV(self->incomingBufferMutex);
[6139]299      continue;
[5624]300    }
301
[5630]302    //printf("thread_read: nbytesread=%d\n", nbytesread);
[5624]303
[5630]304    memcpy(self->incomingBuffer+self->incomingBufferLength, buffer, nbytesread);
305    self->incomingBufferLength += nbytesread;
306
307    SDL_mutexV(self->incomingBufferMutex);
[5624]308  }
309
[6139]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");
[5624]325  return 0;
326}
327
[5630]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;
[5624]334
[6139]335  self->thread_write_running = true;
336
[5630]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
[5628]342
[5805]343//     printf("thread_write nbytes=%d listening=%d\n", nbytestowrite, (int)self->_isListening);
[5630]344
345    //if buffer is full
[6139]346    if (nbytestowrite<=0 || !self->tcpSocket)
[5630]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    {
[5737]366      printf("SDLNet_TCP_Recv: %s\n", SDLNet_GetError());
[5630]367
368      SDL_mutexP(self->socketMutex);
369
370      SDLNet_TCP_Close(self->tcpSocket);
371      self->tcpSocket = NULL;
372
373      SDL_mutexV(self->socketMutex);
[6139]374      continue;
[5630]375    }
376
377  }
378
[6139]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");
[5630]394  return 0;
395}
396
[5996]397bool NetworkSocket::writePacket( byte * data, int length )
398{
[6139]399  PRINTF(5)("NetworkSocket::writePacket()\n");
[5996]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{
[6139]414  PRINTF(5)("NetworkSocket::readPacket()\n");
[5996]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.