home *** CD-ROM | disk | FTP | other *** search
/ Nebula 1995 August / NEBULA.bin / SourceCode / MiscKit1.2.6 / Source / MiscINETSocket.m < prev    next >
Encoding:
Text File  |  1994-05-15  |  15.8 KB  |  652 lines

  1. /*  Class for handling sockets in the Internet domain.
  2.  *
  3.  *  Copyright (c) 1994 Christopher J. Kane.
  4.  *
  5.  *  This software is subject to the terms of the MiscKit license
  6.  *  agreement. Refer to the license document included with the
  7.  *  MiscKit distribution for these terms.
  8.  *
  9.  *  Version 1.0 BETA (26 April 1994)
  10.  */
  11.  
  12. #import <misckit/MiscINETSocket.h>
  13. #import <objc/HashTable.h>
  14. #import <libc.h>
  15. #import <netdb.h>
  16. #import <netinet/in_systm.h>
  17. #import <netinet/ip.h>
  18. #import <netinet/ip_icmp.h>
  19. #import <netinet/tcp.h>
  20. #import <sys/errno.h>
  21. extern int errno;
  22.  
  23. static MiscINETSocket *handySocket = nil;
  24.  
  25. static unsigned short in_cksum(unsigned char *cp, int nbytes)
  26. {
  27.     unsigned short wa[(nbytes>>1)+1], *wp, result;
  28.     long sum;
  29.     wp = &wa[0];
  30.     memset((char *)wp, 0, sizeof(wp));
  31.     memcpy((char *)wp, cp, nbytes);
  32.     for (sum = 0; 0 < nbytes; nbytes -= 2)
  33.         sum += *wp++;
  34.     while (sum >> 16)
  35.         sum = (sum >> 16) + (sum & 0xffff);
  36.     result = (unsigned short)~sum;
  37.     if (result == 0x0)
  38.         result = 0xffff;
  39.     return result;
  40. }
  41.  
  42. static int wait_for_socket_read(int sock, unsigned int ms)
  43. {
  44.     struct timeval timeout = {ms/1000, (ms%1000)*1000};
  45.     fd_set rfds;
  46.     int ret;
  47.     FD_ZERO(&rfds);
  48.     FD_SET(sock, &rfds);
  49.     while ((ret = select(sock+1, &rfds, NULL, NULL, (ms==0 ? NULL : &timeout))) < 0) {
  50.         if (errno == EINTR)
  51.             continue;
  52.         return -1;
  53.     }
  54.     return ret;
  55. }
  56.  
  57. static int get_service_port(const char *service, int type)
  58. {
  59.     struct servent *sent;
  60.     switch (type) {
  61.     case MiscSOCK_DGRAM :
  62.         sent = getservbyname((char *)service, "udp");
  63.         if (sent == NULL)
  64.             sent = getservbyport(atoi(service), "udp");
  65.         break;
  66.     case MiscSOCK_STREAM:
  67.         sent = getservbyname((char *)service, "tcp");
  68.         if (sent == NULL)
  69.             sent = getservbyport(atoi(service), "tcp");
  70.         break;
  71.     default    :
  72.         /* RAW connections to services are not supported. */
  73.         errno = ESOCKTNOSUPPORT;
  74.         return -1;
  75.     }
  76.     if (sent == NULL) {
  77.         errno = ENOENT;
  78.         return -1;
  79.     }
  80.     return sent->s_port;
  81. }
  82.  
  83. @implementation MiscINETSocket
  84.  
  85. #define ECHOPKTLEN 32
  86.  
  87. + (int)ping:(MiscINETAddress *)addr timeout:(unsigned int)ms useECHO:(BOOL)aBool
  88. {
  89.     if (addr == nil) {
  90.         errno = EDESTADDRREQ;
  91.         return -1;
  92.     }
  93.     if (aBool) {
  94.         char out_pkt[ECHOPKTLEN], in_pkt[2*ECHOPKTLEN];
  95.         int i, ret, in_len = sizeof(in_pkt);
  96.         for (i = 0; i < ECHOPKTLEN; i++)
  97.             out_pkt[i] = (char)(random()%256);
  98.         ret = [MiscINETSocket sendDgram:out_pkt length:sizeof(out_pkt) to:addr service:"echo" timeout:ms retries:0 withReply:in_pkt length:&in_len];
  99.         if (ret <= 0)
  100.             return ret;
  101.         if (in_len != ECHOPKTLEN)
  102.             return -1;
  103.         for (i = 0; i < ECHOPKTLEN; i++)
  104.             if (out_pkt[i] != in_pkt[i])
  105.                 return -1;
  106.         return 1;
  107.     } else {
  108.         struct {
  109.             unsigned char type, code;
  110.             unsigned short cksum, id, seq;
  111.             unsigned char data[2*ICMP_MINLEN];
  112.         } out_pkt = {ICMP_ECHO, 0, 0, getpid() & 0xffff, 1};
  113.         struct sockaddr_in sockaddr;
  114.         char buffer[sizeof(out_pkt)+64];
  115.         int ret;
  116.         struct icmp *icmpp;
  117.         if (handySocket == nil)
  118.             handySocket = [MiscINETSocket alloc];
  119.         handySocket = [handySocket init];
  120.         handySocket->sock = socket(PF_INET, SOCK_RAW, IPPROTO_ICMP);
  121.         if (handySocket->sock < 0)
  122.             return -1;
  123.         handySocket->domain = PF_INET;
  124.         handySocket->type = RAW;
  125.         out_pkt.cksum = in_cksum((u_char *)&out_pkt, sizeof(out_pkt));
  126.         sockaddr.sin_family = AF_INET;
  127.         sockaddr.sin_addr = [addr address];
  128.         sockaddr.sin_port = 0;
  129.         if (sendto(handySocket->sock, &out_pkt, sizeof(out_pkt), 0, (struct sockaddr *)&sockaddr, sizeof(sockaddr)) < 0)
  130.             return -1;
  131.         ret = wait_for_socket_read(handySocket->sock, ms);
  132.         if (ret <= 0)
  133.             return ret;
  134.         memset(buffer, '\0', sizeof(buffer));
  135.         if (recv(handySocket->sock, buffer, sizeof(buffer), 0) < 0)
  136.             return -1;
  137.         icmpp = (struct icmp *)(buffer + 4*((struct ip *)buffer)->ip_hl);
  138.         if (icmpp->icmp_type == ICMP_ECHOREPLY && icmpp->icmp_id == (getpid() & 0xffff))
  139.             return 1;
  140.         return -1;
  141.     }
  142. }
  143.  
  144. + runServer:(id)sockets target:(id)target action:(SEL)action fork:(BOOL)fFlag loop:(BOOL)lFlag
  145. {
  146.     BOOL isCollection = NO;
  147.     fd_set fds;
  148.     int fd, nfd;
  149.     if (![target respondsTo:action] || sockets == nil) {
  150.         errno = EINVAL;
  151.         return nil;
  152.     }
  153.     FD_ZERO(&fds);
  154.     if ([sockets isKindOf:[HashTable class]]) {
  155.         Class Socket = [MiscSocket class];
  156.         for (fd = sizeof(fds)*8; fd--;) {
  157.             id obj;
  158.             if (![sockets isKey:(void *)fd])
  159.                 continue;
  160.             obj = [sockets valueForKey:(void *)fd];
  161.             if ([obj isKindOf:Socket] && ![obj isClosed])
  162.                 FD_SET([obj socket], &fds);
  163.         }
  164.         isCollection = YES;
  165.     } else if ([sockets isKindOf:[MiscSocket class]] && ![sockets isClosed]) {
  166.         FD_SET([sockets socket], &fds);
  167.     } else {
  168.         return nil;
  169.     }
  170.     for (fd = sizeof(fds)*8; fd--;)
  171.         if (FD_ISSET(fd, &fds))
  172.             break;
  173.     nfd = fd + 1;
  174.     if (nfd <= 0) {
  175.         errno = EINVAL;
  176.         return nil;
  177.     }
  178.     do {
  179.         fd_set rfds;
  180.         id sock_obj;
  181.         memcpy(&rfds, &fds, sizeof(rfds));
  182.         if (select(nfd, &rfds, NULL, NULL, NULL) < 0) {
  183.             if (errno == EINTR)
  184.                 continue;
  185.             return nil;
  186.         }
  187.         for (fd = 0; fd < nfd; fd++) {
  188.             if (!FD_ISSET(fd, &rfds))
  189.                 continue;
  190.             sock_obj = isCollection ? (id)[sockets valueForKey:(void *)fd] : sockets;
  191.             if ([sock_obj type] == MiscSOCK_STREAM)
  192.                 if ([sock_obj acceptNewConnection:&sock_obj timeout:0] < 0)
  193.                     return nil;
  194.             if (fFlag) {
  195.                 switch (fork()) {
  196.                 case -1:
  197.                     return nil;
  198.                 case 0 :
  199.                     [target perform:action with:sock_obj];
  200.                     exit(0);
  201.                 }
  202.             } else
  203.                 [target perform:action with:sock_obj];
  204.             if ([sock_obj type] == MiscSOCK_STREAM)
  205.                 [sock_obj free];
  206.         }
  207.     } while (lFlag);
  208.     return self;
  209. }
  210.  
  211. + sendDgram:(void *)data length:(int)dlen to:(MiscINETAddress *)addr port:(int)portNum
  212. {
  213.     struct sockaddr_in sockaddr;
  214.     if (addr == nil) {
  215.         errno = EDESTADDRREQ;
  216.         return nil;
  217.     }
  218.     if (handySocket == nil)
  219.         handySocket = [MiscINETSocket alloc];
  220.     handySocket = [handySocket initDomain:PF_INET type:MiscSOCK_DGRAM];
  221.     if (handySocket == nil || portNum < 0)
  222.         return nil;
  223.     sockaddr.sin_family = AF_INET;
  224.     sockaddr.sin_addr = [addr address];
  225.     sockaddr.sin_port = htons((short)(portNum & 0xffff));
  226.     if (sendto(handySocket->sock, data, dlen, 0, (struct sockaddr *)&sockaddr, sizeof(sockaddr)) < 0)
  227.         return nil;
  228.     return self;
  229. }
  230.  
  231. + sendDgram:(void *)data length:(int)dlen to:(MiscINETAddress *)addr service:(const char *)service
  232. {
  233.     return [self sendDgram:data length:dlen to:addr port:get_service_port(service, MiscSOCK_DGRAM)];
  234. }
  235.  
  236. + (int)sendDgram:(void *)data length:(int)dlen to:(MiscINETAddress *)addr port:(int)portNum timeout:(unsigned int)ms retries:(int)retries withReply:(void *)repl length:(int *)rlen
  237. {
  238.     struct sockaddr_in to_addr;
  239.     if (addr == nil) {
  240.         errno = EDESTADDRREQ;
  241.         return -1;
  242.     }
  243.     if (handySocket == nil)
  244.         handySocket = [MiscINETSocket alloc];
  245.     handySocket = [handySocket initDomain:PF_INET type:MiscSOCK_DGRAM];
  246.     if (handySocket == nil || portNum < 0)
  247.         return -1;
  248.     to_addr.sin_family = AF_INET;
  249.     to_addr.sin_addr = [addr address];
  250.     to_addr.sin_port = htons((short)(portNum & 0xffff));
  251.     do {
  252.         int ret;
  253.         if (sendto(handySocket->sock, data, dlen, 0, (struct sockaddr *)&to_addr, sizeof(to_addr)) < 0)
  254.             return -1;
  255.         ret = wait_for_socket_read(handySocket->sock, ms);
  256.         if (ret < 0)
  257.             return -1;
  258.         if (0 < ret) {
  259.             struct sockaddr_in from_addr;
  260.             int len = sizeof(from_addr);
  261.             ret = recvfrom(handySocket->sock, repl, *rlen, 0, (struct sockaddr *)&from_addr, &len);
  262.             if (ret < 0)
  263.                 return -1;
  264.             if (!memcmp(&to_addr, &from_addr, len-sizeof(to_addr.sin_zero))) {
  265.                 *rlen = ret;
  266.                 return 1;
  267.             }
  268.         }
  269.     } while (retries-- > 0);
  270.     return 0;
  271. }
  272.  
  273. + (int)sendDgram:(void *)data length:(int)dlen to:(MiscINETAddress *)addr service:(const char *)service timeout:(unsigned int)ms retries:(int)retries withReply:(void *)repl length:(int *)rlen
  274. {
  275.     return [self sendDgram:data length:dlen to:addr port:get_service_port(service, MiscSOCK_DGRAM) timeout:ms retries:retries withReply:repl length:rlen];
  276. }
  277.  
  278. - init
  279. {
  280.     [super init];
  281.     if (localAddress != nil)
  282.         localAddress = [localAddress free];
  283.     if (remoteAddress != nil)
  284.         remoteAddress = [remoteAddress free];
  285.     localPortNum = remotePortNum = -1;
  286.     return self;
  287. }
  288.  
  289. - copyFromZone:(NXZone *)zone
  290. {
  291.     MiscINETSocket *copy = [super copyFromZone:zone];
  292.     copy->localAddress = [localAddress copyFromZone:zone];
  293.     copy->remoteAddress = [remoteAddress copyFromZone:zone];
  294.     return copy;
  295. }
  296.  
  297. - read:(NXTypedStream *)stream;
  298. {
  299.     [super read:stream];
  300.     localAddress = NXReadObject(stream);
  301.     NXReadType(stream, "i", &localPortNum);
  302.     remoteAddress = NXReadObject(stream);
  303.     NXReadType(stream, "i", &remotePortNum);
  304.     return self;
  305. }
  306.  
  307. - write:(NXTypedStream *)stream
  308. {
  309.     [super write:stream];
  310.     NXWriteRootObject(stream, localAddress);
  311.     NXWriteType(stream, "i", &localPortNum);
  312.     NXWriteRootObject(stream, remoteAddress);
  313.     NXWriteType(stream, "i", &remotePortNum);
  314.     return self;
  315. }
  316.  
  317. - (int)acceptNewConnection:(MiscINETSocket **)newSocket timeout:(unsigned int)ms
  318. {
  319.     int ret;
  320.     *newSocket = nil;
  321.     if (type != MiscSOCK_STREAM) {
  322.         errno = EINVAL;
  323.         return -1;
  324.     }
  325.     ret = wait_for_socket_read(sock, ms);
  326.     if (0 < ret) {
  327.         struct sockaddr_in sockaddr;
  328.         int len = sizeof(sockaddr);
  329.         ret = accept(sock, (struct sockaddr *)&sockaddr, &len);
  330.         if (0 <= ret) {
  331.             *newSocket = [[MiscINETSocket alloc] init];
  332.             (*newSocket)->sock = ret;
  333.             (*newSocket)->domain = PF_INET;
  334.             (*newSocket)->type = MiscSOCK_STREAM;
  335.             ret = 1;
  336.         }
  337.     }
  338.     return ret;
  339. }
  340.  
  341. - connectTo:(MiscINETAddress *)addr port:(int)portNum type:(int)aType
  342. {
  343.     struct sockaddr_in sockaddr;
  344.     if (addr == nil) {
  345.         errno = EDESTADDRREQ;
  346.         return [self free];
  347.     }
  348.     self = [self initDomain:PF_INET type:aType];
  349.     if (self == nil || portNum < 0)
  350.         return [self free];
  351.     sockaddr.sin_family = AF_INET;
  352.     sockaddr.sin_addr = [addr address];
  353.     sockaddr.sin_port = htons((short)(portNum & 0xffff));
  354.     if (connect(sock, (struct sockaddr *)&sockaddr, sizeof(sockaddr)) < 0)
  355.         return [self free];
  356.     return self;
  357. }
  358.  
  359. - connectTo:(MiscINETAddress *)addr service:(const char *)service type:(int)aType
  360. {
  361.     return [self connectTo:addr port:get_service_port(service, aType) type:aType];
  362. }
  363.  
  364. - openServerPort:(int *)portNum type:(int)aType
  365. {
  366.     struct sockaddr_in sockaddr;
  367.     int on = 1, old_errno = errno;
  368.     self = [self initDomain:PF_INET type:aType];
  369.     if (self == nil || *portNum < 0)
  370.         return [self free];
  371.     setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on));
  372.     errno = old_errno;
  373.     sockaddr.sin_family = AF_INET;
  374.     sockaddr.sin_port = htons((short)(*portNum & 0xffff));
  375.     sockaddr.sin_addr.s_addr = INADDR_ANY;
  376.     if (bind(sock, (struct sockaddr *)&sockaddr, sizeof(sockaddr)) < 0)
  377.         return [self free];
  378.     if (aType == MiscSOCK_STREAM)
  379.         listen(sock, 2);
  380.     return self;
  381. }
  382.  
  383. - openServerService:(const char *)service type:(int)aType
  384. {
  385.     int port = get_service_port(service, aType);
  386.     if (port < 0)
  387.         return [self free];
  388.     return [self openServerPort:&port type:aType];
  389. }
  390.  
  391. - (int)receiveData:(void *)data length:(int *)dlen
  392. {
  393.     return [self receiveData:data length:dlen timeout:0 from:nil port:NULL];
  394. }
  395.  
  396. - (int)receiveData:(void *)data length:(int *)dlen timeout:(unsigned int)ms from:(MiscINETAddress *)addr port:(int *)port
  397. {
  398.     int ret = wait_for_socket_read(sock, ms);
  399.     if (0 <= ret) {
  400.         struct sockaddr_in sockaddr;
  401.         int len = sizeof(sockaddr);
  402.         ret = recvfrom(sock, data, *dlen, 0, (struct sockaddr *)&sockaddr, &len);
  403.         if (0 == ret) {
  404.             [self close];
  405.             errno = EPIPE;
  406.             ret = -1;
  407.         } else if (0 < ret) {
  408.             [addr initTo:sockaddr.sin_addr];
  409.             *dlen = ret;
  410.             if (port != NULL)
  411.                 *port = (int)ntohs(sockaddr.sin_port);
  412.             ret = 1;
  413.         }
  414.     }
  415.     return ret;
  416. }
  417.  
  418. - (int)receiveData:(void *)data length:(int *)dlen timeout:(unsigned int)ms toNext:(unsigned char)sentinel
  419. {
  420.     struct timeval t1, t2;
  421.     int i, ret;
  422.     if (type != MiscSOCK_STREAM) {
  423.         errno = EINVAL;
  424.         return -1;
  425.     }
  426.     gettimeofday(&t1, NULL);
  427.     for (i = *dlen, *dlen = 0; i--;) {
  428.         if (0 < ms) {
  429.             int ms_left;
  430.             gettimeofday(&t2, NULL);
  431.             ms_left = ms - 1000*(t2.tv_sec-t1.tv_sec) + (t2.tv_usec-t1.tv_usec)/1000;
  432.             if (ms_left < 1)
  433.                 return 0;
  434.             ret = wait_for_socket_read(sock, ms_left);
  435.             if (ret <= 0)
  436.                 return ret;
  437.         }
  438.         ret = read(sock, data, 1);
  439.         if (ret < 0)
  440.             return -1;
  441.         else if (0 == ret) {
  442.             [self close];
  443.             errno = EPIPE;
  444.             return -1;
  445.         } 
  446.         (*dlen)++;
  447.         if (*(unsigned char *)data == sentinel)
  448.             return 1;
  449.         data++;
  450.     }
  451.     return 1;
  452. }
  453.  
  454. - sendData:(void *)data length:(int)dlen
  455. {
  456.     while (0 < dlen) {
  457.         int ret = write(sock, data, dlen);
  458.         if (ret <= 0) {
  459.             if (errno == EINTR)
  460.                 continue;
  461.             else if (errno == EPIPE || errno == 0) {
  462.                 [self close];
  463.                 return nil;
  464.             }
  465.             return nil;
  466.         }
  467.         dlen -= ret;
  468.         data += ret;
  469.     }
  470.     return self;
  471. }
  472.  
  473. - shutdownLocalEnd
  474. {
  475.     if (localAddress != nil)
  476.         localAddress = [localAddress free];
  477.     localPortNum = -1;
  478.     return (shutdown(sock, 1) < 0 ? nil : self);
  479. }
  480.  
  481. - shutdownRemoteEnd
  482. {
  483.     if (remoteAddress != nil)
  484.         remoteAddress = [remoteAddress free];
  485.     remotePortNum = -1;
  486.     return (shutdown(sock, 0) < 0 ? nil : self);
  487. }
  488.  
  489. - enableDebug:(BOOL)aBool
  490. {
  491.     int on = aBool;
  492.     if (![self isClosed]) {
  493.         int size = sizeof(on), old_errno = errno;
  494.         setsockopt(sock, SOL_SOCKET, SO_DEBUG, (char *)&on, size);
  495.         errno = old_errno;
  496.     }
  497.     return self;
  498. }
  499.  
  500. - (BOOL)debugEnabled
  501. {
  502.     int on = NO;
  503.     if (![self isClosed]) {
  504.         int size = sizeof(on), old_errno = errno;
  505.         getsockopt(sock, SOL_SOCKET, SO_DEBUG, (char *)&on, &size);
  506.         errno = old_errno;
  507.     }
  508.     return (BOOL)on;
  509. }
  510.  
  511. - enableDelay:(BOOL)aBool
  512. {
  513.     int on = aBool;
  514.     if (![self isClosed]) {
  515.         int size = sizeof(on), old_errno = errno;
  516.         setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *)&on, size);
  517.         errno = old_errno;
  518.     }
  519.     return self;
  520. }
  521.  
  522. - (BOOL)delayEnabled
  523. {
  524.     int on = YES;
  525.     if (![self isClosed]) {
  526.         int size = sizeof(on), old_errno = errno;
  527.         getsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *)&on, &size);
  528.         errno = old_errno;
  529.     }
  530.     return (BOOL)on;
  531. }
  532.  
  533. - enableKeepAlive:(BOOL)aBool
  534. {
  535.     int on = aBool;
  536.     if (![self isClosed]) {
  537.         int size = sizeof(on), old_errno = errno;
  538.         setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (char *)&on, size);
  539.         errno = old_errno;
  540.     }
  541.     return self;
  542. }
  543.  
  544. - (BOOL)keepAliveEnabled
  545. {
  546.     int on = NO;
  547.     if (![self isClosed]) {
  548.         int size = sizeof(on), old_errno = errno;
  549.         getsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (char *)&on, &size);
  550.         errno = old_errno;
  551.     }
  552.     return (BOOL)on;
  553. }
  554.  
  555. - setLingerTime:(int)secs
  556. {
  557.     if (![self isClosed]) {
  558.         struct linger ling;
  559.         int size = sizeof(ling), old_errno = errno;
  560.         ling.l_onoff = 0 < secs ? 1 : 0;
  561.         ling.l_linger = 0 < secs ? secs : 0;
  562.         setsockopt(sock, SOL_SOCKET, SO_LINGER, (char *)&ling, size);
  563.         errno = old_errno;
  564.     }
  565.     return self;
  566. }
  567.  
  568. - (int)lingerTime
  569. {
  570.     int time = 0;
  571.     if (![self isClosed]) {
  572.         struct linger ling;
  573.         int size = sizeof(ling), old_errno = errno;
  574.         getsockopt(sock, SOL_SOCKET, SO_LINGER, (char *)&ling, &size);
  575.         errno = old_errno;
  576.         if (ling.l_onoff)
  577.             time = ling.l_linger;
  578.     }
  579.     return time;
  580. }
  581.  
  582. - (BOOL)dataAvailable
  583. {
  584.     int old_errno = errno;
  585.     BOOL avail = NO;
  586.     if (![self isClosed]) {
  587.         struct timeval timeout = {0, 0};
  588.         fd_set rfds;
  589.         FD_ZERO(&rfds);
  590.         FD_SET(sock, &rfds);
  591.         if (0 < select(sock+1, &rfds, NULL, NULL, &timeout))
  592.             avail = YES;
  593.     }
  594.     errno = old_errno;
  595.     return avail;
  596. }
  597.  
  598. - (MiscINETAddress *)localAddress
  599. {
  600.     if (localAddress == nil) {
  601.         struct sockaddr_in sockaddr;
  602.         int len = sizeof(sockaddr);
  603.         if (getsockname(sock, (struct sockaddr *)&sockaddr, &len) < 0)
  604.             return nil;
  605.         localAddress = [[MiscINETAddress allocFromZone:[self zone]] initTo:sockaddr.sin_addr];
  606.         if (localAddress != nil)
  607.             localPortNum = ntohs(sockaddr.sin_port & 0xffff);
  608.     }
  609.     return localAddress;
  610. }
  611.  
  612. - (int)localPortNum
  613. {
  614.     if (localPortNum == -1)
  615.         [self localAddress];
  616.     return localPortNum;
  617. }
  618.  
  619. - (MiscINETAddress *)remoteAddress
  620. {
  621.     if (remoteAddress == nil) {
  622.         struct sockaddr_in sockaddr;
  623.         int len = sizeof(sockaddr);
  624.         if (getpeername(sock, (struct sockaddr *)&sockaddr, &len) < 0)
  625.             return nil;
  626.         remoteAddress = [[MiscINETAddress allocFromZone:[self zone]] initTo:sockaddr.sin_addr];
  627.         if (remoteAddress != nil)
  628.             remotePortNum = ntohs(sockaddr.sin_port & 0xffff);
  629.     }
  630.     return remoteAddress;
  631. }
  632.  
  633. - (int)remotePortNum
  634. {
  635.     if (remotePortNum == -1)
  636.         [self remoteAddress];
  637.     return remotePortNum;
  638. }
  639.  
  640. - (int)socketError
  641. {
  642.     int err = 0;
  643.     if (![self isClosed]) {
  644.         int size = sizeof(err), old_errno = errno;
  645.         getsockopt(sock, SOL_SOCKET, SO_ERROR, (char *)&err, &size);
  646.         errno = old_errno;
  647.     }
  648.     return err;
  649. }
  650.  
  651. @end
  652.