4
* 2001-January-28 Jason Rohrer
7
* 2001-January-29 Jason Rohrer
8
* Fixed an endian bug that was messing up the port numbers.
10
* 2002-October-13 Jason Rohrer
11
* Added support for timeout on connect.
12
* Fixed several windows compile bugs.
14
* 2002-December-2 Jason Rohrer
15
* Fixed resource leak when connection fails.
16
* Changed close calls to win32 closesocket calls.
18
* 2004-January-2 Jason Rohrer
19
* Fixed a thread safety issue with gethostbyname.
21
* 2004-January-4 Jason Rohrer
22
* Added use of network function locks.
24
* 2006-April-25 Jason Rohrer
25
* Added missing check for a NULL outTimedOut parameter.
27
* 2008-September-30 Jason Rohrer
28
* Added support for non-blocking connect.
33
#include "minorGems/network/SocketClient.h"
34
#include "minorGems/network/NetworkFunctionLocks.h"
35
#include "minorGems/system/MutexLock.h"
48
struct in_addr *nameToAddress( char *inAddress );
50
int timed_connect( int inSocketID,
51
struct sockaddr *inSocketAddress,
53
int inTimeoutInMilliseconds );
57
Socket *SocketClient::connectToServer( HostAddress *inAddress,
58
long inTimeoutInMilliseconds,
61
if( !Socket::isFrameworkInitialized() ) {
63
// try to init the framework
65
int error = Socket::initSocketFramework();
69
printf( "initializing network socket framework failed\n" );
74
unsigned long socketID = socket( AF_INET, SOCK_STREAM, 0 );
76
if( socketID == INVALID_SOCKET ) {
77
printf( "Creating socket failed.\n" );
85
//struct in_addr internet_address;
88
struct in_addr *internet_address =
89
nameToAddress( inAddress->mAddressString );
91
if( internet_address == NULL ) {
92
printf( "Host name lookup failed: " );
96
closesocket( socketID );
100
//hp = gethostbyname( inAddress->mAddressString );
101
//memcpy( &internet_address, *( hp->h_addr_list ), sizeof( struct in_addr ) );
103
sock.i.sin_family = AF_INET;
104
sock.i.sin_port = htons( inAddress->mPort );
105
sock.i.sin_addr = *internet_address;
110
if( inTimeoutInMilliseconds != -1 ) {
113
error = timed_connect( socketID, &sock.s, sizeof( struct sockaddr ),
114
inTimeoutInMilliseconds );
116
if( outTimedOut != NULL ) {
120
if( inTimeoutInMilliseconds == 0 ) {
121
// caller didn't want to wait at all
125
// treat timeout as error
130
*outTimedOut = false;
137
error = connect( socketID, &sock.s, sizeof( struct sockaddr ) );
141
delete internet_address;
145
//printf( "Connecting to host failed: " );
146
//inAddress->print();
149
closesocket( socketID );
153
// package into a Socket and return it
154
Socket *returnSocket = new Socket();
156
unsigned long *idSpace = new unsigned long[1];
157
idSpace[0] = socketID;
158
returnSocket->mNativeObjectPointer = (void *)idSpace;
162
returnSocket->setConnected( false );
171
/* Converts ascii text to in_addr struct. NULL is returned if the
172
address can not be found.
173
Result must be destroyed by caller.
174
Adapted from the Unix Socket FAQ */
175
struct in_addr *nameToAddress( char *inAddress ) {
176
struct hostent *host;
178
static struct in_addr saddr;
179
struct in_addr *copiedSaddr = new struct in_addr;
182
/* First try it as aaa.bbb.ccc.ddd. */
183
saddr.s_addr = inet_addr( inAddress );
184
if( saddr.s_addr != INADDR_NONE ) {
186
// copy to avoid returning pointer to stack
187
memcpy( copiedSaddr, &saddr, sizeof( struct in_addr ) );
191
// must keep this locked until we are done copying the in_addr out
192
// of the returned hostent
193
NetworkFunctionLocks::mGetHostByNameLock.lock();
195
char hostFound = false;
196
host = gethostbyname( inAddress );
201
sizeof( struct in_addr ) );
206
NetworkFunctionLocks::mGetHostByNameLock.unlock();
222
/* timed_read adapted from gnut, by Josh Pieper */
223
/* Josh Pieper, (c) 2000 */
224
/* This file is distributed under the GPL, see file COPYING for details */
226
// just like connect except that it times out after time secs
227
// returns -2 on timeout, otherwise same as connect
228
int timed_connect( int inSocketID,
229
struct sockaddr *inSocketAddress,
231
int inTimeoutInMilliseconds ) {
238
//g_debug(1,"entering sock=%i secs=%i\n",inSocketID,inTimeoutInSeconds);
240
//ret = fcntl( inSocketID, F_SETFL, O_NONBLOCK );
241
// use ioctlsocket on win32 instead of fcntl
242
// set to non-blocking mode
243
unsigned long onFlag = 1;
244
ret = ioctlsocket( inSocketID, FIONBIO, &onFlag );
247
//g_debug(5,"fcntl returned %i\n",ret);
253
ret = connect( inSocketID, inSocketAddress, inAddressLength );
254
//g_debug(5,"connect returned %i\n",ret);
257
//g_debug(0,"immediate connection!\n");
258
// wooah! immediate connection
261
// changed from what Josh originally returned (-2)
262
// immediate connection *can* happen sometimes, right?
263
// for example, when connecting to localhost...
267
// if (errno != EINPROGRESS) {
268
// perror("timed_connect, connect");
274
FD_SET( inSocketID, &fsr );
276
tv.tv_sec = inTimeoutInMilliseconds / 1000;
277
int remainder = inTimeoutInMilliseconds % 1000;
278
tv.tv_usec = remainder * 1000;
281
ret = select( inSocketID+1, NULL, &fsr, NULL, &tv );
282
//g_debug(5,"select returned %i\n",ret);
286
//g_debug(1,"timeout\n");
287
//fcntl( inSocketID, F_SETFL, 0 );
288
unsigned long offFlag = 0;
289
ret = ioctlsocket( inSocketID, FIONBIO, &offFlag );
295
ret = getsockopt( inSocketID, SOL_SOCKET, SO_ERROR, (char*)( &val ), &len );
296
//g_debug(5,"getsockopt returned %i val=%i\n",ret,val);
299
//g_debug(1,"getsockopt returned: %i\n",ret);
304
//g_debug(3,"returning failure!\n");
308
//ret = fcntl( inSocketID, F_SETFL, 0 );
309
// use ioctlsocket on win32 instead of fcntl
310
// set back to blocking mode
311
unsigned long offFlag = 0;
312
ret = ioctlsocket( inSocketID, FIONBIO, &offFlag );
315
//g_debug(1,"fcntl: %i\n",ret);
317
//g_debug(3,"returning success val=%i\n",val);