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