PageRenderTime 60ms CodeModel.GetById 24ms app.highlight 31ms RepoModel.GetById 1ms app.codeStats 0ms

/indra/llmessage/net.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 665 lines | 468 code | 93 blank | 104 comment | 80 complexity | b914bdb70ee55711901b4c5cd1caa600 MD5 | raw file
  1/** 
  2 * @file net.cpp
  3 * @brief Cross-platform routines for sending and receiving packets.
  4 *
  5 * $LicenseInfo:firstyear=2000&license=viewerlgpl$
  6 * Second Life Viewer Source Code
  7 * Copyright (C) 2010, Linden Research, Inc.
  8 * 
  9 * This library is free software; you can redistribute it and/or
 10 * modify it under the terms of the GNU Lesser General Public
 11 * License as published by the Free Software Foundation;
 12 * version 2.1 of the License only.
 13 * 
 14 * This library is distributed in the hope that it will be useful,
 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 17 * Lesser General Public License for more details.
 18 * 
 19 * You should have received a copy of the GNU Lesser General Public
 20 * License along with this library; if not, write to the Free Software
 21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 22 * 
 23 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 24 * $/LicenseInfo$
 25 */
 26
 27#include "linden_common.h"
 28
 29#include "net.h"
 30
 31// system library includes
 32#include <stdexcept>
 33
 34#if LL_WINDOWS
 35	#define WIN32_LEAN_AND_MEAN
 36	#include <winsock2.h>
 37	#include <windows.h>
 38#else
 39	#include <sys/types.h>
 40	#include <sys/socket.h>
 41	#include <netinet/in.h>
 42	#include <arpa/inet.h>
 43	#include <fcntl.h>
 44	#include <errno.h>
 45#endif
 46
 47// linden library includes
 48#include "llerror.h"
 49#include "llhost.h"
 50#include "lltimer.h"
 51#include "indra_constants.h"
 52
 53// Globals
 54#if LL_WINDOWS
 55
 56SOCKADDR_IN stDstAddr;
 57SOCKADDR_IN stSrcAddr;
 58SOCKADDR_IN stLclAddr;
 59static WSADATA stWSAData;
 60
 61#else
 62
 63struct sockaddr_in stDstAddr;
 64struct sockaddr_in stSrcAddr;
 65struct sockaddr_in stLclAddr;
 66
 67#if LL_DARWIN
 68#ifndef _SOCKLEN_T
 69#define _SOCKLEN_T
 70typedef int socklen_t;
 71#endif
 72#endif
 73
 74#endif
 75
 76static U32 gsnReceivingIFAddr = INVALID_HOST_IP_ADDRESS; // Address to which datagram was sent
 77
 78const char* LOOPBACK_ADDRESS_STRING = "127.0.0.1";
 79const char* BROADCAST_ADDRESS_STRING = "255.255.255.255";
 80
 81#if LL_DARWIN
 82	// Mac OS X returns an error when trying to set these to 400000.  Smaller values succeed.
 83	const int	SEND_BUFFER_SIZE	= 200000;
 84	const int	RECEIVE_BUFFER_SIZE	= 200000;
 85#else // LL_DARWIN
 86	const int	SEND_BUFFER_SIZE	= 400000;
 87	const int	RECEIVE_BUFFER_SIZE	= 400000;
 88#endif // LL_DARWIN
 89
 90// universal functions (cross-platform)
 91
 92LLHost get_sender()
 93{
 94	return LLHost(stSrcAddr.sin_addr.s_addr, ntohs(stSrcAddr.sin_port));
 95}
 96
 97U32 get_sender_ip(void) 
 98{
 99	return stSrcAddr.sin_addr.s_addr;
100}
101
102U32 get_sender_port() 
103{
104	return ntohs(stSrcAddr.sin_port);
105}
106
107LLHost get_receiving_interface()
108{
109	return LLHost(gsnReceivingIFAddr, INVALID_PORT);
110}
111
112U32 get_receiving_interface_ip(void)
113{
114	return gsnReceivingIFAddr;
115}
116
117const char* u32_to_ip_string(U32 ip)
118{
119	static char buffer[MAXADDRSTR];	 /* Flawfinder: ignore */ 
120
121	// Convert the IP address into a string
122	in_addr in;
123	in.s_addr = ip;
124	char* result = inet_ntoa(in);
125
126	// NULL indicates error in conversion
127	if (result != NULL)
128	{
129		strncpy( buffer, result, MAXADDRSTR );	 /* Flawfinder: ignore */ 
130		buffer[MAXADDRSTR-1] = '\0';
131		return buffer;
132	}
133	else
134	{
135		return "(bad IP addr)";
136	}
137}
138
139
140// Returns ip_string if successful, NULL if not.  Copies into ip_string
141char *u32_to_ip_string(U32 ip, char *ip_string)
142{
143	char *result;
144	in_addr in;
145
146	// Convert the IP address into a string
147	in.s_addr = ip;
148	result = inet_ntoa(in);
149
150	// NULL indicates error in conversion
151	if (result != NULL)
152	{
153		//the function signature needs to change to pass in the lengfth of first and last.
154		strcpy(ip_string, result);	/*Flawfinder: ignore*/
155		return ip_string;
156	}
157	else
158	{
159		return NULL;
160	}
161}
162
163
164// Wrapper for inet_addr()
165U32 ip_string_to_u32(const char* ip_string)
166{
167	// *NOTE: Windows doesn't support inet_aton(), so we are using
168	// inet_addr(). Unfortunately, INADDR_NONE == INADDR_BROADCAST, so 
169	// we have to check whether the input is a broadcast address before
170	// deciding that @ip_string is invalid.
171	//
172	// Also, our definition of INVALID_HOST_IP_ADDRESS doesn't allow us to
173	// use wildcard addresses. -Ambroff
174	U32 ip = inet_addr(ip_string);
175	if (ip == INADDR_NONE 
176			&& strncmp(ip_string, BROADCAST_ADDRESS_STRING, MAXADDRSTR) != 0)
177	{
178		llwarns << "ip_string_to_u32() failed, Error: Invalid IP string '" << ip_string << "'" << llendl;
179		return INVALID_HOST_IP_ADDRESS;
180	}
181	return ip;
182}
183
184
185//////////////////////////////////////////////////////////////////////////////////////////
186// Windows Versions
187//////////////////////////////////////////////////////////////////////////////////////////
188
189#if LL_WINDOWS
190
191S32 start_net(S32& socket_out, int& nPort) 
192{			
193	// Create socket, make non-blocking
194	// Init WinSock
195	int nRet;
196	int hSocket;
197
198	int snd_size = SEND_BUFFER_SIZE;
199	int rec_size = RECEIVE_BUFFER_SIZE;
200	int buff_size = 4;
201 
202	// Initialize windows specific stuff
203	if (WSAStartup(0x0202, &stWSAData))
204	{
205		S32 err = WSAGetLastError();
206		WSACleanup();
207		LL_WARNS("AppInit") << "Windows Sockets initialization failed, err " << err << LL_ENDL;
208		return 1;
209	}
210
211	// Get a datagram socket
212	hSocket = (int)socket(AF_INET, SOCK_DGRAM, 0);
213	if (hSocket == INVALID_SOCKET)
214	{
215		S32 err = WSAGetLastError();
216		WSACleanup();
217		LL_WARNS("AppInit") << "socket() failed, err " << err << LL_ENDL;
218		return 2;
219	}
220
221	// Name the socket (assign the local port number to receive on)
222	stLclAddr.sin_family      = AF_INET;
223	stLclAddr.sin_addr.s_addr = htonl(INADDR_ANY);
224	stLclAddr.sin_port        = htons(nPort);
225
226	S32 attempt_port = nPort;
227	LL_DEBUGS("AppInit") << "attempting to connect on port " << attempt_port << LL_ENDL;
228	nRet = bind(hSocket, (struct sockaddr*) &stLclAddr, sizeof(stLclAddr));
229
230	if (nRet == SOCKET_ERROR)
231	{
232		// If we got an address in use error...
233		if (WSAGetLastError() == WSAEADDRINUSE)
234		{
235			// Try all ports from PORT_DISCOVERY_RANGE_MIN to PORT_DISCOVERY_RANGE_MAX
236			for(attempt_port = PORT_DISCOVERY_RANGE_MIN;
237				attempt_port <= PORT_DISCOVERY_RANGE_MAX;
238				attempt_port++)
239			{
240				stLclAddr.sin_port = htons(attempt_port);
241				LL_DEBUGS("AppInit") << "trying port " << attempt_port << LL_ENDL;
242				nRet = bind(hSocket, (struct sockaddr*) &stLclAddr, sizeof(stLclAddr));
243
244				if (!(nRet == SOCKET_ERROR && 
245					WSAGetLastError() == WSAEADDRINUSE))
246				{
247					break;
248				}
249			}
250
251			if (nRet == SOCKET_ERROR)
252			{
253				LL_WARNS("AppInit") << "startNet() : Couldn't find available network port." << LL_ENDL;
254				// Fail gracefully here in release
255				return 3;
256			}
257		}
258		else
259		// Some other socket error
260		{
261			LL_WARNS("AppInit") << llformat("bind() port: %d failed, Err: %d\n", nPort, WSAGetLastError()) << LL_ENDL;
262			// Fail gracefully in release.
263			return 4;
264		}
265	}
266
267	sockaddr_in socket_address;
268	S32 socket_address_size = sizeof(socket_address);
269	getsockname(hSocket, (SOCKADDR*) &socket_address, &socket_address_size);
270	attempt_port = ntohs(socket_address.sin_port);
271
272	LL_INFOS("AppInit") << "connected on port " << attempt_port << LL_ENDL;
273	nPort = attempt_port;
274	
275	// Set socket to be non-blocking
276	unsigned long argp = 1;
277	nRet = ioctlsocket (hSocket, FIONBIO, &argp);
278	if (nRet == SOCKET_ERROR) 
279	{
280		printf("Failed to set socket non-blocking, Err: %d\n", 
281		WSAGetLastError());
282	}
283
284	// set a large receive buffer
285	nRet = setsockopt(hSocket, SOL_SOCKET, SO_RCVBUF, (char *)&rec_size, buff_size);
286	if (nRet)
287	{
288		LL_INFOS("AppInit") << "Can't set receive buffer size!" << LL_ENDL;
289	}
290
291	nRet = setsockopt(hSocket, SOL_SOCKET, SO_SNDBUF, (char *)&snd_size, buff_size);
292	if (nRet)
293	{
294		LL_INFOS("AppInit") << "Can't set send buffer size!" << LL_ENDL;
295	}
296
297	getsockopt(hSocket, SOL_SOCKET, SO_RCVBUF, (char *)&rec_size, &buff_size);
298	getsockopt(hSocket, SOL_SOCKET, SO_SNDBUF, (char *)&snd_size, &buff_size);
299
300	LL_DEBUGS("AppInit") << "startNet - receive buffer size : " << rec_size << LL_ENDL;
301	LL_DEBUGS("AppInit") << "startNet - send buffer size    : " << snd_size << LL_ENDL;
302
303	//  Setup a destination address
304	stDstAddr.sin_family =      AF_INET;
305	stDstAddr.sin_addr.s_addr = INVALID_HOST_IP_ADDRESS;
306	stDstAddr.sin_port =        htons(nPort);
307
308	socket_out = hSocket;
309	return 0;
310}
311
312void end_net(S32& socket_out)
313{
314	if (socket_out >= 0)
315	{
316		shutdown(socket_out, SD_BOTH);
317		closesocket(socket_out);
318	}
319	WSACleanup();
320}
321
322S32 receive_packet(int hSocket, char * receiveBuffer)
323{
324	//  Receives data asynchronously from the socket set by initNet().
325	//  Returns the number of bytes received into dataReceived, or zero
326	//  if there is no data received.
327	int nRet;
328	int addr_size = sizeof(struct sockaddr_in);
329
330	nRet = recvfrom(hSocket, receiveBuffer, NET_BUFFER_SIZE, 0, (struct sockaddr*)&stSrcAddr, &addr_size);
331	if (nRet == SOCKET_ERROR ) 
332	{
333		if (WSAEWOULDBLOCK == WSAGetLastError())
334			return 0;
335		if (WSAECONNRESET == WSAGetLastError())
336			return 0;
337		llinfos << "receivePacket() failed, Error: " << WSAGetLastError() << llendl;
338	}
339	
340	return nRet;
341}
342
343// Returns TRUE on success.
344BOOL send_packet(int hSocket, const char *sendBuffer, int size, U32 recipient, int nPort)
345{
346	//  Sends a packet to the address set in initNet
347	//  
348	int nRet = 0;
349	U32 last_error = 0;
350
351	stDstAddr.sin_addr.s_addr = recipient;
352	stDstAddr.sin_port = htons(nPort);
353	do
354	{
355		nRet = sendto(hSocket, sendBuffer, size, 0, (struct sockaddr*)&stDstAddr, sizeof(stDstAddr));					
356
357		if (nRet == SOCKET_ERROR ) 
358		{
359			last_error = WSAGetLastError();
360			if (last_error != WSAEWOULDBLOCK)
361			{
362				// WSAECONNRESET - I think this is caused by an ICMP "connection refused"
363				// message being sent back from a Linux box...  I'm not finding helpful
364				// documentation or web pages on this.  The question is whether the packet
365				// actually got sent or not.  Based on the structure of this code, I would
366				// assume it is.  JNC 2002.01.18
367				if (WSAECONNRESET == WSAGetLastError())
368				{
369					return TRUE;
370				}
371				llinfos << "sendto() failed to " << u32_to_ip_string(recipient) << ":" << nPort 
372					<< ", Error " << last_error << llendl;
373			}
374		}
375	} while (  (nRet == SOCKET_ERROR)
376			 &&(last_error == WSAEWOULDBLOCK));
377
378	return (nRet != SOCKET_ERROR);
379}
380
381//////////////////////////////////////////////////////////////////////////////////////////
382// Linux Versions
383//////////////////////////////////////////////////////////////////////////////////////////
384
385#else
386
387//  Create socket, make non-blocking
388S32 start_net(S32& socket_out, int& nPort)
389{
390	int hSocket, nRet;
391	int snd_size = SEND_BUFFER_SIZE;
392	int rec_size = RECEIVE_BUFFER_SIZE;
393
394	socklen_t buff_size = 4;
395
396	//  Create socket
397	hSocket = socket(AF_INET, SOCK_DGRAM, 0);
398	if (hSocket < 0)
399	{
400		llwarns << "socket() failed" << llendl;
401		return 1;
402	}
403
404	if (NET_USE_OS_ASSIGNED_PORT == nPort)
405	{
406		// Although bind is not required it will tell us which port we were
407		// assigned to.
408		stLclAddr.sin_family      = AF_INET;
409		stLclAddr.sin_addr.s_addr = htonl(INADDR_ANY);
410		stLclAddr.sin_port        = htons(0);
411		llinfos << "attempting to connect on OS assigned port" << llendl;
412		nRet = bind(hSocket, (struct sockaddr*) &stLclAddr, sizeof(stLclAddr));
413		if (nRet < 0)
414		{
415			llwarns << "Failed to bind on an OS assigned port error: "
416					<< nRet << llendl;
417		}
418		else
419		{
420			sockaddr_in socket_info;
421			socklen_t len = sizeof(sockaddr_in);
422			int err = getsockname(hSocket, (sockaddr*)&socket_info, &len);
423			llinfos << "Get socket returned: " << err << " length " << len << llendl;
424			nPort = ntohs(socket_info.sin_port);
425			llinfos << "Assigned port: " << nPort << llendl;
426			
427		}
428	}
429	else
430	{
431		// Name the socket (assign the local port number to receive on)
432		stLclAddr.sin_family      = AF_INET;
433		stLclAddr.sin_addr.s_addr = htonl(INADDR_ANY);
434		stLclAddr.sin_port        = htons(nPort);
435		U32 attempt_port = nPort;
436		llinfos << "attempting to connect on port " << attempt_port << llendl;
437
438		nRet = bind(hSocket, (struct sockaddr*) &stLclAddr, sizeof(stLclAddr));
439		if (nRet < 0)
440		{
441			// If we got an address in use error...
442			if (errno == EADDRINUSE)
443			{
444				// Try all ports from PORT_DISCOVERY_RANGE_MIN to PORT_DISCOVERY_RANGE_MAX
445				for(attempt_port = PORT_DISCOVERY_RANGE_MIN;
446					attempt_port <= PORT_DISCOVERY_RANGE_MAX;
447					attempt_port++)
448				{
449					stLclAddr.sin_port = htons(attempt_port);
450					llinfos << "trying port " << attempt_port << llendl;
451					nRet = bind(hSocket, (struct sockaddr*) &stLclAddr, sizeof(stLclAddr));
452					if (!((nRet < 0) && (errno == EADDRINUSE)))
453					{
454						break;
455					}
456				}
457				if (nRet < 0)
458				{
459					llwarns << "startNet() : Couldn't find available network port." << llendl;
460					// Fail gracefully in release.
461					return 3;
462				}
463			}
464			// Some other socket error
465			else
466			{
467				llwarns << llformat ("bind() port: %d failed, Err: %s\n", nPort, strerror(errno)) << llendl;
468				// Fail gracefully in release.
469				return 4;
470			}
471		}
472		llinfos << "connected on port " << attempt_port << llendl;
473		nPort = attempt_port;
474	}
475	// Set socket to be non-blocking
476	fcntl(hSocket, F_SETFL, O_NONBLOCK);
477	// set a large receive buffer
478	nRet = setsockopt(hSocket, SOL_SOCKET, SO_RCVBUF, (char *)&rec_size, buff_size);
479	if (nRet)
480	{
481		llinfos << "Can't set receive size!" << llendl;
482	}
483	nRet = setsockopt(hSocket, SOL_SOCKET, SO_SNDBUF, (char *)&snd_size, buff_size);
484	if (nRet)
485	{
486		llinfos << "Can't set send size!" << llendl;
487	}
488	getsockopt(hSocket, SOL_SOCKET, SO_RCVBUF, (char *)&rec_size, &buff_size);
489	getsockopt(hSocket, SOL_SOCKET, SO_SNDBUF, (char *)&snd_size, &buff_size);
490
491	llinfos << "startNet - receive buffer size : " << rec_size << llendl;
492	llinfos << "startNet - send buffer size    : " << snd_size << llendl;
493
494#if LL_LINUX
495	// Turn on recipient address tracking
496	{
497		int use_pktinfo = 1;
498		if( setsockopt( hSocket, SOL_IP, IP_PKTINFO, &use_pktinfo, sizeof(use_pktinfo) ) == -1 )
499		{
500			llwarns << "No IP_PKTINFO available" << llendl;
501		}
502		else
503		{
504			llinfos << "IP_PKKTINFO enabled" << llendl;
505		}
506	}
507#endif
508
509	//  Setup a destination address
510	char achMCAddr[MAXADDRSTR] = "127.0.0.1";	/* Flawfinder: ignore */ 
511	stDstAddr.sin_family =      AF_INET;
512	stDstAddr.sin_addr.s_addr = ip_string_to_u32(achMCAddr);
513	stDstAddr.sin_port =        htons(nPort);
514
515	socket_out = hSocket;
516	return 0;
517}
518
519void end_net(S32& socket_out)
520{
521	if (socket_out >= 0)
522	{
523		close(socket_out);
524	}
525}
526
527#if LL_LINUX
528static int recvfrom_destip( int socket, void *buf, int len, struct sockaddr *from, socklen_t *fromlen, U32 *dstip )
529{
530	int size;
531	struct iovec iov[1];
532	char cmsg[CMSG_SPACE(sizeof(struct in_pktinfo))];
533	struct cmsghdr *cmsgptr;
534	struct msghdr msg = {0};
535
536	iov[0].iov_base = buf;
537	iov[0].iov_len = len;
538
539	memset(&msg, 0, sizeof msg);
540	msg.msg_name = from;
541	msg.msg_namelen = *fromlen;
542	msg.msg_iov = iov;
543	msg.msg_iovlen = 1;
544	msg.msg_control = &cmsg;
545	msg.msg_controllen = sizeof(cmsg);
546
547	size = recvmsg(socket, &msg, 0);
548
549	if (size == -1)
550	{
551		return -1;
552	}
553
554	for (cmsgptr = CMSG_FIRSTHDR(&msg); cmsgptr != NULL; cmsgptr = CMSG_NXTHDR( &msg, cmsgptr))
555	{
556		if( cmsgptr->cmsg_level == SOL_IP && cmsgptr->cmsg_type == IP_PKTINFO )
557		{
558			in_pktinfo *pktinfo = (in_pktinfo *)CMSG_DATA(cmsgptr);
559			if( pktinfo )
560			{
561				// Two choices. routed and specified. ipi_addr is routed, ipi_spec_dst is
562				// routed. We should stay with specified until we go to multiple
563				// interfaces
564				*dstip = pktinfo->ipi_spec_dst.s_addr;
565			}
566		}
567	}
568
569	return size;
570}
571#endif
572
573int receive_packet(int hSocket, char * receiveBuffer)
574{
575	//  Receives data asynchronously from the socket set by initNet().
576	//  Returns the number of bytes received into dataReceived, or zero
577	//  if there is no data received.
578	// or -1 if an error occured!
579	int nRet;
580	socklen_t addr_size = sizeof(struct sockaddr_in);
581
582	gsnReceivingIFAddr = INVALID_HOST_IP_ADDRESS;
583
584#if LL_LINUX
585	nRet = recvfrom_destip(hSocket, receiveBuffer, NET_BUFFER_SIZE, (struct sockaddr*)&stSrcAddr, &addr_size, &gsnReceivingIFAddr);
586#else	
587	int recv_flags = 0;
588	nRet = recvfrom(hSocket, receiveBuffer, NET_BUFFER_SIZE, recv_flags, (struct sockaddr*)&stSrcAddr, &addr_size);
589#endif
590
591	if (nRet == -1)
592	{
593		// To maintain consistency with the Windows implementation, return a zero for size on error.
594		return 0;
595	}
596
597	// Uncomment for testing if/when implementing for Mac or Windows:
598	// llinfos << "Received datagram to in addr " << u32_to_ip_string(get_receiving_interface_ip()) << llendl;
599
600	return nRet;
601}
602
603BOOL send_packet(int hSocket, const char * sendBuffer, int size, U32 recipient, int nPort)
604{
605	int		ret;
606	BOOL	success;
607	BOOL	resend;
608	S32		send_attempts = 0;
609
610	stDstAddr.sin_addr.s_addr = recipient;
611	stDstAddr.sin_port = htons(nPort);
612
613	do
614	{
615		ret = sendto(hSocket, sendBuffer, size, 0,	(struct sockaddr*)&stDstAddr, sizeof(stDstAddr));
616		send_attempts++;
617
618		if (ret >= 0)
619		{
620			// successful send
621			success = TRUE;
622			resend = FALSE;
623		}
624		else
625		{
626			// send failed, check to see if we should resend
627			success = FALSE;
628
629			if (errno == EAGAIN)
630			{
631				// say nothing, just repeat send
632				llinfos << "sendto() reported buffer full, resending (attempt " << send_attempts << ")" << llendl;
633				llinfos << inet_ntoa(stDstAddr.sin_addr) << ":" << nPort << llendl;
634				resend = TRUE;
635			}
636			else if (errno == ECONNREFUSED)
637			{
638				// response to ICMP connection refused message on earlier send
639				llinfos << "sendto() reported connection refused, resending (attempt " << send_attempts << ")" << llendl;
640				llinfos << inet_ntoa(stDstAddr.sin_addr) << ":" << nPort << llendl;
641				resend = TRUE;
642			}
643			else
644			{
645				// some other error
646				llinfos << "sendto() failed: " << errno << ", " << strerror(errno) << llendl;
647				llinfos << inet_ntoa(stDstAddr.sin_addr) << ":" << nPort << llendl;
648				resend = FALSE;
649			}
650		}
651	}
652	while (resend && send_attempts < 3);
653
654	if (send_attempts >= 3)
655	{
656		llinfos << "sendPacket() bailed out of send!" << llendl;
657		return FALSE;
658	}
659
660	return success;
661}
662
663#endif
664
665//EOF