## modules/sk/sk_socket.c

/* [<][>][^][v][top][bottom][index][help] */

## DEFINITIONS

This source file includes following functions.

1. SK_atoport
2. SK_close
3. SK_getsock
4. SK_accept_connection
5. SK_connect
6. SK_read
7. SK_write
8. SK_gets
9. SK_puts
10. SK_putc
11. SK_getc
12. SK_getpeername
13. SK_getpeerip

       1 /***************************************
       2   $Revision: 1.22 $
       3
       4   Socket module - routines facilitating calls to socket library.
       5
       6   Status: NOT REVUED, TESTED
       7
       8   Basic code adapted by Chris Ottrey from
       9       http://www.ibrado.com/sock-faq/sfaq.html#faq65 - sample source code.
      10   ******************/ /******************
      11   Modification History:
      12         ottrey (08/03/1999) Created from sockhelp.c.
      13         ottrey (08/03/1998) Heavily butchered.
      14         joao   (22/06/1999) Modified socket creation and accepts.
      15         marek  (December 2000) Added connection function w/timeout.
      16   ******************/ /******************
      17   Copyright (c) 1999,2000,2001,2002                     RIPE NCC
      18
      19   All Rights Reserved
      20
      21   Permission to use, copy, modify, and distribute this software and its
      22   documentation for any purpose and without fee is hereby granted,
      23   provided that the above copyright notice appear in all copies and that
      24   both that copyright notice and this permission notice appear in
      25   supporting documentation, and that the name of the author not be
      26   used in advertising or publicity pertaining to distribution of the
      27   software without specific, written prior permission.
      28
      29   THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
      30   ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL
      31   AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
      32   DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
      33   AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
      34   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
      35   ***************************************/
      36
      37 #include "rip.h"
      38
      39 /* SK_atoport() */
      40 /*++++++++++++++++++++++++++++++++++++++
      41    Take a service name, and a service type, and return a port number.  If the
      42    service name is not found, it tries it as a decimal number.  The number
      43    returned is byte ordered for the network.
      44
      45   char *service   Service name (or port number).
      46
      47   char *proto     Protocol (eg "tcp").
      48
      49   Author:
      50         ottrey.
      51
      52   ++++++++++++++++++++++++++++++++++++++*/
      53 int SK_atoport(const char *service, const char *proto) {
         /* [<][>][^][v][top][bottom][index][help] */
      54   unsigned port;
      55   long int lport;
      56   struct servent *serv;
      57   char *errpos;
      58   struct servent result;
      59   char buffer[STR_XXL];
      60
      61   /* First try to read it from /etc/services */
      62
      63 #ifdef __linux__
      64   if(getservbyname_r(service, proto, &result, buffer, sizeof(buffer), &serv) < 0) serv = NULL;
      65 #else
      66   serv = getservbyname_r(service, proto, &result, buffer, sizeof(buffer));
      67 #endif
      68
      69   if (serv != NULL)
      70     port = serv->s_port;
      71   else { /* Not in services, maybe a number? */
      72     lport = strtol(service,&errpos,0);
      73     if ( (errpos[0] != 0) || (lport < 1) || (lport > 65535) )
      74       return -1; /* Invalid port address */
      75     port = htons(lport);
      76   }
      77   return port;
      78 } /* SK_atoport() */
      79
      80
      81 /* SK_close() */
      82 /*++++++++++++++++++++++++++++++++++++++
      83
      84   int SK_close     wrapper around closing the socket. Returns the value
      85                    returned by close(2)
      86
      87   int socket       socket to be closed
      88
      89   Author:
      90         ottrey
      91   ++++++++++++++++++++++++++++++++++++++*/
      92 int SK_close(int socket) {
         /* [<][>][^][v][top][bottom][index][help] */
      93   ER_dbg_va(FAC_SK, ASP_SK_GEN, "Closing socket... %d", socket);
      94
      95   return close(socket);
      96 }
      97
      98 /* SK_getsock() */
      99 /*++++++++++++++++++++++++++++++++++++++
     100
     101    int  SK_getsock        This function creates a socket and binds to it.
     102                           Returns the number of the created
     103                           descriptor/listening socket.
     104
     105    int socket_type        SOCK_STREAM or SOCK_DGRAM (TCP or UDP sockets)
     106
     107    unsigned  port         The port to listen on. Ports < 1024 are
     108                           reserved for the root user. Host byte order.
     109
     110    int backlog            Size of the backlog queue to be set on that
     111                           socket.
     112
     113    uint32_t bind_address  Address to bind to, in network order.
     114
     115   Authors:
     116         ottrey,
     117         joao,
     118         marek (added htons conversion for port).
     119
     120   ++++++++++++++++++++++++++++++++++++++*/
     121 int  SK_getsock(int socket_type, unsigned h_port, int backlog,
         /* [<][>][^][v][top][bottom][index][help] */
     122                 uint32_t bind_address) {
     123   struct sockaddr_in address;
     124   int listening_socket;
     125   int reuse_addr = 1;
     126   u_short port = htons(h_port);
     127
     128   /* Setup internet address information.
     129      This is used with the bind() call */
     130   memset((char *) &address, 0, sizeof(address));
     131   address.sin_family = AF_INET;
     132   address.sin_port = port;
     133   address.sin_addr.s_addr = bind_address;
     134
     135   /* Map all of the signals and exit routine */
     136
     137   listening_socket = socket(AF_INET, socket_type, 0);
     138   if (listening_socket < 0) {
     139     perror("socket");
     140     exit(EXIT_FAILURE);
     141   }
     142
     143   setsockopt(listening_socket, SOL_SOCKET, SO_REUSEADDR, (void *)&reuse_addr, sizeof(reuse_addr));
     144
     145   if (bind(listening_socket, (struct sockaddr *) &address, sizeof(address)) < 0) {
     146     fprintf(stderr,
     147         "error %d with bind() to %s:%d; %s\n",
     148         errno,
     149         inet_ntoa(address.sin_addr),
     150         h_port,
     151         strerror(errno));
     152     close(listening_socket);
     153     exit(EXIT_FAILURE);
     154   }
     155
     156
     157   if (socket_type == SOCK_STREAM) {
     158     listen(listening_socket, backlog); /* Queue up to five connections before
     159                                   having them automatically rejected. */
     160   }
     161
     162   return listening_socket;
     163 } /* SK_getsock() */
     164
     165 /*++++++++++++++++++++++++++++++++++++++
     166
     167    Wait for an incoming connection on the specified socket
     168
     169    int  SK_accept_connection The socket for communicating to the client
     170
     171    int  listening_socket     The socket that the server is bound to
     172
     173   Authors:
     174         joao,
     175         marek.
     176   ++++++++++++++++++++++++++++++++++++++*/
     177 int SK_accept_connection(int listening_socket) {
         /* [<][>][^][v][top][bottom][index][help] */
     178   int connected_socket = -1;
     179   int num_errors = 0;
     180
     181 #define MAX_ACCEPT_ERRORS 3
     182
     183   for (;;) {
     184
     185     ER_dbg_va(FAC_SK, ASP_SK_GEN,
     186               "Going to accept connections on socket : %d",listening_socket);
     187
     188     connected_socket = accept(listening_socket, NULL, NULL);
     189     if (connected_socket < 0) {
     190       /* Either a real error occured, or blocking was interrupted for
     191          some reason.  Only abort execution if a real error occured. */
     192       switch(errno) {
     193       case EINTR:        /* Interrupted system call */
     194       case ECONNABORTED: /* Software caused connection abort */
     195         /* no warning */
     196         continue;    /* don't return - do the accept again */
     197       default:
     198         /* special case: shutdown of the server - just return */
     199         if( CO_get_do_server() == 0 ) {
     200           return -1;
     201         }
     202         else { /* real error */
     203           if( ++num_errors < MAX_ACCEPT_ERRORS ) {
     204             /* warn */
     205             ER_perror(FAC_SK, SK_ACERW, "(%d) %s", errno, strerror(errno));
     206           }
     207           else {
     208             /* crash */
     209             ER_perror(FAC_SK, SK_ACERF,
     210                 "too many accept() errors (maximum is %d)", MAX_ACCEPT_ERRORS);
     211             die;
     212           }
     213         }
     214       }
     215     }
     216     else { /* success */
     217        ER_dbg_va(FAC_SK, ASP_SK_GEN, "client connected on socket %d",
     218             connected_socket
     219             );
     220
     221        return connected_socket;
     222     }
     223
     224   }
     225 }
     226
     227
     228 /*++++++++++++++++++++++++++++++++++++++
     229
     230   er_ret_t SK_connect       wrapper around connect(), doing non-blocking
     231                             connection with timeout
     232
     233   int *sock         pointer to the storage for socket descriptor
     234
     235   char *hostname    host to connect to
     236
     237   int port          port to connect to
     238
     239   int timeout       in seconds
     240
     241   Author: marek
     242
     243   ++++++++++++++++++++++++++++++++++++++*/
     244 er_ret_t SK_connect(int  *sock, char *hostname, unsigned int port, unsigned int timeout)
         /* [<][>][^][v][top][bottom][index][help] */
     245 {
     246   struct sockaddr_in sin;
     247   struct hostent *hp;
     248   int s;
     249   int flags;
     250   struct timeval ptm;
     251   fd_set rset, wset;
     252   int gs, sel, er, erlen=sizeof(er);
     253   int error;
     254   struct hostent result;
     255   char aliasbuf[8192]; /* Stevens, UNIX net. prog., p.304 */
     256
     257   /* look up the host name */
     258 #ifdef __linux__
     259   er = (gethostbyname_r(hostname,  &result, aliasbuf,
     260                         sizeof(aliasbuf), &hp, &error) < 0 );
     261 #else /* default is Solaris implementation */
     262   hp = gethostbyname_r(hostname,  &result, aliasbuf,
     263                        sizeof(aliasbuf), &error);
     264   er = ( hp == NULL );
     265 #endif
     266
     267   if( er ) {
     268     return SK_BADHOST;
     269   }
     270
     271   /* create a socket */
     272   s = socket(AF_INET, SOCK_STREAM, 0);
     273   if (s < 0) {
     274     return SK_SOCKET;
     275   }
     276
     277   /* bind to it */
     278   bzero((caddr_t)&sin, sizeof (sin));
     279   sin.sin_family = hp->h_addrtype;
     280   if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
     281     close(s);
     282     return SK_BIND;
     283   }
     284   bcopy(hp->h_addr, (char *)&sin.sin_addr, hp->h_length);
     285   sin.sin_port=htons(port);
     286
     287   /* connect in non-blocking mode */
     288   flags = fcntl(s, F_GETFL, 0);
     289   fcntl(s, F_SETFL, flags | O_NONBLOCK );
     290
     291   if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0
     292       && errno != EINPROGRESS ) {
     293     close(s);
     294     return SK_CONNECT;
     295   }
     296
     297   /* now wait for success */
     298   FD_ZERO( &rset );
     299   FD_SET( s, &rset );
     300   wset = rset;
     301   ptm.tv_usec = 0;
     302   ptm.tv_sec = timeout;
     303
     304   if( (sel=select(s+1,  &rset, &wset, NULL, &ptm)) == 0 ) {
     305     /* timeout */
     306     close(s);
     307     return SK_TIMEOUT;
     308   }
     309   if (sel < 0) {
     310     close(s);
     311     return SK_CONNECT;
     312   }
     313
     314   gs = getsockopt(s, SOL_SOCKET, SO_ERROR, &er, &erlen);
     315
     316   if( gs < 0 || er ) {   /* Stevens code, p.411 is exceptionally crappy */
     317     close(s);
     318     return SK_CONNECT;
     319   } /* if error */
     320
     321   fcntl(s, F_SETFL, flags);
     322   *sock = s;
     323
     324   return SK_OK;
     325 }
     326
     327
     328 /* XXX: deprecated SK_read(), SK_gets(), and SK_getc(), since these
     329         functions are unused, and do not work with the buffering added
     330         to SK_cd_gets()
     331         - Shane, 2002-05-13 */
     332
     333 #if 0
     334 /* SK_read() */
     335 /*++++++++++++++++++++++++++++++++++++++
     336
     337    This is just like the read() system call, except that it will make
     338    sure that all your data goes through the socket.
     339
     340    int    SK_read   Returns the number of bytes read.
     341
     342    int    sockfd    The socket file descriptor.
     343
     344    char   *buf      The buffer to be read from the socket.
     345
     346    size_t count     The number of bytes in the buffer.
     347
     348   Author:
     349         ottrey
     350
     351   ++++++++++++++++++++++++++++++++++++++*/
     352 int SK_read(int sockfd, char *buf, size_t count) {
         /* [<][>][^][v][top][bottom][index][help] */
     353   size_t bytes_read = 0;
     354   int this_read;
     355
     356   while (bytes_read < count) {
     357     do
     358       this_read = read(sockfd, buf, count - bytes_read);
     359     while ( (this_read < 0) && (errno == EINTR) );
     360     if (this_read < 0)
     361       return this_read;
     362     else if (this_read == 0)
     363       return bytes_read;
     364     bytes_read += this_read;
     365     buf += this_read;
     366   }
     367
     368   return count;
     369
     370 } /* SK_read() */
     371 #endif /* 0 */
     372
     373
     374 /* SK_write() */
     375 /*++++++++++++++++++++++++++++++++++++++
     376
     377    int SK_write   Returns:
     378                      -1 on error
     379                       0 on timeout
     380                       1 on success (all bytes written)
     381
     382    int sockfd                      The socket file descriptor.
     383
     384    const char *buf                 The buffer to be written to the socket.
     385
     386    int count                       The number of bytes in the buffer.
     387
     388    const struct timeval *timeout   Maximum time to wait between each
     389                                    write() call, or NULL for "forever".
     390
     391    int *count_sent                 Set to the number of bytes sucessfully
     392                                    written.  This value is always valid,
     393                                    although it will be less than the
     394                                    total number of bytes to send if
     395                                    the function returns -1 or 0.  NULL
     396                                    may be sent if the caller does not
     397                                    care about the number of bytes sent on
     398                                    failure.
     399
     400   ++++++++++++++++++++++++++++++++++++++*/
     401
     402 int
     403 SK_write(int sockfd,
         /* [<][>][^][v][top][bottom][index][help] */
     404          const char *buf,
     405          int count,
     406          const struct timeval *timeout,
     407          int *count_sent)
     408 {
     409   int     local_count_sent;    /* only used if caller passes NULL */
     410   fd_set  fds;
     411   int     select_ret;
     412   struct  timeval tv;
     413   int     write_ret;
     414
     415   /* copious logging never hurt anybody (well, except people with slow
     416      computers or small hard disks) */
     417   ER_dbg_va(FAC_SK, ASP_SK_WRIT,
     418             "SK_write = { sockfd=[%d], buf=[%s], count=[%d]",
     419             sockfd, buf, count);
     420
     421   /* allow caller to pass NULL if it doesn't care about the count sent */
     422   if (count_sent == NULL) {
     423       count_sent = &local_count_sent;
     424   }
     425
     426   /* loop around until we send all of our data, or we get a timeout or
     427      disconnect */
     428   *count_sent = 0;
     429   while (*count_sent < count) {
     430
     431     /* first, call select() and see if we can write without blocking */
     432     FD_ZERO(&fds);
     433     FD_SET(sockfd, &fds);
     434     if (timeout == NULL) {
     435         select_ret = select(sockfd+1, NULL, &fds, NULL, NULL);
     436     } else {
     437         /* make a copy of timeout, because it's value is undefined
     438            on return from select() */
     439         tv = *timeout;
     440         select_ret = select(sockfd+1, NULL, &fds, NULL, &tv);
     441     }
     442     /* check for error */
     443     if (select_ret < 0) {
     444         /* log the error and return "timeout" */
     445         ER_perror(FAC_SK, SK_SELECT, "(%d) %s", errno, strerror(errno));
     446         return -1;
     447     }
     448     /* check for timeout */
     449     if ((select_ret == 0) || !FD_ISSET(sockfd, &fds)) {
     450         return -1;
     451     }
     452
     453
     454     /* at this point we can safely write */
     455     write_ret = write(sockfd, buf, count - *count_sent);
     456
     457     /* if write failed, assume other side disconnected */
     458     if (write_ret <= 0) {
     459         return 0;
     460     }
     461
     462     /* update our current status */
     463     *count_sent += write_ret;
     464     buf += write_ret;
     465
     466   }
     467
     468   /* all bytes sent, return success */
     469   return 1;
     470 } /* SK_write() */
     471
     472
     473 #if 0
     474 /* SK_gets() */
     475 /*++++++++++++++++++++++++++++++++++++++
     476
     477    This function reads from a socket, until it recieves a linefeed
     478    character.  It fills the buffer "str" up to the maximum size "count".
     479
     480    int SK_gets      Returns the total_count of bytes read.
     481
     482    int    sockfd    The socket file descriptor.
     483
     484    char   *str      The buffer to be written from the socket.
     485
     486    size_t count     The number of bytes in the buffer.
     487
     488
     489   Authors:
     490         ottrey,
     491         marek (modified for meaningful error codes).
     492
     493   Side Effects:
     494         This function will return -1 if the socket is closed during the read operation.
     495
     496         Note that if a single line exceeds the length of count, the extra data
     497         will be read and discarded!  You have been warned.
     498
     499   ++++++++++++++++++++++++++++++++++++++*/
     500 int SK_gets(int  sockfd, char *str, size_t count) {
         /* [<][>][^][v][top][bottom][index][help] */
     501   int bytes_read;
     502   int total_count = 0;
     503   char *current_position;
     504   char last_read = 0;
     505
     506   int control_c = 0;
     507
     508   current_position = str;
     509   while (last_read != 10) {
     510
     511     bytes_read = read(sockfd, &last_read, 1);
     512     if (bytes_read <= 0) {
     513       /* The other side may have closed unexpectedly */
     514       return SK_DISCONNECT;
     515       /* Is this effective on other platforms than linux? */
     516     }
     517     if ( (total_count < count) && (last_read != 10) && (last_read !=13) ) {
     518       *current_position = last_read;
     519       current_position++;
     520       total_count++;
     521     }
     522
     523     if (last_read == -1) {
     524       bytes_read = read(sockfd, &last_read, 1);
     525       if (last_read == -12) {
     526         ER_dbg_va(FAC_SK, ASP_SK_GEN,"Client pressed Control-c");
     527         control_c = 1;
     528         ER_dbg_va(FAC_SK, ASP_SK_GEN,"returning SK_INTERRUPT");
     529         return SK_INTERRUPT;
     530       }
     531     }
     532   }
     533   if (count > 0) {
     534     *current_position = 0;
     535   }
     536
     537   return total_count;
     538
     539 } /* SK_gets() */
     540 #endif /* 0 */
     541
     542
     543 /* SK_puts() */
     544 /*++++++++++++++++++++++++++++++++++++++
     545
     546    This function writes a character string out to a socket.
     547
     548    int SK_puts  The total_count of bytes written,
     549                 or -1 on hangup, error, or timeout
     550
     551    int    sockfd    The socket file descriptor.
     552
     553    char   *str      The buffer to be written from the socket.
     554
     555    const struct timeval *timeout   Maximum time to wait between each
     556                                    write() call, or NULL for "forever".
     557
     558   ++++++++++++++++++++++++++++++++++++++*/
     559 int
     560 SK_puts(int sockfd, const char *str, const struct timeval *timeout)
         /* [<][>][^][v][top][bottom][index][help] */
     561 {
     562   int count_sent;
     563   if (SK_write(sockfd, str, strlen(str), timeout, &count_sent) <= 0) {
     564       return -1;
     565   } else {
     566       return count_sent;
     567   }
     568 } /* SK_puts() */
     569
     570 /* SK_putc() */
     571 /*++++++++++++++++++++++++++++++++++++++
     572
     573   This function writes a single character out to a socket.
     574
     575    int SK_putc       Returns the number of characters written.
     576
     577    int sockfd        socket
     578
     579    char ch           character
     580
     581    const struct timeval *timeout   Maximum time to wait between each
     582                                    write() call, or NULL for "forever".
     583
     584   ++++++++++++++++++++++++++++++++++++++*/
     585 int
     586 SK_putc(int sockfd, char ch, const struct timeval *timeout)
         /* [<][>][^][v][top][bottom][index][help] */
     587 {
     588   int count_sent;
     589   SK_write(sockfd, &ch, 1, timeout, &count_sent);
     590   return count_sent;
     591 }/* SK_putc() */
     592
     593 #if 0
     594 /*++++++++++++++++++++++++++++++++++++++
     595
     596    This function reads a single character from a socket.
     597
     598    returns EOF when no character can be read.
     599
     600   ++++++++++++++++++++++++++++++++++++++*/
     601 int SK_getc(int  sockfd) {
         /* [<][>][^][v][top][bottom][index][help] */
     602   char ch;
     603
     604   if( read(sockfd, &ch, 1) <= 0 ) {
     605     return EOF;
     606   }
     607   else {
     608     return ch;
     609   }
     610 }/* SK_getc() */
     611 #endif /* 0 */
     612
     613 /* SK_getpeername() */
     614 /*++++++++++++++++++++++++++++++++++++++
     615
     616   This function will tell you who is at the other end of a connected stream socket.
     617
     618   char *SK_getpeername     Returns allocated string with the IP in it,
     619                            or "--" if the descriptor is not a socket,
     620                            or NULL on error.
     621
     622   int    sockfd            The socket or file descriptor.
     623
     624   +html+ <PRE>
     625   Authors:
     626         ottrey,
     627         marek (modified error handling, made MT-Safe).
     628   +html+ </PRE>
     629
     630   ++++++++++++++++++++++++++++++++++++++*/
     631 char *SK_getpeername(int  sockfd)
         /* [<][>][^][v][top][bottom][index][help] */
     632 {
     633   char *hostaddress=NULL;
     634   struct sockaddr_in addr_in;
     635   int namelen=sizeof(addr_in);
     636
     637   if (getpeername(sockfd, (struct sockaddr *)&addr_in, &namelen) == 0) {
     638
     639     hostaddress = (char *)UT_malloc(INET_ADDRSTRLEN);
     640     inet_ntop(AF_INET, &(addr_in.sin_addr),  hostaddress, INET_ADDRSTRLEN);
     641   }
     642   else {
     643     int er = errno;
     644
     645     if( er == ENOTSOCK ) {
     646       hostaddress = wr_string("--");
     647     }
     648     else {
     649       /* XXX: hack to avoid crash in the case where peer disconnects */
     650       /* To fix this, the socket interface needs to deal with a structure
     651          containing not only the file descriptor, but also the address of
     652          the host and the peer.  Other goodies, like the current time,
     653          time of last operation, and last errno could also be included
     654          for good measure. */
     655       hostaddress = UT_strdup("127.0.0.1");
     656     }
     657   }
     658
     659   return hostaddress;
     660
     661 } /* SK_getpeername() */
     662
     663
     664 /* SK_getpeerip */
     665 /*++++++++++++++++++++++++++++++++++++++
     666
     667   This function will check the ip of the connected peer and store it in the
     668   ip_addr_t structure defined in the IP module.
     669
     670   int SK_getpeerip    returns 0 on success, -1 on failure.
     671
     672   int  sockfd         The socket descriptor (file will result in -1)
     673
     674   ip_addr_t *ip       Pointer to where the address should be stored.
     675
     676   +html+ <PRE>
     677   Author:
     678         marek
     679   +html+ </PRE>
     680   ++++++++++++++++++++++++++++++++++++++*/
     681
     682 int SK_getpeerip(int  sockfd, ip_addr_t *ip) {
         /* [<][>][^][v][top][bottom][index][help] */
     683   struct sockaddr_in addr_in;
     684   int namelen=sizeof(addr_in);
     685   int ret=-1;
     686
     687   memset(& addr_in, 0, sizeof(struct sockaddr_in));
     688
     689   if (getpeername(sockfd, (struct sockaddr *)(& addr_in), &namelen) != -1) {
     690     ret=0;
     691     IP_addr_s2b(ip, &addr_in, namelen);
     692   } else {
     693       /* XXX: hack to avoid crash in the case where peer disconnects */
     694       /* To fix this, the socket interface needs to deal with a structure
     695          containing not only the file descriptor, but also the address of
     696          the host and the peer.  Other goodies, like the current time,
     697          time of last operation, and last errno could also be included
     698          for good measure. */
     699       ret = 0;
     700       addr_in.sin_family = AF_INET;
     701       addr_in.sin_addr.s_addr = INADDR_LOOPBACK;
     702       addr_in.sin_port = 0;
     703       IP_addr_s2b(ip, &addr_in, namelen);
     704   }
     705
     706   return ret;
     707 }
     708

/* [<][>][^][v][top][bottom][index][help] */