~ubuntu-branches/ubuntu/precise/primrose/precise

« back to all changes in this revision

Viewing changes to minorGems/network/win32/SocketClientWin32.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Paul Wise
  • Date: 2009-04-06 19:26:56 UTC
  • Revision ID: james.westby@ubuntu.com-20090406192656-cri7503gebyvfl8t
Tags: upstream-5+dfsg1
ImportĀ upstreamĀ versionĀ 5+dfsg1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Modification History
 
3
 *
 
4
 * 2001-January-28              Jason Rohrer
 
5
 * Created. 
 
6
 *
 
7
 * 2001-January-29              Jason Rohrer
 
8
 * Fixed an endian bug that was messing up the port numbers.  
 
9
 *
 
10
 * 2002-October-13   Jason Rohrer
 
11
 * Added support for timeout on connect.
 
12
 * Fixed several windows compile bugs.
 
13
 *
 
14
 * 2002-December-2   Jason Rohrer
 
15
 * Fixed resource leak when connection fails.
 
16
 * Changed close calls to win32 closesocket calls.
 
17
 *
 
18
 * 2004-January-2   Jason Rohrer
 
19
 * Fixed a thread safety issue with gethostbyname.
 
20
 *
 
21
 * 2004-January-4   Jason Rohrer
 
22
 * Added use of network function locks.
 
23
 *
 
24
 * 2006-April-25   Jason Rohrer
 
25
 * Added missing check for a NULL outTimedOut parameter.
 
26
 *
 
27
 * 2008-September-30   Jason Rohrer
 
28
 * Added support for non-blocking connect.
 
29
 */
 
30
 
 
31
 
 
32
 
 
33
#include "minorGems/network/SocketClient.h"
 
34
#include "minorGems/network/NetworkFunctionLocks.h"
 
35
#include "minorGems/system/MutexLock.h"
 
36
 
 
37
#include <Winsock.h>
 
38
#include <stdlib.h>
 
39
#include <stdio.h>
 
40
 
 
41
#include <fcntl.h>
 
42
#include <time.h>
 
43
 
 
44
 
 
45
 
 
46
 
 
47
// prototypes
 
48
struct in_addr *nameToAddress( char *inAddress ); 
 
49
 
 
50
int timed_connect( int inSocketID,
 
51
                   struct sockaddr *inSocketAddress,
 
52
                   int inAddressLength,
 
53
                   int inTimeoutInMilliseconds );
 
54
 
 
55
 
 
56
 
 
57
Socket *SocketClient::connectToServer( HostAddress *inAddress,
 
58
                                       long inTimeoutInMilliseconds,
 
59
                                       char *outTimedOut ) {
 
60
 
 
61
        if( !Socket::isFrameworkInitialized() ) {
 
62
                
 
63
                // try to init the framework
 
64
                
 
65
                int error = Socket::initSocketFramework();
 
66
                
 
67
                if( error == -1 ) {
 
68
                        
 
69
                        printf( "initializing network socket framework failed\n" );
 
70
                        return NULL;
 
71
                        }
 
72
                }
 
73
 
 
74
        unsigned long socketID = socket( AF_INET, SOCK_STREAM, 0 );     
 
75
 
 
76
        if( socketID == INVALID_SOCKET ) {
 
77
                printf( "Creating socket failed.\n" );
 
78
                return NULL;
 
79
                }
 
80
 
 
81
        union sock {
 
82
                struct  sockaddr s;
 
83
                struct  sockaddr_in i;
 
84
                } sock;
 
85
        //struct in_addr internet_address;
 
86
        //struct hostent *hp;
 
87
 
 
88
        struct in_addr *internet_address = 
 
89
                nameToAddress( inAddress->mAddressString );
 
90
 
 
91
        if( internet_address == NULL ) {
 
92
                printf( "Host name lookup failed:  " );
 
93
                inAddress->print();
 
94
                printf( "\n" );
 
95
 
 
96
        closesocket( socketID );
 
97
        return NULL;
 
98
                }
 
99
 
 
100
        //hp = gethostbyname( inAddress->mAddressString );
 
101
        //memcpy( &internet_address, *( hp->h_addr_list ), sizeof( struct in_addr ) );
 
102
        
 
103
        sock.i.sin_family = AF_INET;
 
104
        sock.i.sin_port = htons( inAddress->mPort );
 
105
        sock.i.sin_addr = *internet_address;
 
106
 
 
107
 
 
108
    int error;
 
109
 
 
110
    if( inTimeoutInMilliseconds != -1 ) {
 
111
        // use timeout
 
112
        
 
113
        error = timed_connect( socketID, &sock.s, sizeof( struct sockaddr ),
 
114
                               inTimeoutInMilliseconds );
 
115
 
 
116
        if( outTimedOut != NULL ) {
 
117
            if( error == -2 ) {
 
118
                *outTimedOut = true;
 
119
                
 
120
                if( inTimeoutInMilliseconds == 0 ) {
 
121
                    // caller didn't want to wait at all
 
122
                    error = 0;
 
123
                    }
 
124
                else {
 
125
                    // treat timeout as error
 
126
                    error = -1;
 
127
                    }
 
128
                }
 
129
            else {
 
130
                *outTimedOut = false;
 
131
                }
 
132
            }
 
133
        }
 
134
    else {
 
135
        // don't use timeout
 
136
        
 
137
        error = connect( socketID, &sock.s, sizeof( struct sockaddr ) );
 
138
        }
 
139
 
 
140
 
 
141
    delete internet_address;
 
142
    
 
143
 
 
144
    if( error == -1 ) {
 
145
                //printf( "Connecting to host failed:  " );
 
146
                //inAddress->print();
 
147
                //printf( "\n" );
 
148
 
 
149
        closesocket( socketID );
 
150
                return NULL;
 
151
                }
 
152
        
 
153
        // package into a Socket and return it
 
154
        Socket *returnSocket = new Socket();
 
155
        
 
156
        unsigned long *idSpace = new unsigned long[1];
 
157
        idSpace[0] = socketID;
 
158
        returnSocket->mNativeObjectPointer = (void *)idSpace;
 
159
        
 
160
    if( *outTimedOut ) {
 
161
        // not connected yet
 
162
        returnSocket->setConnected( false );
 
163
        }
 
164
 
 
165
        
 
166
        return returnSocket;
 
167
        }
 
168
 
 
169
 
 
170
 
 
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;
 
177
 
 
178
    static struct in_addr saddr;
 
179
    struct in_addr *copiedSaddr = new struct in_addr;
 
180
    
 
181
    
 
182
        /* First try it as aaa.bbb.ccc.ddd. */
 
183
        saddr.s_addr = inet_addr( inAddress );
 
184
        if( saddr.s_addr != INADDR_NONE ) {
 
185
 
 
186
        // copy to avoid returning pointer to stack
 
187
        memcpy( copiedSaddr, &saddr, sizeof( struct in_addr ) );
 
188
        return copiedSaddr;
 
189
                }
 
190
 
 
191
    // must keep this locked until we are done copying the in_addr out
 
192
    // of the returned hostent
 
193
    NetworkFunctionLocks::mGetHostByNameLock.lock();
 
194
 
 
195
    char hostFound = false;
 
196
    host = gethostbyname( inAddress );
 
197
    if( host != NULL ) {
 
198
        
 
199
        memcpy( copiedSaddr,
 
200
                *host->h_addr_list,
 
201
                sizeof( struct in_addr ) );
 
202
        
 
203
        hostFound = true;
 
204
        }
 
205
 
 
206
    NetworkFunctionLocks::mGetHostByNameLock.unlock();
 
207
 
 
208
 
 
209
    
 
210
    if( hostFound ) {
 
211
        return copiedSaddr;
 
212
        }
 
213
    else {
 
214
        delete copiedSaddr;
 
215
        }
 
216
    
 
217
        return NULL;
 
218
        }
 
219
 
 
220
 
 
221
 
 
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 */
 
225
 
 
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,
 
230
                   int inAddressLength,
 
231
                   int inTimeoutInMilliseconds ) {
 
232
        int ret;
 
233
        fd_set fsr;
 
234
        struct timeval tv;
 
235
        int val;
 
236
    int len;
 
237
    
 
238
        //g_debug(1,"entering sock=%i secs=%i\n",inSocketID,inTimeoutInSeconds);
 
239
        
 
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 );
 
245
 
 
246
    
 
247
    //g_debug(5,"fcntl returned %i\n",ret);
 
248
        
 
249
        if( ret < 0 ) {
 
250
        return ret;
 
251
        }
 
252
    
 
253
        ret = connect( inSocketID, inSocketAddress, inAddressLength );
 
254
        //g_debug(5,"connect returned %i\n",ret);
 
255
        
 
256
        if( ret == 0 ) {
 
257
                //g_debug(0,"immediate connection!\n");
 
258
                // wooah!  immediate connection
 
259
                // return -2;
 
260
 
 
261
        // changed from what Josh originally returned (-2)
 
262
        // immediate connection *can* happen sometimes, right?
 
263
        // for example, when connecting to localhost...
 
264
        return 0;
 
265
        }
 
266
        
 
267
//      if (errno != EINPROGRESS) {
 
268
//              perror("timed_connect, connect");
 
269
//              return ret;
 
270
//      }
 
271
        
 
272
 
 
273
        FD_ZERO( &fsr );
 
274
        FD_SET( inSocketID, &fsr );
 
275
 
 
276
    tv.tv_sec = inTimeoutInMilliseconds / 1000;
 
277
        int remainder = inTimeoutInMilliseconds % 1000;
 
278
        tv.tv_usec = remainder * 1000;
 
279
    
 
280
 
 
281
        ret = select( inSocketID+1, NULL, &fsr, NULL, &tv );
 
282
        //g_debug(5,"select returned %i\n",ret);
 
283
 
 
284
        if( ret==0 ) {
 
285
                // timeout
 
286
                //g_debug(1,"timeout\n");
 
287
                //fcntl( inSocketID, F_SETFL, 0 );
 
288
                unsigned long offFlag = 0;
 
289
        ret = ioctlsocket( inSocketID, FIONBIO, &offFlag );
 
290
                
 
291
                return -2;
 
292
        }
 
293
 
 
294
        len = 4;
 
295
        ret = getsockopt( inSocketID, SOL_SOCKET, SO_ERROR, (char*)( &val ), &len );
 
296
        //g_debug(5,"getsockopt returned %i val=%i\n",ret,val);
 
297
        
 
298
        if( ret < 0 ) {
 
299
                //g_debug(1,"getsockopt returned: %i\n",ret);
 
300
                return ret;
 
301
        }
 
302
 
 
303
        if (val!=0) {
 
304
                //g_debug(3,"returning failure!\n");
 
305
                return -1;
 
306
        }
 
307
        
 
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 );
 
313
    
 
314
    
 
315
        //g_debug(1,"fcntl: %i\n",ret);
 
316
        
 
317
        //g_debug(3,"returning success val=%i\n",val);
 
318
        return 0;
 
319
    }