PEBL 2.2
Psychology Experiment Building Language - Cross-platform psychological experiment development system
sdl/PlatformNetwork.cpp
Go to the documentation of this file.
1//* -*- mode:C++; tab-width:4; c-basic-offset:4; indent-tabs-mode:nil -*- */
3// Name: src/platforms/sdl/PlatformNetwork.cpp
4// Purpose: Class for handling network communication
5// Author: Shane T. Mueller, Ph.D.
6// Copyright: (c) 2006-2026 Shane T. Mueller <smueller@obereed.net>
7// License: GPL 2
8//
9//
10//
11// This file is part of the PEBL project.
12//
13// PEBL is free software; you can redistribute it and/or modify
14// it under the terms of the GNU General Public License as published by
15// the Free Software Foundation; either version 2 of the License, or
16// (at your option) any later version.
17//
18// PEBL is distributed in the hope that it will be useful,
19// but WITHOUT ANY WARRANTY; without even the implied warranty of
20// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21// GNU General Public License for more details.
22//
23// You should have received a copy of the GNU General Public License
24// along with PEBL; if not, write to the Free Software
25// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27#include "PlatformNetwork.h"
28#include "../../devices/PNetwork.h"
29#include "../../utility/PError.h"
30#include "../../libs/PEBLEnvironment.h"
31
32#ifdef PEBL_NETWORK
33
34#ifdef PEBL_OSX
35#include "SDL.h"
36#include "SDL_net.h"
37#else
38#include "SDL.h"
39#include "SDL_net.h"
40#endif
41
42
43#include <cstring> //for strdup
44#include <string>
45#include <stdlib.h>
46
47using std::string;
48using std::cerr;
49using std::endl;
50
51
53{
54 //mAddress is SDL-specific, so it is
55 //not exposed to users.
56
57 mAddress = new IPaddress;
58 mAddress->host=0;
59 mAddress->port=0;
60 mSocket = NULL;
61 mMyAddress = NULL;
62 mListener = NULL;
63}
64
66{
67 if(mAddress)
68 delete mAddress;
69 SDLNet_Quit();
70}
71
72
73void PlatformNetwork::Init()
74{
75 std::cerr << "Initializing network\n";
76 int val = SDLNet_Init();
77
78 if(val==0)
79 {
80 std::cerr << "Network System Initialized\n";
81
82 }
83 else
84 {
85
86 PError::SignalFatalError("Network System Failed to Initialize.");
87 }
88
89}
90
91void PlatformNetwork::SetHostIP(unsigned int ip)
92{
93
94 PNetwork::SetHostIP(ip); //mHost = ip;
95 mAddress->host=ip;
96}
97
98void PlatformNetwork::SetPort(unsigned int port)
99{
100
101 //SDL swaps the byte order in the SDL_Net library for some reason.
102 //So we need to pre-swap to ensure we get the right port.
103
104 //This should swap the byte order
105 //PNetwork::SetPort(SDL_SwapBE16(port));
106 PNetwork::SetPort((port));
107 mAddress->port = SDL_SwapBE16(mPort);
108
109 //std::cerr << "Port: " << port <<"|"<<mPort << "|"<<mAddress->port<< std::endl;
110 //std::cerr << "tmp: " <<tmp << std::endl;
111
112}
113
114
115Variant PlatformNetwork::GetMyIPAddress()
116{
117 if(mMyAddress)
118 return ConvertAddress(mMyAddress);
119 else
120 {
121 mMyAddress = new IPaddress;
122 SDLNet_ResolveHost(mMyAddress,NULL,mAddress->port);
123 return ConvertAddress(mMyAddress);
124 }
125}
126
127Variant PlatformNetwork::GetIPAddress()
128{
129
130 //This will get the IP address that was connected to you,
131 //assuming you are a host.
132 if(mAddress==NULL)
133 return "<UNKNOWN ADDRESS>";//SetHostIP(SDLNet_TCP_GetPeerAddress(mSocket));
134 return ConvertAddress(mAddress);
135}
136
137//This resolves the IP currently stored in mAddress
138void PlatformNetwork::SetHostName(std::string hostname)
139{
140
141 PNetwork::SetHostName(hostname);
142
143 //This will use hostname to obtain mAddress, an IPaddress.
144 SDLNet_ResolveHost(mAddress,
145 mHostName.c_str(),
146 mAddress->port);
147
148 //std::cout<< "Host address from name [" << mAddress->host << "]"<< std::endl;
149}
150
151
152//This gets the IP address of the other side of the connection.
153
154
156{
157 Uint32 host = address->host;
159 return v;
160}
161
162// This opens a connection to some host that is listening for it.
163//
164void PlatformNetwork::Open()
165{
166
167 if(mAddress->host == 0)
168 PError::SignalFatalError("Trying to open connection to unspecified host");
169
170 mSocket = SDLNet_TCP_Open(mAddress);
171
172
173 if(!mSocket)
174 {
175 // PError::SignalWarning("Unable to establish connection to " + mHostName);
176 PNetwork::SetOpen(false);
177 }
178 else
179 {
180 PNetwork::SetOpen(true);
181 }
182}
183
184// This listens for a connection.
185//
186bool PlatformNetwork::CheckForConnection()
187{
188
189 //First, create the socket to listen on:
190
191 // IPaddress * tmpAddress = new IPaddress;
192 // tmpAddress->host = INADDR_ANY;
193 // tmpAddress->port = SDL_SwapBE16(mPort);
194
195
196 //std::cerr << "unable" << tmpAddress->port << endl;
197 //TCPsocket listener = SDLNet_TCP_Open(tmpAddress);
198
199 //an mListener socket already needs to have been opened.
200 if(!mListener)
201 PError::SignalFatalError(Variant("Unable to listen for connection in PlatformNetwork::CheckForConnection on port:") + Variant((int)mPort) );
202
203 //If we haven't opened the socket yet, do so now:
204
205 if(mSocket == NULL)
206 mSocket = SDLNet_TCP_Accept(mListener);
207
208 if(mSocket)
209 PNetwork::SetOpen(true);
210
211
212 // if(!mIsOpen)
213 //Close the listener, because we won't need it again the way we operate.
214 //SDLNet_TCP_Close(mListener);
215
216
217 // delete tmpAddress;
218 return mIsOpen;
219}
220
221
222
223bool PlatformNetwork::CreateListener()
224{
225
226 //First, create the socket to listen on:
227
228 IPaddress * tmpAddress = new IPaddress;
229 tmpAddress->host = INADDR_ANY;
230 tmpAddress->port = SDL_SwapBE16(mPort);
231
232
233 // std::cerr << "unable" << tmpAddress->port << endl;
234 mListener = SDLNet_TCP_Open(tmpAddress);
235 if(!mListener)
236 PError::SignalFatalError("Unable to create listener Socket." );
237
238 return true;
239}
240
241// This requires a listener socket to have been opened.
242//
243bool PlatformNetwork::Accept(int mstimeout)
244{
245
246 if(mListener==NULL)
247 {
248 PError::SignalFatalError("Trying to accept a connection on a network port that has not been opened.");
249 }
250 int now = SDL_GetTicks();
251 int end = now + mstimeout;
252 //This doesn't work too well. It should have a timeout.
253 while(mSocket == NULL & SDL_GetTicks()<end )
254 {
255 mSocket = SDLNet_TCP_Accept(mListener);
256 PEBLEnvironment::myTimer.Sleep(1); // Wait to avoid burning CPU
257 }
258
259 //cout << "opened socket\n";
260
261 // if(mAddress)
262 // delete mAddress;
263 //mAddress = SDLNet_TCP_GetPeerAddress(mSocket);
264
265 //Close the 'listening' socket.
266 SDLNet_TCP_Close(mListener);
267
268 if(mSocket==NULL)
269 {
270 PNetwork::SetOpen(false);
271 }
272 else
273 {
274 PNetwork::SetOpen(true);
275 }
276 return mSocket!=NULL;
277}
278
279
280// This is an all-on-one open-socket-listen-connect.
281// One might prefer a two-step process giving a bit more
282// control.
283
284bool PlatformNetwork::Accept()
285{
286
287 //First, create the socket to listen on:
288
289 IPaddress * tmpAddress = new IPaddress;
290 tmpAddress->host = INADDR_ANY;
291 tmpAddress->port = SDL_SwapBE16(mPort);
292
293
294 // std::cerr << "unable" << tmpAddress->port << endl;
295 TCPsocket listener = SDLNet_TCP_Open(tmpAddress);
296 if(!listener)
297 PError::SignalFatalError("Unable to listen for connection 2." );
298
299
300
301 //This doesn't work too well; maybe it should have an optional timeout?
302 while(mSocket == NULL)
303 {
304 mSocket = SDLNet_TCP_Accept(listener);
305 PEBLEnvironment::myTimer.Sleep(1); // Wait to avoid burning CPU
306 }
307
308 //cout << "opened socket\n";
309
310 // if(mAddress)
311 // delete mAddress;
312 //mAddress = SDLNet_TCP_GetPeerAddress(mSocket);
313
314 //Close the 'listening' socket.
315 SDLNet_TCP_Close(listener);
316 delete tmpAddress;
317 if(mSocket==NULL)
318 {
319 PNetwork::SetOpen(false);
320 }
321 else
322 {
323 PNetwork::SetOpen(true);
324 }
325 return mSocket!=NULL;
326}
327
328
329void PlatformNetwork::Close()
330{
331 if(mSocket)
332 SDLNet_TCP_Close(mSocket);
333 mSocket = NULL;
334 PNetwork::SetOpen(false);
335}
336
337
338bool PlatformNetwork::SendString(std::string data)
339{
340
341 char* buffer = NULL;
342 if(mIsOpen)
343 {
344
345 buffer = strdup(data.c_str());
346 unsigned long int sent = SDLNet_TCP_Send(mSocket, buffer,
347 (int)(data.length()));
348
349
350 if(sent != (int)data.length())
351 {
352 std::cerr << "Tried to send: " << data.length() << std::endl;
353 std::cerr << "Succeeded at: " << sent << std::endl;
354 PError::SignalWarning("Error sending data to " + mHostName + ". Not all data sent. Retry send");
355 free(buffer);
356 return false;
357 }
358 }else{
359 PError::SignalFatalError("Trying to send data without an open connection.");
360 return false;
361 }
362
363 free(buffer);
364 return true;
365}
366
367
368
369bool PlatformNetwork::SendByte(int byte)
370{
371
372 if(mIsOpen)
373 {
374
375 int sent = SDLNet_TCP_Send(mSocket, &byte,1);
376 if(sent != 1)
377 {
378 PError::SignalWarning("Error sending data to " + mHostName + ". Entire Message Not Sent.");
379 return 0;
380 }
381 }else{
382 PError::SignalFatalError("Trying to send data without an open connection.");
383 }
384 return true;
385}
386
387std::string PlatformNetwork::Receive(int length)
388{
389 char * message = NULL;
390 if(mIsOpen)
391 {
392 message = new char[length+1];
393 int pos = 0;
394 while(pos<length)
395 {
396
397 int result = SDLNet_TCP_Recv(mSocket,message+pos,length);
398 //cout << "length: " << length <<"|" << pos << " <<<< " << result << endl;
399
400 if(result == -1)
401 {
402 PError::SignalFatalError("Error receiving data from " + mHostName + ".");
403 }
404 else if(result == 0)
405 {
406 PError::SignalFatalError("Error receiving data from " + mHostName + ". Connection Closed by peer.");
407 }else{
408
409 pos = pos + result;
410 }
411 }
412 //Put a null char at the end.
413 message[length] = '\0';
414 }else{
415 PError::SignalFatalError("Trying to receive data without an open connection.");
416 }
417
418 //Make a copy and return the message.
419 std::string ret = std::string(message);
420 // free(message); tHanks to Martin Strunz
421 delete [] message;
422 return ret;
423}
424
425
426std::ostream& PlatformNetwork::SendToStream(std::ostream& out)const
427{
428 out << "<Network Connection: " << mHostName << ">";
429 return out;
430}
431
432#endif
#define NULL
Definition BinReloc.cpp:317
bool mIsOpen
Definition PNetwork.h:77
virtual void SetHostIP(unsigned int host)
Definition PNetwork.cpp:81
virtual void SetOpen(bool open)
Definition PNetwork.cpp:91
std::string mHostName
Definition PNetwork.h:73
unsigned int mPort
Definition PNetwork.h:75
virtual Variant ConvertAddress(unsigned long int address)
Definition PNetwork.cpp:57
virtual void SetHostName(std::string hostname)
Definition PNetwork.cpp:97
virtual void SetPort(unsigned int port)
Definition PNetwork.cpp:108
virtual std::ostream & SendToStream(std::ostream &out) const
virtual void Sleep(unsigned long int msecs)
PlatformTimer myTimer
void SignalWarning(const std::string &message)
Definition PError.cpp:119
void SignalFatalError(const std::string &message)