Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 5628 was 5628, checked in by rennerc, 18 years ago

network_unit_test.cc: added test for much data
network_socket: added delay if input buffer is full

File size: 6.7 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/**
32 * Default constructor
33 */
34NetworkSocket::NetworkSocket()
35{
36  /* set the class id for the base object */
37  this->setClassID(CL_NETWORK_SOCKET, "NetworkSocket");
38
39  tcpSocket = NULL;
40  bufferlength = 0;
41
42  mutex = SDL_CreateMutex();
43  socketmutex = SDL_CreateMutex();
44  terminateThread = false;
45
46  /* Init SDL_net */
47  //NOTE: do we need to call SDLNet_Init for all instances?
48  if(SDLNet_Init()==-1)
49  {
50    PRINTF(1)("SDLNet_Init: %s\n", SDLNet_GetError());
51    return;
52  }
53  else
54    PRINTF(5)("SDL_net initialized\n");
55
56  PRINTF(0)("NetworkSocket created\n");
57
58}
59
60/**
61 * Default destructor
62 */
63NetworkSocket::~ NetworkSocket( )
64{
65  /* Quit SDL_net */
66  // NOTE: what if other instances of NetworkSocket running?
67  SDLNet_Quit();
68  PRINTF(5)("SDL_net shutdown\n");
69
70  SDL_DestroyMutex(mutex);
71  SDL_DestroyMutex(socketmutex);
72}
73
74/**
75 * This function establishes a TCP/UDP connection to a given server (function argument).
76 * It is called by the NetworkStream. It creates a TCP/UDP socket for the connection.
77 * @param ip
78 * @param port
79 */
80void NetworkSocket::connectToServer(IPaddress ip, unsigned int port)
81{
82  //check if not already connected or listening
83  if (tcpSocket)
84  {
85    PRINTF(1)("NetworkSocket::listen: tcpSocket!=NULL! maybe you already called listen or connectToServer or did not call disconnectServer()!");
86  }
87
88  /* Connect to the host and port contained in ip using a TCP connection. */
89  tcpSocket = SDLNet_TCP_Open(&ip);
90  if(!tcpSocket)
91  {
92    PRINTF(1)("SDLNet_TCP_Open: %s\n", SDLNet_GetError());
93    return;
94  }
95
96  SDL_CreateThread(thread_read, (void*)this);
97}
98
99/**
100 * Tells the NetworkSocket to listen on a specific port for incoming connections.
101 * NetworkSocket::writeBytes(...) will have no effect until there is a valuable connection.
102 * @param port
103 */
104void NetworkSocket::listen(unsigned int port)
105{
106  //check if not already connected or listening
107  if (tcpSocket)
108  {
109    PRINTF(1)("NetworkSocket::listen: tcpSocket!=NULL! maybe you already called listen or connectToServer or did not call disconnectServer()!\n");
110    return;
111  }
112
113  IPaddress ip;
114
115  if (SDLNet_ResolveHost(&ip, NULL, port)==-1)
116  {
117    PRINTF(1)("SDLNet_ResolveHost: %s\n", SDLNet_GetError());
118    return;
119  }
120
121  tcpSocket = SDLNet_TCP_Open(&ip);
122
123  if (!tcpSocket)
124  {
125    PRINTF(1)("SDLNet_TCP_Open: %s\n", SDLNet_GetError());
126    return;
127  }
128
129  SDL_CreateThread(thread_listen, (void*)this);
130}
131
132/**
133 * DTears down a TCP/UDP connection.
134 */
135void NetworkSocket::disconnectServer( )
136{
137  terminateThread = true;
138  /* Close the connection */
139
140  SDL_mutexP(socketmutex);
141  SDLNet_TCP_Close(tcpSocket);
142  tcpSocket = NULL;
143  SDL_mutexV(socketmutex);
144
145}
146
147
148/**
149 * This function writes some bytes (data) to the network connection (if the connection is already
150 * estabilhed) otherwise it just does nothing (silently discarding the data). And writes some
151 * warnings
152 * @param data: pointer to the data to send
153 * @param length: n bytes to send
154 * @return the number successfully written bytes
155 */
156int NetworkSocket::writeBytes(byte * data, int length)
157{
158  SDL_mutexP(socketmutex);
159
160  if (!tcpSocket || data==NULL)
161    return 0;
162
163  int res = SDLNet_TCP_Send(tcpSocket, data, length);
164
165  SDL_mutexV(socketmutex);
166
167  if (res<length)
168    PRINTF(1)("SDLNet_TCP_Send: %s\n", SDLNet_GetError());
169
170  return res;
171}
172
173/**
174 * Reads in the bytes from the network interface and passes it to the NetworkStream.
175 * This function must internaly be implemented/connected as a thread, since the read
176 * functions of many network libraries are blocking an would therefore block the whole
177 * program.
178 * From outside, the thread shouldn't be accessible at all.
179 * @param data: pointer to memory, big enough to store length bytes
180 * @param length: n bytes to read
181 * @return the number successfully read bytes. -1 on error. may be less than length!
182 */
183int NetworkSocket::readBytes(byte * data, int length)
184{
185  if (data==NULL)
186    return 0;
187
188  int nbytes = (length<bufferlength) ? length : bufferlength;
189
190  // just in case ...
191  if (nbytes<0)
192    return -1;
193
194  if (nbytes==0)
195      return 0;
196
197  SDL_mutexP(mutex);
198
199  memcpy(data, buf, nbytes);
200
201  //important: use memmove because the memory areas may overlap
202  memmove(buf, buf+nbytes, bufferlength-nbytes);
203  bufferlength -= nbytes;
204
205  SDL_mutexV(mutex);
206
207  return nbytes;
208}
209
210/**
211 * used to create a thread to listen
212 * will call thrad_read when established connection
213 * @param data: pointer to NetwortSocket
214 */
215int NetworkSocket::thread_listen( void * data )
216{
217  NetworkSocket * self = (NetworkSocket*)data;
218  TCPsocket tempsocket;
219
220  tempsocket = SDLNet_TCP_Accept(self->tcpSocket);
221
222  SDL_mutexP(self->socketmutex);
223  SDLNet_TCP_Close(self->tcpSocket);
224  self->tcpSocket = NULL;
225
226  if (!tempsocket)
227  {
228    PRINTF(1)("SDLNet_TCP_Accept: %s\n", SDLNet_GetError());
229    SDL_mutexV(self->socketmutex);
230    return -1;
231  }
232
233  self->tcpSocket = tempsocket;
234
235  SDL_mutexV(self->socketmutex);
236
237  return thread_read(data);
238}
239
240/**
241 * used to create a thread to read from socket
242 * @param data: pointer to NetworkSocket
243 */
244int NetworkSocket::thread_read( void * data )
245{
246  int nbytesread = 0;
247  int nbytestoread = 0;
248  char buffer[_LOCAL_BUFFER_SIZE];
249  NetworkSocket * self = (NetworkSocket*)data;
250
251  while (!self->terminateThread)
252  {
253#define min(a,b) (a<b)?a:b
254    nbytestoread = min(_INCOMING_BUFFER_SIZE - self->bufferlength, _LOCAL_BUFFER_SIZE);
255
256    //if buffer is full
257    if (nbytestoread<=0)
258    {
259      SDL_Delay(_MSECONDS_SLEEP_FULL_BUFFER);
260      continue;
261    }
262
263    nbytesread = SDLNet_TCP_Recv(self->tcpSocket, buffer, nbytestoread);
264
265    SDL_mutexP(self->mutex);
266
267    if (nbytesread<=0)
268    {
269      PRINTF(1)("SDLNet_TCP_Recv: %s\n", SDLNet_GetError());
270
271      SDL_mutexP(self->socketmutex);
272
273      SDLNet_TCP_Close(self->tcpSocket);
274      self->tcpSocket = NULL;
275
276      SDL_mutexV(self->socketmutex);
277      SDL_mutexV(self->mutex);
278      return -1;
279    }
280
281    memcpy(self->buf+self->bufferlength, buffer, nbytesread);
282    self->bufferlength += nbytesread;
283
284    SDL_mutexV(self->mutex);
285  }
286
287  return 0;
288}
289
290
291
Note: See TracBrowser for help on using the repository browser.