Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 6026 was 5996, checked in by patrick, 19 years ago

orxonox/trunk: merged network branche into trunk with command svn merge -r 5824:HEAD

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