1 | /* Copyright (c) 2001, Stanford University
|
---|
2 | * All rights reserved
|
---|
3 | *
|
---|
4 | * See the file LICENSE.txt for information on redistributing this software.
|
---|
5 | */
|
---|
6 |
|
---|
7 | #ifdef WINDOWS
|
---|
8 | #define WIN32_LEAN_AND_MEAN
|
---|
9 | #pragma warning( push, 3 )
|
---|
10 | #include <winsock2.h>
|
---|
11 | #include <ws2tcpip.h> /* for ipv6 */
|
---|
12 | #include <time.h>
|
---|
13 | #pragma warning( pop )
|
---|
14 | #pragma warning( disable : 4514 )
|
---|
15 | #pragma warning( disable : 4127 )
|
---|
16 | # ifndef VBOX
|
---|
17 | typedef int ssize_t;
|
---|
18 | # endif
|
---|
19 | #define write(a,b,c) send(a,b,c,0)
|
---|
20 | #else
|
---|
21 | #include <sys/types.h>
|
---|
22 | #if defined(OSF1)
|
---|
23 | typedef int socklen_t;
|
---|
24 | #endif
|
---|
25 | #include <sys/socket.h>
|
---|
26 | #include <sys/time.h>
|
---|
27 | #include <sys/ioctl.h>
|
---|
28 | #ifdef LINUX
|
---|
29 | #define IP_MTU 14
|
---|
30 | #endif
|
---|
31 | #include <netinet/in.h>
|
---|
32 | #if !defined(IRIX) /* ip6.h might not be present on other unix variants either */
|
---|
33 | #include <netinet/ip6.h>
|
---|
34 | #endif
|
---|
35 | #include <netinet/udp.h>
|
---|
36 | #ifndef DARWIN
|
---|
37 | #include <netinet/tcp.h>
|
---|
38 | #endif
|
---|
39 | #include <arpa/inet.h>
|
---|
40 | #include <netdb.h>
|
---|
41 | #include <unistd.h>
|
---|
42 | #endif
|
---|
43 |
|
---|
44 | #include <limits.h>
|
---|
45 | #include <stdlib.h>
|
---|
46 | #include <stdio.h>
|
---|
47 | #include <errno.h>
|
---|
48 | #include <signal.h>
|
---|
49 | #include <string.h>
|
---|
50 | #ifdef AIX
|
---|
51 | #include <strings.h>
|
---|
52 | #endif
|
---|
53 |
|
---|
54 | #include "cr_error.h"
|
---|
55 | #include "cr_mem.h"
|
---|
56 | #include "cr_string.h"
|
---|
57 | #include "cr_bufpool.h"
|
---|
58 | #include "cr_net.h"
|
---|
59 | #include "cr_endian.h"
|
---|
60 | #include "cr_threads.h"
|
---|
61 | #include "net_internals.h"
|
---|
62 |
|
---|
63 | #ifdef ADDRINFO
|
---|
64 | #define PF PF_UNSPEC
|
---|
65 | #endif
|
---|
66 |
|
---|
67 | #ifndef MSG_TRUNC
|
---|
68 | #define MSG_TRUNC 0
|
---|
69 | #endif
|
---|
70 |
|
---|
71 | #ifdef IRIX
|
---|
72 | /* IRIX defines this token, but appears to be missing the related types
|
---|
73 | * and functions. Turn it off.
|
---|
74 | */
|
---|
75 | #undef AF_INET6
|
---|
76 | #endif
|
---|
77 |
|
---|
78 | #if defined( WINDOWS ) || defined( IRIX ) || defined( IRIX64 )
|
---|
79 | typedef int socklen_t;
|
---|
80 | #endif
|
---|
81 |
|
---|
82 | static void
|
---|
83 | crUDPIPWriteExact( CRConnection *conn, const void *buf, unsigned int len )
|
---|
84 | {
|
---|
85 | int retval;
|
---|
86 | if ( len > conn->mtu + sizeof(conn->seq) )
|
---|
87 | {
|
---|
88 | crWarning( "crUDPIPWriteExact(%d): too big a packet for mtu %d, dropping !", len, (int)(conn->mtu + sizeof(conn->seq)) );
|
---|
89 | return;
|
---|
90 | }
|
---|
91 | retval = sendto( conn->udp_socket, buf, len, 0,
|
---|
92 | (struct sockaddr *) &(conn->remoteaddr), sizeof(conn->remoteaddr));
|
---|
93 | if ( retval <= 0 )
|
---|
94 | {
|
---|
95 | int err = crTCPIPErrno( );
|
---|
96 | crWarning( "crUDPIPWriteExact(%d): %s", len, crTCPIPErrorString( err ) );
|
---|
97 | #ifdef LINUX
|
---|
98 | if ( err == EMSGSIZE )
|
---|
99 | {
|
---|
100 | int opt;
|
---|
101 | socklen_t leno = sizeof(opt);
|
---|
102 | crDebug( "Too big a UDP packet(%d), looking at new MTU...", len );
|
---|
103 | if ( getsockopt( conn->udp_socket, SOL_IP, IP_MTU_DISCOVER, &opt, &leno) == -1)
|
---|
104 | {
|
---|
105 | err = crTCPIPErrno( );
|
---|
106 | crWarning( "Couldn't determine whether PMTU discovery is used : %s", crTCPIPErrorString( err ) );
|
---|
107 | return;
|
---|
108 | }
|
---|
109 | if ( leno != sizeof(opt) )
|
---|
110 | {
|
---|
111 | crWarning( "Unexpected length %d for PMTU_DISCOVERY option length", leno );
|
---|
112 | return;
|
---|
113 | }
|
---|
114 | if ( opt == IP_PMTUDISC_DONT )
|
---|
115 | {
|
---|
116 | crWarning( "Uh, PMTU discovery isn't enabled ?!" );
|
---|
117 | return;
|
---|
118 | }
|
---|
119 | if ( getsockopt( conn->udp_socket, SOL_IP, IP_MTU, &opt, &leno) == -1 )
|
---|
120 | {
|
---|
121 | err = crTCPIPErrno( );
|
---|
122 | crWarning( "Couldn't determine the MTU : %s", crTCPIPErrorString( err ) );
|
---|
123 | return;
|
---|
124 | }
|
---|
125 | if ( leno != sizeof(opt) )
|
---|
126 | {
|
---|
127 | crWarning( "Unexpected length %d for MTU option length", leno );
|
---|
128 | return;
|
---|
129 | }
|
---|
130 | opt -= sizeof(conn->seq) + sizeof(struct udphdr) + sizeof(struct ip6_hdr);
|
---|
131 | if (opt >= (int) conn->mtu)
|
---|
132 | {
|
---|
133 | crWarning( "But MTU discovery is still bigger ! Narrowing it by hand to %d", conn->mtu = (conn->mtu * 2 / 3) & ~0x3 );
|
---|
134 | }
|
---|
135 | else
|
---|
136 | {
|
---|
137 | crDebug( "new MTU is %d", opt );
|
---|
138 | conn->mtu = opt & ~0x3;
|
---|
139 | }
|
---|
140 | }
|
---|
141 | #endif
|
---|
142 | }
|
---|
143 | }
|
---|
144 |
|
---|
145 | static void
|
---|
146 | crUDPTCPIPAccept( CRConnection *conn, const char *hostname, unsigned short port )
|
---|
147 | {
|
---|
148 | int err;
|
---|
149 | socklen_t addr_length;
|
---|
150 | #ifndef ADDRINFO
|
---|
151 | struct sockaddr addr;
|
---|
152 | struct sockaddr_in udpaddr;
|
---|
153 | #else
|
---|
154 | struct sockaddr_storage addr;
|
---|
155 | struct addrinfo *res,*cur;
|
---|
156 | struct addrinfo hints;
|
---|
157 | #endif
|
---|
158 |
|
---|
159 | crTCPIPAccept( conn, hostname, port );
|
---|
160 |
|
---|
161 | #ifndef ADDRINFO
|
---|
162 | conn->udp_socket = socket( AF_INET, SOCK_DGRAM, 0 );
|
---|
163 | if ( conn->udp_socket >= 0 )
|
---|
164 | {
|
---|
165 | memset(&udpaddr, 0, sizeof(udpaddr));
|
---|
166 | udpaddr.sin_family = AF_INET;
|
---|
167 | udpaddr.sin_addr.s_addr = INADDR_ANY;
|
---|
168 | udpaddr.sin_port = htons(0);
|
---|
169 | if ( bind( conn->udp_socket, (struct sockaddr *) &udpaddr, sizeof(udpaddr) ) )
|
---|
170 | {
|
---|
171 | err = crTCPIPErrno( );
|
---|
172 | crWarning( "Couldn't bind socket: %s", crTCPIPErrorString( err ) );
|
---|
173 | crCloseSocket( conn->udp_socket );
|
---|
174 | conn->udp_socket = -1;
|
---|
175 | }
|
---|
176 | }
|
---|
177 | #else
|
---|
178 | memset(&hints, 0, sizeof(hints));
|
---|
179 | hints.ai_flags = AI_PASSIVE;
|
---|
180 | hints.ai_family = PF;
|
---|
181 | hints.ai_socktype = SOCK_DGRAM;
|
---|
182 |
|
---|
183 | err = getaddrinfo( NULL, "0", &hints, &res);
|
---|
184 | if ( err )
|
---|
185 | crError( "Couldn't find local UDP port: %s", gai_strerror(err));
|
---|
186 |
|
---|
187 | conn->udp_socket = -1;
|
---|
188 |
|
---|
189 | for (cur=res;cur;cur=cur->ai_next)
|
---|
190 | {
|
---|
191 | conn->udp_socket = socket( cur->ai_family, cur->ai_socktype, cur->ai_protocol );
|
---|
192 | if ( conn->udp_socket == -1 )
|
---|
193 | {
|
---|
194 | err = crTCPIPErrno( );
|
---|
195 | if (err != EAFNOSUPPORT)
|
---|
196 | crWarning( "Couldn't create socket of family %i: %s, trying another one", cur->ai_family, crTCPIPErrorString( err ) );
|
---|
197 | continue;
|
---|
198 | }
|
---|
199 | if ( bind( conn->udp_socket, cur->ai_addr, cur->ai_addrlen ) )
|
---|
200 | {
|
---|
201 | err = crTCPIPErrno( );
|
---|
202 | crWarning( "Couldn't bind socket: %s", crTCPIPErrorString( err ) );
|
---|
203 | crCloseSocket( conn->udp_socket );
|
---|
204 | conn->udp_socket = -1;
|
---|
205 | continue;
|
---|
206 | }
|
---|
207 | break;
|
---|
208 |
|
---|
209 | }
|
---|
210 | freeaddrinfo(res);
|
---|
211 | #endif
|
---|
212 |
|
---|
213 | if ( conn->udp_socket < 0 )
|
---|
214 | crError( "Couldn't find local UDP port" );
|
---|
215 |
|
---|
216 | addr_length = sizeof(addr);
|
---|
217 | err = getsockname( conn->udp_socket, (struct sockaddr *) &addr, &addr_length );
|
---|
218 |
|
---|
219 | if ( err == -1 )
|
---|
220 | crError( "Couldn't get our local UDP port: %s", crTCPIPErrorString( crTCPIPErrno( ) ) );
|
---|
221 |
|
---|
222 | switch (((struct sockaddr *) &addr)->sa_family) {
|
---|
223 | case AF_INET:
|
---|
224 | crTCPIPWriteExact( conn, &((struct sockaddr_in *)&addr)->sin_port,
|
---|
225 | sizeof(((struct sockaddr_in *)&addr)->sin_port));
|
---|
226 | break;
|
---|
227 | #ifdef AF_INET6
|
---|
228 | case AF_INET6:
|
---|
229 | crTCPIPWriteExact( conn, &((struct sockaddr_in6 *)&addr)->sin6_port,
|
---|
230 | sizeof(((struct sockaddr_in6 *)&addr)->sin6_port));
|
---|
231 | break;
|
---|
232 | #endif
|
---|
233 | default:
|
---|
234 | crError( "Unknown address family: %d", ((struct sockaddr *) &addr)->sa_family);
|
---|
235 | }
|
---|
236 | }
|
---|
237 |
|
---|
238 |
|
---|
239 | static unsigned int safelen=0;
|
---|
240 | static void crUDPTCPIPSend( CRConnection *conn, void **bufp,
|
---|
241 | const void *start, unsigned int len )
|
---|
242 | {
|
---|
243 | static unsigned int safedone=0;
|
---|
244 | CRTCPIPBuffer *udptcpip_buffer;
|
---|
245 | unsigned int *lenp;
|
---|
246 |
|
---|
247 | if ( !conn || conn->type == CR_NO_CONNECTION )
|
---|
248 | return;
|
---|
249 |
|
---|
250 | if ( safelen+len > safelen )
|
---|
251 | {
|
---|
252 | safelen+=len;
|
---|
253 | if (safelen-safedone>100000)
|
---|
254 | {
|
---|
255 | safedone=safelen;
|
---|
256 | crDebug( "%dKo safe", safelen/1024 );
|
---|
257 | }
|
---|
258 | }
|
---|
259 |
|
---|
260 | conn->seq++;
|
---|
261 | if ( bufp == NULL )
|
---|
262 | {
|
---|
263 | unsigned int len_swap = conn->swap ? SWAP32(len) : len;
|
---|
264 | /* we are doing synchronous sends from user memory, so no need
|
---|
265 | * to get fancy. Simply write the length & the payload and
|
---|
266 | * return. */
|
---|
267 | crTCPIPWriteExact( conn, &len_swap, sizeof(len_swap) );
|
---|
268 | if ( conn->type == CR_NO_CONNECTION ) return;
|
---|
269 | crTCPIPWriteExact( conn, start, len );
|
---|
270 | return;
|
---|
271 | }
|
---|
272 |
|
---|
273 | udptcpip_buffer = (CRTCPIPBuffer *)(*bufp) - 1;
|
---|
274 |
|
---|
275 | CRASSERT( udptcpip_buffer->magic == CR_TCPIP_BUFFER_MAGIC );
|
---|
276 |
|
---|
277 | /* All of the buffers passed to the send function were allocated
|
---|
278 | * with crTCPIPAlloc(), which includes a header with a 4 byte
|
---|
279 | * length field, to insure that we always have a place to write
|
---|
280 | * the length field, even when start == *bufp. */
|
---|
281 | lenp = (unsigned int *) start - 1;
|
---|
282 | if (conn->swap)
|
---|
283 | {
|
---|
284 | *lenp = SWAP32(len);
|
---|
285 | }
|
---|
286 | else
|
---|
287 | {
|
---|
288 | *lenp = len;
|
---|
289 | }
|
---|
290 |
|
---|
291 | if ( __tcpip_write_exact( conn->tcp_socket, lenp, len + sizeof(*lenp) ) < 0 )
|
---|
292 | {
|
---|
293 | __tcpip_dead_connection( conn );
|
---|
294 | }
|
---|
295 |
|
---|
296 | /* reclaim this pointer for reuse and try to keep the client from
|
---|
297 | accidentally reusing it directly */
|
---|
298 | #ifdef CHROMIUM_THREADSAFE
|
---|
299 | crLockMutex(&cr_tcpip.mutex);
|
---|
300 | #endif
|
---|
301 | crBufferPoolPush( cr_tcpip.bufpool, udptcpip_buffer, conn->buffer_size );
|
---|
302 | /* Since the buffer's now in the 'free' buffer pool, the caller can't
|
---|
303 | * use it any more. Setting bufp to NULL will make sure the caller
|
---|
304 | * doesn't try to re-use the buffer.
|
---|
305 | */
|
---|
306 | *bufp = NULL;
|
---|
307 | #ifdef CHROMIUM_THREADSAFE
|
---|
308 | crUnlockMutex(&cr_tcpip.mutex);
|
---|
309 | #endif
|
---|
310 | }
|
---|
311 |
|
---|
312 | static unsigned int barflen=0;
|
---|
313 | static void crUDPTCPIPBarf( CRConnection *conn, void **bufp,
|
---|
314 | const void *start, unsigned int len)
|
---|
315 | {
|
---|
316 | static unsigned int barfdone=0;
|
---|
317 | static const unsigned int sizes[]={
|
---|
318 | 0,10,50,100,500,1000,5000,10000,UINT_MAX
|
---|
319 | };
|
---|
320 | static unsigned int nbs[sizeof(sizes)/sizeof(int)] = {
|
---|
321 | 0, 0, 0, 0, 0, 0, 0, 0, 0
|
---|
322 | };
|
---|
323 | static unsigned int nb;
|
---|
324 | unsigned int *seqp;
|
---|
325 | CRTCPIPBuffer *udptcpip_buffer;
|
---|
326 | int i;
|
---|
327 |
|
---|
328 | if (!bufp) {
|
---|
329 | crDebug("writing safely %d bytes because from user memory",len);
|
---|
330 | crUDPTCPIPSend( conn, bufp, start, len);
|
---|
331 | return;
|
---|
332 | }
|
---|
333 | if (len > conn->mtu) {
|
---|
334 | crDebug("writing safely %d bytes because that is too much for MTU %d", len, conn->mtu);
|
---|
335 | crUDPTCPIPSend( conn, bufp, start, len);
|
---|
336 | return;
|
---|
337 | }
|
---|
338 |
|
---|
339 | if ( barflen+len > barflen )
|
---|
340 | {
|
---|
341 | barflen+=len;
|
---|
342 | nb++;
|
---|
343 | for(i=0;;i++)
|
---|
344 | if (len > sizes[i] && len <= sizes[i+1]) {
|
---|
345 | nbs[i]++;
|
---|
346 | break;
|
---|
347 | }
|
---|
348 | if (barflen-barfdone>1<<22) {
|
---|
349 | barfdone=barflen;
|
---|
350 | crDebug( "send traffic: %d%sMo barfed %dKo safe", barflen/(1024*1024), barflen?"":".0", safelen/1024 );
|
---|
351 | if (nb) {
|
---|
352 | for (i=0; i < (int) (sizeof(sizes)/sizeof(int)-1); i++)
|
---|
353 | fprintf(stderr,"%u:%u%s%% ",sizes[i],(nbs[i]*100)/nb,nbs[i]==0?".0":"");
|
---|
354 | fprintf(stderr,"\n");
|
---|
355 | }
|
---|
356 | }
|
---|
357 | }
|
---|
358 |
|
---|
359 | udptcpip_buffer = (CRTCPIPBuffer *)(*bufp) - 1;
|
---|
360 |
|
---|
361 | CRASSERT( udptcpip_buffer->magic == CR_TCPIP_BUFFER_MAGIC );
|
---|
362 |
|
---|
363 | seqp = (unsigned int *) start - 1;
|
---|
364 | if (conn->swap)
|
---|
365 | {
|
---|
366 | *seqp = SWAP32(conn->seq);
|
---|
367 | }
|
---|
368 | else
|
---|
369 | {
|
---|
370 | *seqp = conn->seq;
|
---|
371 | }
|
---|
372 | crUDPIPWriteExact( conn, seqp, len + sizeof(*seqp) );
|
---|
373 |
|
---|
374 | /* reclaim this pointer for reuse and try to keep the client from
|
---|
375 | accidentally reusing it directly */
|
---|
376 | #ifdef CHROMIUM_THREADSAFE
|
---|
377 | crLockMutex(&cr_tcpip.mutex);
|
---|
378 | #endif
|
---|
379 | crBufferPoolPush( cr_tcpip.bufpool, udptcpip_buffer, conn->buffer_size );
|
---|
380 | #ifdef CHROMIUM_THREADSAFE
|
---|
381 | crUnlockMutex(&cr_tcpip.mutex);
|
---|
382 | #endif
|
---|
383 | *bufp = NULL;
|
---|
384 | }
|
---|
385 |
|
---|
386 | static void
|
---|
387 | crUDPTCPIPReceive( CRConnection *conn, CRTCPIPBuffer *buf, int len )
|
---|
388 | {
|
---|
389 | CRMessage *msg;
|
---|
390 | CRMessageType cached_type;
|
---|
391 | #if 0
|
---|
392 | crLogRead( len );
|
---|
393 | #endif
|
---|
394 |
|
---|
395 | conn->recv_credits -= len;
|
---|
396 |
|
---|
397 | conn->total_bytes_recv += len;
|
---|
398 |
|
---|
399 | msg = (CRMessage *) (buf + 1);
|
---|
400 | cached_type = msg->header.type;
|
---|
401 | if (conn->swap)
|
---|
402 | {
|
---|
403 | msg->header.type = (CRMessageType) SWAP32( msg->header.type );
|
---|
404 | msg->header.conn_id = (CRMessageType) SWAP32( msg->header.conn_id );
|
---|
405 | }
|
---|
406 |
|
---|
407 | crNetDispatchMessage( cr_tcpip.recv_list, conn, msg, len );
|
---|
408 |
|
---|
409 | /* CR_MESSAGE_OPCODES is freed in
|
---|
410 | * crserverlib/server_stream.c
|
---|
411 | *
|
---|
412 | * OOB messages are the programmer's problem. -- Humper 12/17/01 */
|
---|
413 | if (cached_type != CR_MESSAGE_OPCODES && cached_type != CR_MESSAGE_OOB)
|
---|
414 | {
|
---|
415 | crTCPIPFree( conn, buf + 1 );
|
---|
416 | }
|
---|
417 | }
|
---|
418 |
|
---|
419 | int
|
---|
420 | crUDPTCPIPRecv( void )
|
---|
421 | {
|
---|
422 | int num_ready, max_fd;
|
---|
423 | fd_set read_fds;
|
---|
424 | int i;
|
---|
425 | /* ensure we don't get caught with a new thread connecting */
|
---|
426 | int num_conns = cr_tcpip.num_conns;
|
---|
427 |
|
---|
428 | #ifdef CHROMIUM_THREADSAFE
|
---|
429 | crLockMutex(&cr_tcpip.recvmutex);
|
---|
430 | #endif
|
---|
431 |
|
---|
432 | max_fd = 0;
|
---|
433 | FD_ZERO( &read_fds );
|
---|
434 | for ( i = 0; i < num_conns; i++ )
|
---|
435 | {
|
---|
436 | CRConnection *conn = cr_tcpip.conns[i];
|
---|
437 | if ( !conn || conn->type == CR_NO_CONNECTION ) continue;
|
---|
438 | if ( conn->recv_credits > 0 || conn->type != CR_UDPTCPIP )
|
---|
439 | {
|
---|
440 | /*
|
---|
441 | * NOTE: may want to always put the FD in the descriptor
|
---|
442 | * set so we'll notice broken connections. Down in the
|
---|
443 | * loop that iterates over the ready sockets only peek
|
---|
444 | * (MSG_PEEK flag to recv()?) if the connection isn't
|
---|
445 | * enabled.
|
---|
446 | */
|
---|
447 | CRSocket sock = conn->tcp_socket;
|
---|
448 |
|
---|
449 | if (conn->type != CR_UDPTCPIP)
|
---|
450 | continue;
|
---|
451 |
|
---|
452 | if ( (int) sock + 1 > max_fd )
|
---|
453 | max_fd = (int) sock + 1;
|
---|
454 | FD_SET( sock, &read_fds );
|
---|
455 |
|
---|
456 | sock = conn->udp_socket;
|
---|
457 | if ( (int) sock + 1 > max_fd )
|
---|
458 | max_fd = (int) sock + 1;
|
---|
459 | FD_SET( sock, &read_fds );
|
---|
460 | }
|
---|
461 | }
|
---|
462 |
|
---|
463 | if (!max_fd) {
|
---|
464 | #ifdef CHROMIUM_THREADSAFE
|
---|
465 | crUnlockMutex(&cr_tcpip.recvmutex);
|
---|
466 | #endif
|
---|
467 | return 0;
|
---|
468 | }
|
---|
469 |
|
---|
470 | if ( num_conns )
|
---|
471 | {
|
---|
472 | num_ready = __crSelect( max_fd, &read_fds, 0, 500 );
|
---|
473 | }
|
---|
474 | else
|
---|
475 | {
|
---|
476 | crWarning( "Waiting for first connection..." );
|
---|
477 | num_ready = __crSelect( max_fd, &read_fds, 0, 0 );
|
---|
478 | }
|
---|
479 |
|
---|
480 | if ( num_ready == 0 ) {
|
---|
481 | #ifdef CHROMIUM_THREADSAFE
|
---|
482 | crUnlockMutex(&cr_tcpip.recvmutex);
|
---|
483 | #endif
|
---|
484 | return 0;
|
---|
485 | }
|
---|
486 |
|
---|
487 | for ( i = 0; i < num_conns; i++ )
|
---|
488 | {
|
---|
489 | CRConnection *conn = cr_tcpip.conns[i];
|
---|
490 | CRTCPIPBuffer *buf;
|
---|
491 | int len;
|
---|
492 | int sock;
|
---|
493 |
|
---|
494 | if ( !conn || conn->type == CR_NO_CONNECTION ) continue;
|
---|
495 |
|
---|
496 | if ( conn->type != CR_UDPTCPIP )
|
---|
497 | continue;
|
---|
498 |
|
---|
499 | if ( conn->udp_packet ) {
|
---|
500 | unsigned int *seq;
|
---|
501 | buf = conn->udp_packet;
|
---|
502 | seq = (unsigned int *)(buf + 1) - 1;
|
---|
503 | if ( *seq == conn->ack )
|
---|
504 | {
|
---|
505 | crUDPTCPIPReceive( conn, buf,
|
---|
506 | conn->udp_packetlen );
|
---|
507 | conn->udp_packet = NULL;
|
---|
508 | i--; /* can now read other packets */
|
---|
509 | continue;
|
---|
510 | }
|
---|
511 | if ( *seq - conn->ack > (~(0U)) >> 1 )
|
---|
512 | {
|
---|
513 | crError( "%u is older than %u ?!", *seq, conn->ack );
|
---|
514 | crTCPIPFree( conn, buf + 1 );
|
---|
515 | conn->udp_packet = NULL;
|
---|
516 | i--; /* can now read other packets */
|
---|
517 | continue;
|
---|
518 | }
|
---|
519 | /* still too early, wait for TCP data */
|
---|
520 | }
|
---|
521 | else if ( FD_ISSET(conn->udp_socket, &read_fds ) )
|
---|
522 | {
|
---|
523 | unsigned int *seq;
|
---|
524 | buf = ((CRTCPIPBuffer *) crTCPIPAlloc( conn )) - 1;
|
---|
525 | seq = ((unsigned int *) (buf + 1)) - 1;
|
---|
526 |
|
---|
527 | len = recv( conn->udp_socket, (void *)seq,
|
---|
528 | buf->allocated + sizeof(*seq), MSG_TRUNC );
|
---|
529 |
|
---|
530 | CRASSERT( len > 0 );
|
---|
531 | CRASSERT( (unsigned int)len <= buf->allocated + sizeof(*seq) );
|
---|
532 | if ( len < (int) sizeof(*seq) )
|
---|
533 | {
|
---|
534 | crWarning( "too short a UDP packet : %d", len);
|
---|
535 | crTCPIPFree( conn, buf + 1 );
|
---|
536 | continue;
|
---|
537 | }
|
---|
538 |
|
---|
539 | buf->len = len;
|
---|
540 |
|
---|
541 | if ( *seq == conn->ack)
|
---|
542 | {
|
---|
543 | crUDPTCPIPReceive( conn, buf, len );
|
---|
544 | continue;
|
---|
545 | }
|
---|
546 |
|
---|
547 | if ( *seq - conn->ack > (~(0U)) >> 1 )
|
---|
548 | {
|
---|
549 | crWarning( "%u is older than %u, dropping", *seq, conn->ack );
|
---|
550 | crTCPIPFree( conn, buf + 1 );
|
---|
551 | continue;
|
---|
552 | }
|
---|
553 | conn->udp_packet = buf;
|
---|
554 | conn->udp_packetlen = len;
|
---|
555 | }
|
---|
556 |
|
---|
557 | sock = conn->tcp_socket;
|
---|
558 | if ( !FD_ISSET( sock, &read_fds ) )
|
---|
559 | continue;
|
---|
560 |
|
---|
561 | if ( __tcpip_read_exact( sock, &len, sizeof(len)) <= 0 )
|
---|
562 | {
|
---|
563 | __tcpip_dead_connection( conn );
|
---|
564 | i--;
|
---|
565 | continue;
|
---|
566 | }
|
---|
567 |
|
---|
568 | if (conn->swap)
|
---|
569 | {
|
---|
570 | len = SWAP32(len);
|
---|
571 | }
|
---|
572 |
|
---|
573 | CRASSERT( len > 0 );
|
---|
574 |
|
---|
575 | if ( (unsigned int)len <= conn->buffer_size )
|
---|
576 | {
|
---|
577 | buf = (CRTCPIPBuffer *) crTCPIPAlloc( conn ) - 1;
|
---|
578 | }
|
---|
579 | else
|
---|
580 | {
|
---|
581 | buf = (CRTCPIPBuffer *)
|
---|
582 | crAlloc( sizeof(*buf) + len );
|
---|
583 | buf->magic = CR_TCPIP_BUFFER_MAGIC;
|
---|
584 | buf->kind = CRTCPIPMemoryBig;
|
---|
585 | buf->pad = 0;
|
---|
586 | }
|
---|
587 |
|
---|
588 | buf->len = len;
|
---|
589 |
|
---|
590 | if ( __tcpip_read_exact( sock, buf + 1, len ) <= 0 )
|
---|
591 | {
|
---|
592 | crWarning( "Bad juju: %d %d", buf->allocated, len );
|
---|
593 | crFree( buf );
|
---|
594 | __tcpip_dead_connection( conn );
|
---|
595 | i--;
|
---|
596 | continue;
|
---|
597 | }
|
---|
598 |
|
---|
599 | crUDPTCPIPReceive( conn, buf, len );
|
---|
600 | conn->ack++;
|
---|
601 | }
|
---|
602 |
|
---|
603 | #ifdef CHROMIUM_THREADSAFE
|
---|
604 | crUnlockMutex(&cr_tcpip.recvmutex);
|
---|
605 | #endif
|
---|
606 |
|
---|
607 | return 1;
|
---|
608 | }
|
---|
609 |
|
---|
610 | void crUDPTCPIPInit( CRNetReceiveFuncList *rfl, CRNetCloseFuncList *cfl, unsigned int mtu )
|
---|
611 | {
|
---|
612 | crTCPIPInit( rfl, cfl, mtu );
|
---|
613 | }
|
---|
614 |
|
---|
615 | /* The function that actually connects. This should only be called by clients
|
---|
616 | * Servers have another way to set up the socket. */
|
---|
617 |
|
---|
618 | static int crUDPTCPIPDoConnect( CRConnection *conn )
|
---|
619 | {
|
---|
620 | #ifdef WINDOWS
|
---|
621 | unsigned short port;
|
---|
622 | #else
|
---|
623 | in_port_t port;
|
---|
624 | #endif
|
---|
625 | #ifdef LINUX
|
---|
626 | int opt = IP_PMTUDISC_DO;
|
---|
627 | #endif
|
---|
628 | #ifndef ADDRINFO
|
---|
629 | struct hostent *hp;
|
---|
630 | #else
|
---|
631 | int err;
|
---|
632 | char port_s[NI_MAXSERV];
|
---|
633 | struct addrinfo *res,*cur;
|
---|
634 | struct addrinfo hints;
|
---|
635 | #endif
|
---|
636 |
|
---|
637 | /* first connect to its tcp port */
|
---|
638 | if ( !crTCPIPDoConnect( conn ) )
|
---|
639 | return 0;
|
---|
640 |
|
---|
641 | /* read its UDP port */
|
---|
642 | crTCPIPReadExact( conn, &port, sizeof( port ) );
|
---|
643 | port = ntohs(port);
|
---|
644 |
|
---|
645 | crDebug( "Server's UDP port is %d", port);
|
---|
646 |
|
---|
647 | /* and connect to it */
|
---|
648 | #ifndef ADDRINFO
|
---|
649 | hp = gethostbyname( conn->hostname );
|
---|
650 | if ( !hp )
|
---|
651 | {
|
---|
652 | crWarning( "Unknown host: \"%s\"", conn->hostname );
|
---|
653 | return 0;
|
---|
654 | }
|
---|
655 | conn->udp_socket = socket( AF_INET, SOCK_DGRAM, 0 );
|
---|
656 | memset(&conn->remoteaddr, 0, sizeof(conn->remoteaddr));
|
---|
657 | conn->remoteaddr.sin_family = AF_INET;
|
---|
658 | conn->remoteaddr.sin_port = htons( (short) port );
|
---|
659 |
|
---|
660 | memcpy( (char *) &conn->remoteaddr.sin_addr, hp->h_addr,
|
---|
661 | sizeof(conn->remoteaddr.sin_addr) );
|
---|
662 | if ( conn->udp_socket >= 0 ) {
|
---|
663 | if ( connect( conn->udp_socket, (struct sockaddr *) &conn->remoteaddr,
|
---|
664 | sizeof(conn->remoteaddr) ) == -1 )
|
---|
665 | crWarning( "Couldn't connect UDP socket : %s", crTCPIPErrorString( crTCPIPErrno( ) ) );
|
---|
666 | } else {
|
---|
667 | #else
|
---|
668 | sprintf(port_s, "%u", port);
|
---|
669 |
|
---|
670 | memset(&hints, 0, sizeof(hints));
|
---|
671 | hints.ai_family = PF;
|
---|
672 | hints.ai_socktype = SOCK_DGRAM;
|
---|
673 |
|
---|
674 | err = getaddrinfo( conn->hostname, port_s, &hints, &res);
|
---|
675 | if ( err )
|
---|
676 | {
|
---|
677 | crWarning( "Unknown host: \"%s\": %s", conn->hostname, gai_strerror(err) );
|
---|
678 | return 0;
|
---|
679 | }
|
---|
680 |
|
---|
681 | for (cur=res;cur;)
|
---|
682 | {
|
---|
683 | conn->udp_socket = socket( cur->ai_family, cur->ai_socktype, cur->ai_protocol );
|
---|
684 | if ( conn->udp_socket >= 0 )
|
---|
685 | {
|
---|
686 | if ( connect( conn->udp_socket, cur->ai_addr, cur->ai_addrlen ) == -1 )
|
---|
687 | crWarning( "Couldn't connect UDP socket : %s", crTCPIPErrorString( crTCPIPErrno( ) ) );
|
---|
688 | break;
|
---|
689 | }
|
---|
690 | err = crTCPIPErrno( );
|
---|
691 | if (err != EAFNOSUPPORT)
|
---|
692 | crWarning( "socket error: %s, trying another way", crTCPIPErrorString( err ) );
|
---|
693 | cur=cur->ai_next;
|
---|
694 | }
|
---|
695 | if (!cur) {
|
---|
696 | freeaddrinfo(res);
|
---|
697 | #endif
|
---|
698 | crWarning( "Couldn't find any suitable way to connect to %s:%d", conn->hostname, port );
|
---|
699 | return 0;
|
---|
700 | }
|
---|
701 |
|
---|
702 | #ifdef LINUX
|
---|
703 | if ( setsockopt(conn->udp_socket, SOL_IP, IP_MTU_DISCOVER, &opt, sizeof(opt)) == -1 )
|
---|
704 | {
|
---|
705 | err = crTCPIPErrno( );
|
---|
706 | crWarning( "MTU discovery can't be activated : %s", crTCPIPErrorString( err ) );
|
---|
707 | }
|
---|
708 | else
|
---|
709 | {
|
---|
710 | socklen_t len = sizeof(opt);
|
---|
711 | if ( getsockopt(conn->udp_socket, SOL_IP, IP_MTU, &opt, &len) == -1 )
|
---|
712 | crWarning( "MTU couldn't be got : %s", crTCPIPErrorString( crTCPIPErrno ( ) ) );
|
---|
713 | else
|
---|
714 | if ( len != sizeof(opt) )
|
---|
715 | crWarning( "Unexpected length %d for MTU option length", len );
|
---|
716 | else
|
---|
717 | {
|
---|
718 | opt -= sizeof(conn->seq) + sizeof(struct udphdr) + sizeof(struct ip6_hdr);
|
---|
719 | crDebug( "MTU is (for now) %d", opt );
|
---|
720 | conn->mtu = opt;
|
---|
721 | }
|
---|
722 | }
|
---|
723 | #endif
|
---|
724 | #ifdef ADDRINFO
|
---|
725 | crMemcpy(&conn->remoteaddr, cur->ai_addr, cur->ai_addrlen);
|
---|
726 | freeaddrinfo(res);
|
---|
727 | #endif
|
---|
728 | return 1;
|
---|
729 | }
|
---|
730 |
|
---|
731 | static void crUDPTCPIPDoDisconnect( CRConnection *conn )
|
---|
732 | {
|
---|
733 | crCloseSocket( conn->udp_socket );
|
---|
734 | crTCPIPDoDisconnect( conn );
|
---|
735 | }
|
---|
736 |
|
---|
737 | void crUDPTCPIPConnection( CRConnection *conn )
|
---|
738 | {
|
---|
739 | crTCPIPConnection( conn );
|
---|
740 |
|
---|
741 | conn->type = CR_UDPTCPIP;
|
---|
742 | conn->Send = crUDPTCPIPSend;
|
---|
743 | conn->Barf = crUDPTCPIPBarf;
|
---|
744 | conn->SendExact = NULL;
|
---|
745 | conn->Recv = NULL; /* none for UDP : *must* multiplex ! */
|
---|
746 | conn->Accept = crUDPTCPIPAccept;
|
---|
747 | conn->Connect = crUDPTCPIPDoConnect;
|
---|
748 | conn->Disconnect = crUDPTCPIPDoDisconnect;
|
---|
749 | conn->seq = 0;
|
---|
750 | conn->ack = 0;
|
---|
751 | conn->udp_packet = NULL;
|
---|
752 | conn->mtu -= sizeof(conn->seq); /* some room for seq */
|
---|
753 | }
|
---|