/apps/desktop/libvncserver/sockets.c

http://ftk.googlecode.com/ · C · 707 lines · 528 code · 108 blank · 71 comment · 128 complexity · 53a9b6f0b37e0396e20fa77c3e0ee8a7 MD5 · raw file

  1. /*
  2. * sockets.c - deal with TCP & UDP sockets.
  3. *
  4. * This code should be independent of any changes in the RFB protocol. It just
  5. * deals with the X server scheduling stuff, calling rfbNewClientConnection and
  6. * rfbProcessClientMessage to actually deal with the protocol. If a socket
  7. * needs to be closed for any reason then rfbCloseClient should be called, and
  8. * this in turn will call rfbClientConnectionGone. To make an active
  9. * connection out, call rfbConnect - note that this does _not_ call
  10. * rfbNewClientConnection.
  11. *
  12. * This file is divided into two types of function. Those beginning with
  13. * "rfb" are specific to sockets using the RFB protocol. Those without the
  14. * "rfb" prefix are more general socket routines (which are used by the http
  15. * code).
  16. *
  17. * Thanks to Karl Hakimian for pointing out that some platforms return EAGAIN
  18. * not EWOULDBLOCK.
  19. */
  20. /*
  21. * Copyright (C) 2005 Rohit Kumar, Johannes E. Schindelin
  22. * OSXvnc Copyright (C) 2001 Dan McGuirk <mcguirk@incompleteness.net>.
  23. * Original Xvnc code Copyright (C) 1999 AT&T Laboratories Cambridge.
  24. * All Rights Reserved.
  25. *
  26. * This is free software; you can redistribute it and/or modify
  27. * it under the terms of the GNU General Public License as published by
  28. * the Free Software Foundation; either version 2 of the License, or
  29. * (at your option) any later version.
  30. *
  31. * This software is distributed in the hope that it will be useful,
  32. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  33. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  34. * GNU General Public License for more details.
  35. *
  36. * You should have received a copy of the GNU General Public License
  37. * along with this software; if not, write to the Free Software
  38. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
  39. * USA.
  40. */
  41. #include <rfb/rfb.h>
  42. #ifdef LIBVNCSERVER_HAVE_SYS_TYPES_H
  43. #include <sys/types.h>
  44. #endif
  45. #ifdef LIBVNCSERVER_HAVE_SYS_TIME_H
  46. #include <sys/time.h>
  47. #endif
  48. #ifdef LIBVNCSERVER_HAVE_SYS_SOCKET_H
  49. #include <sys/socket.h>
  50. #endif
  51. #ifdef LIBVNCSERVER_HAVE_NETINET_IN_H
  52. #include <netinet/in.h>
  53. #include <netinet/tcp.h>
  54. #include <netdb.h>
  55. #include <arpa/inet.h>
  56. #endif
  57. #ifdef LIBVNCSERVER_HAVE_UNISTD_H
  58. #include <unistd.h>
  59. #endif
  60. #if defined(__linux__) && defined(NEED_TIMEVAL)
  61. struct timeval
  62. {
  63. long int tv_sec,tv_usec;
  64. }
  65. ;
  66. #endif
  67. #ifdef LIBVNCSERVER_HAVE_FCNTL_H
  68. #include <fcntl.h>
  69. #endif
  70. #include <errno.h>
  71. #ifdef USE_LIBWRAP
  72. #include <syslog.h>
  73. #include <tcpd.h>
  74. int allow_severity=LOG_INFO;
  75. int deny_severity=LOG_WARNING;
  76. #endif
  77. #if defined(WIN32)
  78. #ifndef __MINGW32__
  79. #pragma warning (disable: 4018 4761)
  80. #endif
  81. #define read(sock,buf,len) recv(sock,buf,len,0)
  82. #define EWOULDBLOCK WSAEWOULDBLOCK
  83. #define ETIMEDOUT WSAETIMEDOUT
  84. #define write(sock,buf,len) send(sock,buf,len,0)
  85. #else
  86. #define closesocket close
  87. #endif
  88. int rfbMaxClientWait = 20000; /* time (ms) after which we decide client has
  89. gone away - needed to stop us hanging */
  90. /*
  91. * rfbInitSockets sets up the TCP and UDP sockets to listen for RFB
  92. * connections. It does nothing if called again.
  93. */
  94. void
  95. rfbInitSockets(rfbScreenInfoPtr rfbScreen)
  96. {
  97. in_addr_t iface = rfbScreen->listenInterface;
  98. if (rfbScreen->socketState!=RFB_SOCKET_INIT)
  99. return;
  100. rfbScreen->socketState = RFB_SOCKET_READY;
  101. if (rfbScreen->inetdSock != -1) {
  102. const int one = 1;
  103. #ifndef WIN32
  104. if (fcntl(rfbScreen->inetdSock, F_SETFL, O_NONBLOCK) < 0) {
  105. rfbLogPerror("fcntl");
  106. return;
  107. }
  108. #endif
  109. if (setsockopt(rfbScreen->inetdSock, IPPROTO_TCP, TCP_NODELAY,
  110. (char *)&one, sizeof(one)) < 0) {
  111. rfbLogPerror("setsockopt");
  112. return;
  113. }
  114. FD_ZERO(&(rfbScreen->allFds));
  115. FD_SET(rfbScreen->inetdSock, &(rfbScreen->allFds));
  116. rfbScreen->maxFd = rfbScreen->inetdSock;
  117. return;
  118. }
  119. if(rfbScreen->autoPort) {
  120. int i;
  121. rfbLog("Autoprobing TCP port \n");
  122. for (i = 5900; i < 6000; i++) {
  123. if ((rfbScreen->listenSock = rfbListenOnTCPPort(i, iface)) >= 0) {
  124. rfbScreen->port = i;
  125. break;
  126. }
  127. }
  128. if (i >= 6000) {
  129. rfbLogPerror("Failure autoprobing");
  130. return;
  131. }
  132. rfbLog("Autoprobing selected port %d\n", rfbScreen->port);
  133. FD_ZERO(&(rfbScreen->allFds));
  134. FD_SET(rfbScreen->listenSock, &(rfbScreen->allFds));
  135. rfbScreen->maxFd = rfbScreen->listenSock;
  136. }
  137. else if(rfbScreen->port>0) {
  138. rfbLog("Listening for VNC connections on TCP port %d\n", rfbScreen->port);
  139. if ((rfbScreen->listenSock = rfbListenOnTCPPort(rfbScreen->port, iface)) < 0) {
  140. rfbLogPerror("ListenOnTCPPort");
  141. return;
  142. }
  143. FD_ZERO(&(rfbScreen->allFds));
  144. FD_SET(rfbScreen->listenSock, &(rfbScreen->allFds));
  145. rfbScreen->maxFd = rfbScreen->listenSock;
  146. }
  147. if (rfbScreen->udpPort != 0) {
  148. rfbLog("rfbInitSockets: listening for input on UDP port %d\n",rfbScreen->udpPort);
  149. if ((rfbScreen->udpSock = rfbListenOnUDPPort(rfbScreen->udpPort, iface)) < 0) {
  150. rfbLogPerror("ListenOnUDPPort");
  151. return;
  152. }
  153. FD_SET(rfbScreen->udpSock, &(rfbScreen->allFds));
  154. rfbScreen->maxFd = max((int)rfbScreen->udpSock,rfbScreen->maxFd);
  155. }
  156. }
  157. void rfbShutdownSockets(rfbScreenInfoPtr rfbScreen)
  158. {
  159. if (rfbScreen->socketState!=RFB_SOCKET_READY)
  160. return;
  161. rfbScreen->socketState = RFB_SOCKET_SHUTDOWN;
  162. if(rfbScreen->inetdSock>-1) {
  163. closesocket(rfbScreen->inetdSock);
  164. FD_CLR(rfbScreen->inetdSock,&rfbScreen->allFds);
  165. rfbScreen->inetdSock=-1;
  166. }
  167. if(rfbScreen->listenSock>-1) {
  168. closesocket(rfbScreen->listenSock);
  169. FD_CLR(rfbScreen->listenSock,&rfbScreen->allFds);
  170. rfbScreen->listenSock=-1;
  171. }
  172. if(rfbScreen->udpSock>-1) {
  173. closesocket(rfbScreen->udpSock);
  174. FD_CLR(rfbScreen->udpSock,&rfbScreen->allFds);
  175. rfbScreen->udpSock=-1;
  176. }
  177. }
  178. /*
  179. * rfbCheckFds is called from ProcessInputEvents to check for input on the RFB
  180. * socket(s). If there is input to process, the appropriate function in the
  181. * RFB server code will be called (rfbNewClientConnection,
  182. * rfbProcessClientMessage, etc).
  183. */
  184. int
  185. rfbCheckFds(rfbScreenInfoPtr rfbScreen,long usec)
  186. {
  187. int nfds;
  188. fd_set fds;
  189. struct timeval tv;
  190. struct sockaddr_in addr;
  191. socklen_t addrlen = sizeof(addr);
  192. char buf[6];
  193. const int one = 1;
  194. int sock;
  195. rfbClientIteratorPtr i;
  196. rfbClientPtr cl;
  197. int result = 0;
  198. if (!rfbScreen->inetdInitDone && rfbScreen->inetdSock != -1) {
  199. rfbNewClientConnection(rfbScreen,rfbScreen->inetdSock);
  200. rfbScreen->inetdInitDone = TRUE;
  201. }
  202. do {
  203. memcpy((char *)&fds, (char *)&(rfbScreen->allFds), sizeof(fd_set));
  204. tv.tv_sec = 0;
  205. tv.tv_usec = usec;
  206. nfds = select(rfbScreen->maxFd + 1, &fds, NULL, NULL /* &fds */, &tv);
  207. if (nfds == 0) {
  208. /* timed out, check for async events */
  209. i = rfbGetClientIterator(rfbScreen);
  210. while((cl = rfbClientIteratorNext(i))) {
  211. if (cl->onHold)
  212. continue;
  213. if (FD_ISSET(cl->sock, &(rfbScreen->allFds)))
  214. rfbSendFileTransferChunk(cl);
  215. }
  216. rfbReleaseClientIterator(i);
  217. return result;
  218. }
  219. if (nfds < 0) {
  220. #ifdef WIN32
  221. errno = WSAGetLastError();
  222. #endif
  223. if (errno != EINTR)
  224. rfbLogPerror("rfbCheckFds: select");
  225. return -1;
  226. }
  227. result += nfds;
  228. if (rfbScreen->listenSock != -1 && FD_ISSET(rfbScreen->listenSock, &fds)) {
  229. if ((sock = accept(rfbScreen->listenSock,
  230. (struct sockaddr *)&addr, &addrlen)) < 0) {
  231. rfbLogPerror("rfbCheckFds: accept");
  232. return -1;
  233. }
  234. #ifndef WIN32
  235. if (fcntl(sock, F_SETFL, O_NONBLOCK) < 0) {
  236. rfbLogPerror("rfbCheckFds: fcntl");
  237. closesocket(sock);
  238. return -1;
  239. }
  240. #endif
  241. if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY,
  242. (char *)&one, sizeof(one)) < 0) {
  243. rfbLogPerror("rfbCheckFds: setsockopt");
  244. closesocket(sock);
  245. return -1;
  246. }
  247. #ifdef USE_LIBWRAP
  248. if(!hosts_ctl("vnc",STRING_UNKNOWN,inet_ntoa(addr.sin_addr),
  249. STRING_UNKNOWN)) {
  250. rfbLog("Rejected connection from client %s\n",
  251. inet_ntoa(addr.sin_addr));
  252. closesocket(sock);
  253. return -1;
  254. }
  255. #endif
  256. rfbLog("Got connection from client %s\n", inet_ntoa(addr.sin_addr));
  257. rfbNewClient(rfbScreen,sock);
  258. FD_CLR(rfbScreen->listenSock, &fds);
  259. if (--nfds == 0)
  260. return result;
  261. }
  262. if ((rfbScreen->udpSock != -1) && FD_ISSET(rfbScreen->udpSock, &fds)) {
  263. if(!rfbScreen->udpClient)
  264. rfbNewUDPClient(rfbScreen);
  265. if (recvfrom(rfbScreen->udpSock, buf, 1, MSG_PEEK,
  266. (struct sockaddr *)&addr, &addrlen) < 0) {
  267. rfbLogPerror("rfbCheckFds: UDP: recvfrom");
  268. rfbDisconnectUDPSock(rfbScreen);
  269. rfbScreen->udpSockConnected = FALSE;
  270. } else {
  271. if (!rfbScreen->udpSockConnected ||
  272. (memcmp(&addr, &rfbScreen->udpRemoteAddr, addrlen) != 0))
  273. {
  274. /* new remote end */
  275. rfbLog("rfbCheckFds: UDP: got connection\n");
  276. memcpy(&rfbScreen->udpRemoteAddr, &addr, addrlen);
  277. rfbScreen->udpSockConnected = TRUE;
  278. if (connect(rfbScreen->udpSock,
  279. (struct sockaddr *)&addr, addrlen) < 0) {
  280. rfbLogPerror("rfbCheckFds: UDP: connect");
  281. rfbDisconnectUDPSock(rfbScreen);
  282. return -1;
  283. }
  284. rfbNewUDPConnection(rfbScreen,rfbScreen->udpSock);
  285. }
  286. rfbProcessUDPInput(rfbScreen);
  287. }
  288. FD_CLR(rfbScreen->udpSock, &fds);
  289. if (--nfds == 0)
  290. return result;
  291. }
  292. i = rfbGetClientIterator(rfbScreen);
  293. while((cl = rfbClientIteratorNext(i))) {
  294. if (cl->onHold)
  295. continue;
  296. if (FD_ISSET(cl->sock, &(rfbScreen->allFds)))
  297. {
  298. if (FD_ISSET(cl->sock, &fds))
  299. rfbProcessClientMessage(cl);
  300. else
  301. rfbSendFileTransferChunk(cl);
  302. }
  303. }
  304. rfbReleaseClientIterator(i);
  305. } while(rfbScreen->handleEventsEagerly);
  306. return result;
  307. }
  308. void
  309. rfbDisconnectUDPSock(rfbScreenInfoPtr rfbScreen)
  310. {
  311. rfbScreen->udpSockConnected = FALSE;
  312. }
  313. void
  314. rfbCloseClient(rfbClientPtr cl)
  315. {
  316. rfbExtensionData* extension;
  317. for(extension=cl->extensions; extension; extension=extension->next)
  318. if(extension->extension->close)
  319. extension->extension->close(cl, extension->data);
  320. LOCK(cl->updateMutex);
  321. #ifdef LIBVNCSERVER_HAVE_LIBPTHREAD
  322. if (cl->sock != -1)
  323. #endif
  324. {
  325. FD_CLR(cl->sock,&(cl->screen->allFds));
  326. if(cl->sock==cl->screen->maxFd)
  327. while(cl->screen->maxFd>0
  328. && !FD_ISSET(cl->screen->maxFd,&(cl->screen->allFds)))
  329. cl->screen->maxFd--;
  330. #ifndef __MINGW32__
  331. shutdown(cl->sock,SHUT_RDWR);
  332. #endif
  333. closesocket(cl->sock);
  334. cl->sock = -1;
  335. }
  336. TSIGNAL(cl->updateCond);
  337. UNLOCK(cl->updateMutex);
  338. }
  339. /*
  340. * rfbConnect is called to make a connection out to a given TCP address.
  341. */
  342. int
  343. rfbConnect(rfbScreenInfoPtr rfbScreen,
  344. char *host,
  345. int port)
  346. {
  347. int sock;
  348. int one = 1;
  349. rfbLog("Making connection to client on host %s port %d\n",
  350. host,port);
  351. if ((sock = rfbConnectToTcpAddr(host, port)) < 0) {
  352. rfbLogPerror("connection failed");
  353. return -1;
  354. }
  355. #ifndef WIN32
  356. if (fcntl(sock, F_SETFL, O_NONBLOCK) < 0) {
  357. rfbLogPerror("fcntl failed");
  358. closesocket(sock);
  359. return -1;
  360. }
  361. #endif
  362. if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY,
  363. (char *)&one, sizeof(one)) < 0) {
  364. rfbLogPerror("setsockopt failed");
  365. closesocket(sock);
  366. return -1;
  367. }
  368. /* AddEnabledDevice(sock); */
  369. FD_SET(sock, &rfbScreen->allFds);
  370. rfbScreen->maxFd = max(sock,rfbScreen->maxFd);
  371. return sock;
  372. }
  373. /*
  374. * ReadExact reads an exact number of bytes from a client. Returns 1 if
  375. * those bytes have been read, 0 if the other end has closed, or -1 if an error
  376. * occurred (errno is set to ETIMEDOUT if it timed out).
  377. */
  378. int
  379. rfbReadExactTimeout(rfbClientPtr cl, char* buf, int len, int timeout)
  380. {
  381. int sock = cl->sock;
  382. int n;
  383. fd_set fds;
  384. struct timeval tv;
  385. while (len > 0) {
  386. n = read(sock, buf, len);
  387. if (n > 0) {
  388. buf += n;
  389. len -= n;
  390. } else if (n == 0) {
  391. return 0;
  392. } else {
  393. #ifdef WIN32
  394. errno = WSAGetLastError();
  395. #endif
  396. if (errno == EINTR)
  397. continue;
  398. #ifdef LIBVNCSERVER_ENOENT_WORKAROUND
  399. if (errno != ENOENT)
  400. #endif
  401. if (errno != EWOULDBLOCK && errno != EAGAIN) {
  402. return n;
  403. }
  404. FD_ZERO(&fds);
  405. FD_SET(sock, &fds);
  406. tv.tv_sec = timeout / 1000;
  407. tv.tv_usec = (timeout % 1000) * 1000;
  408. n = select(sock+1, &fds, NULL, &fds, &tv);
  409. if (n < 0) {
  410. rfbLogPerror("ReadExact: select");
  411. return n;
  412. }
  413. if (n == 0) {
  414. errno = ETIMEDOUT;
  415. return -1;
  416. }
  417. }
  418. }
  419. #undef DEBUG_READ_EXACT
  420. #ifdef DEBUG_READ_EXACT
  421. rfbLog("ReadExact %d bytes\n",len);
  422. for(n=0;n<len;n++)
  423. fprintf(stderr,"%02x ",(unsigned char)buf[n]);
  424. fprintf(stderr,"\n");
  425. #endif
  426. return 1;
  427. }
  428. int rfbReadExact(rfbClientPtr cl,char* buf,int len)
  429. {
  430. return(rfbReadExactTimeout(cl,buf,len,rfbMaxClientWait));
  431. }
  432. /*
  433. * WriteExact writes an exact number of bytes to a client. Returns 1 if
  434. * those bytes have been written, or -1 if an error occurred (errno is set to
  435. * ETIMEDOUT if it timed out).
  436. */
  437. int
  438. rfbWriteExact(rfbClientPtr cl,
  439. const char *buf,
  440. int len)
  441. {
  442. int sock = cl->sock;
  443. int n;
  444. fd_set fds;
  445. struct timeval tv;
  446. int totalTimeWaited = 0;
  447. #undef DEBUG_WRITE_EXACT
  448. #ifdef DEBUG_WRITE_EXACT
  449. rfbLog("WriteExact %d bytes\n",len);
  450. for(n=0;n<len;n++)
  451. fprintf(stderr,"%02x ",(unsigned char)buf[n]);
  452. fprintf(stderr,"\n");
  453. #endif
  454. LOCK(cl->outputMutex);
  455. while (len > 0) {
  456. n = write(sock, buf, len);
  457. if (n > 0) {
  458. buf += n;
  459. len -= n;
  460. } else if (n == 0) {
  461. rfbErr("WriteExact: write returned 0?\n");
  462. return 0;
  463. } else {
  464. #ifdef WIN32
  465. errno = WSAGetLastError();
  466. #endif
  467. if (errno == EINTR)
  468. continue;
  469. if (errno != EWOULDBLOCK && errno != EAGAIN) {
  470. UNLOCK(cl->outputMutex);
  471. return n;
  472. }
  473. /* Retry every 5 seconds until we exceed rfbMaxClientWait. We
  474. need to do this because select doesn't necessarily return
  475. immediately when the other end has gone away */
  476. FD_ZERO(&fds);
  477. FD_SET(sock, &fds);
  478. tv.tv_sec = 5;
  479. tv.tv_usec = 0;
  480. n = select(sock+1, NULL, &fds, NULL /* &fds */, &tv);
  481. if (n < 0) {
  482. if(errno==EINTR)
  483. continue;
  484. rfbLogPerror("WriteExact: select");
  485. UNLOCK(cl->outputMutex);
  486. return n;
  487. }
  488. if (n == 0) {
  489. totalTimeWaited += 5000;
  490. if (totalTimeWaited >= rfbMaxClientWait) {
  491. errno = ETIMEDOUT;
  492. UNLOCK(cl->outputMutex);
  493. return -1;
  494. }
  495. } else {
  496. totalTimeWaited = 0;
  497. }
  498. }
  499. }
  500. UNLOCK(cl->outputMutex);
  501. return 1;
  502. }
  503. /* currently private, called by rfbProcessArguments() */
  504. int
  505. rfbStringToAddr(char *str, in_addr_t *addr) {
  506. if (str == NULL || *str == '\0' || strcmp(str, "any") == 0) {
  507. *addr = htonl(INADDR_ANY);
  508. } else if (strcmp(str, "localhost") == 0) {
  509. *addr = htonl(INADDR_LOOPBACK);
  510. } else {
  511. struct hostent *hp;
  512. if ((*addr = inet_addr(str)) == htonl(INADDR_NONE)) {
  513. if (!(hp = gethostbyname(str))) {
  514. return 0;
  515. }
  516. *addr = *(unsigned long *)hp->h_addr;
  517. }
  518. }
  519. return 1;
  520. }
  521. int
  522. rfbListenOnTCPPort(int port,
  523. in_addr_t iface)
  524. {
  525. struct sockaddr_in addr;
  526. int sock;
  527. int one = 1;
  528. memset(&addr, 0, sizeof(addr));
  529. addr.sin_family = AF_INET;
  530. addr.sin_port = htons(port);
  531. addr.sin_addr.s_addr = iface;
  532. if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
  533. return -1;
  534. }
  535. if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
  536. (char *)&one, sizeof(one)) < 0) {
  537. closesocket(sock);
  538. return -1;
  539. }
  540. if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
  541. closesocket(sock);
  542. return -1;
  543. }
  544. if (listen(sock, 5) < 0) {
  545. closesocket(sock);
  546. return -1;
  547. }
  548. return sock;
  549. }
  550. int
  551. rfbConnectToTcpAddr(char *host,
  552. int port)
  553. {
  554. struct hostent *hp;
  555. int sock;
  556. struct sockaddr_in addr;
  557. memset(&addr, 0, sizeof(addr));
  558. addr.sin_family = AF_INET;
  559. addr.sin_port = htons(port);
  560. if ((addr.sin_addr.s_addr = inet_addr(host)) == htonl(INADDR_NONE))
  561. {
  562. if (!(hp = gethostbyname(host))) {
  563. errno = EINVAL;
  564. return -1;
  565. }
  566. addr.sin_addr.s_addr = *(unsigned long *)hp->h_addr;
  567. }
  568. if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
  569. return -1;
  570. }
  571. if (connect(sock, (struct sockaddr *)&addr, (sizeof(addr))) < 0) {
  572. closesocket(sock);
  573. return -1;
  574. }
  575. return sock;
  576. }
  577. int
  578. rfbListenOnUDPPort(int port,
  579. in_addr_t iface)
  580. {
  581. struct sockaddr_in addr;
  582. int sock;
  583. int one = 1;
  584. memset(&addr, 0, sizeof(addr));
  585. addr.sin_family = AF_INET;
  586. addr.sin_port = htons(port);
  587. addr.sin_addr.s_addr = iface;
  588. if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
  589. return -1;
  590. }
  591. if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
  592. (char *)&one, sizeof(one)) < 0) {
  593. return -1;
  594. }
  595. if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
  596. return -1;
  597. }
  598. return sock;
  599. }