modules/sk/sk_socket.c

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

FUNCTIONS

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.20 $
   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     perror("bind");
 147     close(listening_socket);
 148     exit(EXIT_FAILURE);
 149   }
 150 
 151 
 152   if (socket_type == SOCK_STREAM) {
 153     listen(listening_socket, backlog); /* Queue up to five connections before
 154                                   having them automatically rejected. */
 155   }
 156 
 157   return listening_socket;
 158 } /* SK_getsock() */
 159 
 160 /*++++++++++++++++++++++++++++++++++++++
 161 
 162    Wait for an incoming connection on the specified socket
 163 
 164    int  SK_accept_connection The socket for communicating to the client
 165 
 166    int  listening_socket     The socket that the server is bound to
 167 
 168   Authors:
 169         joao,
 170         marek.
 171   ++++++++++++++++++++++++++++++++++++++*/
 172 int SK_accept_connection(int listening_socket) {
     /* [<][>][^][v][top][bottom][index][help] */
 173   int connected_socket = -1;
 174   int num_errors = 0;
 175 
 176 #define MAX_ACCEPT_ERRORS 3
 177 
 178   for (;;) {
 179     
 180     ER_dbg_va(FAC_SK, ASP_SK_GEN, 
 181               "Going to accept connections on socket : %d",listening_socket);
 182 
 183     connected_socket = accept(listening_socket, NULL, NULL);
 184     if (connected_socket < 0) {
 185       /* Either a real error occured, or blocking was interrupted for
 186          some reason.  Only abort execution if a real error occured. */
 187       switch(errno) {
 188       case EINTR:        /* Interrupted system call */
 189       case ECONNABORTED: /* Software caused connection abort */
 190         /* no warning */
 191         continue;    /* don't return - do the accept again */
 192       default: 
 193         /* special case: shutdown of the server - just return */
 194         if( CO_get_do_server() == 0 ) {
 195           return -1;
 196         }
 197         else { /* real error */
 198           if( ++num_errors < MAX_ACCEPT_ERRORS ) {
 199             /* warn */
 200             ER_perror(FAC_SK, SK_ACERW, "(%d) %s", errno, strerror(errno));
 201           }
 202           else {
 203             /* crash */
 204             ER_perror(FAC_SK, SK_ACERF, 
 205                 "too many accept() errors (maximum is %d)", MAX_ACCEPT_ERRORS);
 206             die;
 207           }
 208         }
 209       }
 210     } 
 211     else { /* success */
 212        ER_dbg_va(FAC_SK, ASP_SK_GEN, "client connected on socket %d", 
 213             connected_socket
 214             );
 215 
 216        return connected_socket;
 217     }
 218 
 219   }
 220 }
 221 
 222 
 223 /*++++++++++++++++++++++++++++++++++++++
 224   
 225   er_ret_t SK_connect       wrapper around connect(), doing non-blocking 
 226                             connection with timeout 
 227 
 228   int *sock         pointer to the storage for socket descriptor 
 229    
 230   char *hostname    host to connect to
 231 
 232   int port          port to connect to
 233 
 234   int timeout       in seconds
 235 
 236   Author: marek
 237 
 238   ++++++++++++++++++++++++++++++++++++++*/
 239 er_ret_t SK_connect(int  *sock, char *hostname, unsigned int port, unsigned int timeout)
     /* [<][>][^][v][top][bottom][index][help] */
 240 {
 241   struct sockaddr_in sin;
 242   struct hostent *hp;
 243   int s;
 244   int flags;
 245   struct timeval ptm;
 246   fd_set rset, wset;
 247   int gs, sel, er, erlen=sizeof(er);
 248   int error;
 249   struct hostent result;
 250   char aliasbuf[8192]; /* Stevens, UNIX net. prog., p.304 */
 251 
 252   /* look up the host name */
 253 #ifdef __linux__
 254   er = (gethostbyname_r(hostname,  &result, aliasbuf, 
 255                         sizeof(aliasbuf), &hp, &error) < 0 );
 256 #else /* default is Solaris implementation */                             
 257   hp = gethostbyname_r(hostname,  &result, aliasbuf, 
 258                        sizeof(aliasbuf), &error);
 259   er = ( hp == NULL ); 
 260 #endif      
 261   
 262   if( er ) {
 263     return SK_BADHOST;
 264   }
 265   
 266   /* create a socket */
 267   s = socket(AF_INET, SOCK_STREAM, 0);
 268   if (s < 0) {
 269     return SK_SOCKET;
 270   }
 271   
 272   /* bind to it */
 273   bzero((caddr_t)&sin, sizeof (sin));
 274   sin.sin_family = hp->h_addrtype;
 275   if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
 276     close(s);
 277     return SK_BIND;
 278   }
 279   bcopy(hp->h_addr, (char *)&sin.sin_addr, hp->h_length);
 280   sin.sin_port=htons(port);
 281 
 282   /* connect in non-blocking mode */
 283   flags = fcntl(s, F_GETFL, 0);
 284   fcntl(s, F_SETFL, flags | O_NONBLOCK );
 285 
 286   if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0
 287       && errno != EINPROGRESS ) {
 288     close(s);
 289     return SK_CONNECT;
 290   }
 291   
 292   /* now wait for success */
 293   FD_ZERO( &rset );
 294   FD_SET( s, &rset );
 295   wset = rset;
 296   ptm.tv_usec = 0;
 297   ptm.tv_sec = timeout;
 298   
 299   if( (sel=select(s+1,  &rset, &wset, NULL, &ptm)) == 0 ) {
 300     /* timeout */
 301     close(s);
 302     return SK_TIMEOUT;
 303   }
 304   if (sel < 0) {
 305     close(s);
 306     return SK_CONNECT;
 307   }
 308   
 309   gs = getsockopt(s, SOL_SOCKET, SO_ERROR, &er, &erlen);
 310   
 311   if( gs < 0 || er ) {   /* Stevens code, p.411 is exceptionally crappy */
 312     close(s);
 313     return SK_CONNECT;
 314   } /* if error */
 315   
 316   fcntl(s, F_SETFL, flags);
 317   *sock = s;
 318   
 319   return SK_OK;
 320 }
 321 
 322 
 323 /* SK_read() */
 324 /*++++++++++++++++++++++++++++++++++++++
 325 
 326    This is just like the read() system call, except that it will make
 327    sure that all your data goes through the socket.
 328 
 329    int    SK_read   Returns the number of bytes read.
 330 
 331    int    sockfd    The socket file descriptor.
 332 
 333    char   *buf      The buffer to be read from the socket.
 334 
 335    size_t count     The number of bytes in the buffer.
 336 
 337   Author:
 338         ottrey
 339 
 340   ++++++++++++++++++++++++++++++++++++++*/
 341 int SK_read(int sockfd, char *buf, size_t count) {
     /* [<][>][^][v][top][bottom][index][help] */
 342   size_t bytes_read = 0;
 343   int this_read;
 344 
 345   while (bytes_read < count) {
 346     do
 347       this_read = read(sockfd, buf, count - bytes_read);
 348     while ( (this_read < 0) && (errno == EINTR) );
 349     if (this_read < 0)
 350       return this_read;
 351     else if (this_read == 0)
 352       return bytes_read;
 353     bytes_read += this_read;
 354     buf += this_read;
 355   }
 356 
 357   return count;
 358 
 359 } /* SK_read() */
 360 
 361 
 362 /* SK_write() */
 363 /*++++++++++++++++++++++++++++++++++++++
 364 
 365    int SK_write   Returns:
 366                      -1 on error
 367                       0 on timeout 
 368                       1 on success (all bytes written)
 369 
 370    int sockfd                      The socket file descriptor.
 371 
 372    const char *buf                 The buffer to be written to the socket.
 373 
 374    int count                       The number of bytes in the buffer.
 375 
 376    const struct timeval *timeout   Maximum time to wait between each 
 377                                    write() call, or NULL for "forever".
 378 
 379    int *count_sent                 Set to the number of bytes sucessfully
 380                                    written.  This value is always valid, 
 381                                    although it will be less than the 
 382                                    total number of bytes to send if 
 383                                    the function returns -1 or 0.  NULL
 384                                    may be sent if the caller does not
 385                                    care about the number of bytes sent on
 386                                    failure.
 387 
 388   ++++++++++++++++++++++++++++++++++++++*/
 389 
 390 int 
 391 SK_write(int sockfd, 
     /* [<][>][^][v][top][bottom][index][help] */
 392          const char *buf,
 393          int count,
 394          const struct timeval *timeout, 
 395          int *count_sent) 
 396 {
 397   int     local_count_sent;    /* only used if caller passes NULL */
 398   fd_set  fds;
 399   int     select_ret;
 400   struct  timeval tv;
 401   int     write_ret;
 402   
 403   /* copious logging never hurt anybody (well, except people with slow
 404      computers or small hard disks) */
 405   ER_dbg_va(FAC_SK, ASP_SK_WRIT,
 406             "SK_write = { sockfd=[%d], buf=[%s], count=[%d]", 
 407             sockfd, buf, count);
 408 
 409   /* allow caller to pass NULL if it doesn't care about the count sent */
 410   if (count_sent == NULL) {
 411       count_sent = &local_count_sent;
 412   }
 413 
 414   /* loop around until we send all of our data, or we get a timeout or
 415      disconnect */
 416   *count_sent = 0;
 417   while (*count_sent < count) {
 418 
 419     /* first, call select() and see if we can write without blocking */
 420     FD_ZERO(&fds);
 421     FD_SET(sockfd, &fds);
 422     if (timeout == NULL) {
 423         select_ret = select(sockfd+1, NULL, &fds, NULL, NULL);
 424     } else {
 425         /* make a copy of timeout, because it's value is undefined 
 426            on return from select() */
 427         tv = *timeout;
 428         select_ret = select(sockfd+1, NULL, &fds, NULL, &tv);
 429     }
 430     /* check for error */
 431     if (select_ret < 0) {
 432         /* log the error and return "timeout" */
 433         ER_perror(FAC_SK, SK_SELECT, "(%d) %s", errno, strerror(errno));
 434         return -1;
 435     }
 436     /* check for timeout */
 437     if ((select_ret == 0) || !FD_ISSET(sockfd, &fds)) {
 438         return -1;
 439     }
 440 
 441 
 442     /* at this point we can safely write */
 443     write_ret = write(sockfd, buf, count - *count_sent);
 444 
 445     /* if write failed, assume other side disconnected */
 446     if (write_ret <= 0) {
 447         return 0;
 448     }
 449 
 450     /* update our current status */
 451     *count_sent += write_ret;
 452     buf += write_ret;
 453 
 454   }
 455 
 456   /* all bytes sent, return success */
 457   return 1;
 458 } /* SK_write() */
 459 
 460 
 461 /* SK_gets() */
 462 /*++++++++++++++++++++++++++++++++++++++
 463 
 464    This function reads from a socket, until it recieves a linefeed
 465    character.  It fills the buffer "str" up to the maximum size "count".
 466 
 467    int SK_gets      Returns the total_count of bytes read.
 468 
 469    int    sockfd    The socket file descriptor.
 470 
 471    char   *str      The buffer to be written from the socket.
 472 
 473    size_t count     The number of bytes in the buffer.
 474 
 475 
 476   Authors:
 477         ottrey,
 478         marek (modified for meaningful error codes).
 479 
 480   Side Effects:
 481         This function will return -1 if the socket is closed during the read operation.
 482 
 483         Note that if a single line exceeds the length of count, the extra data
 484         will be read and discarded!  You have been warned.
 485 
 486   ++++++++++++++++++++++++++++++++++++++*/
 487 int SK_gets(int  sockfd, char *str, size_t count) {
     /* [<][>][^][v][top][bottom][index][help] */
 488   int bytes_read;
 489   int total_count = 0;
 490   char *current_position;
 491   char last_read = 0;
 492 
 493   int control_c = 0;
 494 
 495   current_position = str;
 496   while (last_read != 10) {
 497 
 498     bytes_read = read(sockfd, &last_read, 1);
 499     if (bytes_read <= 0) {
 500       /* The other side may have closed unexpectedly */
 501       return SK_DISCONNECT; 
 502       /* Is this effective on other platforms than linux? */
 503     }
 504     if ( (total_count < count) && (last_read != 10) && (last_read !=13) ) {
 505       *current_position = last_read;
 506       current_position++;
 507       total_count++;
 508     }
 509 
 510     if (last_read == -1) {
 511       bytes_read = read(sockfd, &last_read, 1);
 512       if (last_read == -12) {
 513         ER_dbg_va(FAC_SK, ASP_SK_GEN,"Client pressed Control-c");
 514         control_c = 1;
 515         ER_dbg_va(FAC_SK, ASP_SK_GEN,"returning SK_INTERRUPT");
 516         return SK_INTERRUPT;
 517       }
 518     }
 519   }
 520   if (count > 0) {
 521     *current_position = 0;
 522   }
 523 
 524   return total_count;
 525 
 526 } /* SK_gets() */
 527 
 528 
 529 /* SK_puts() */
 530 /*++++++++++++++++++++++++++++++++++++++
 531 
 532    This function writes a character string out to a socket.
 533 
 534    int SK_puts  The total_count of bytes written, 
 535                 or -1 on hangup, error, or timeout
 536 
 537    int    sockfd    The socket file descriptor.
 538 
 539    char   *str      The buffer to be written from the socket.
 540 
 541    const struct timeval *timeout   Maximum time to wait between each 
 542                                    write() call, or NULL for "forever".
 543 
 544   ++++++++++++++++++++++++++++++++++++++*/
 545 int 
 546 SK_puts(int sockfd, const char *str, const struct timeval *timeout) 
     /* [<][>][^][v][top][bottom][index][help] */
 547 {
 548   int count_sent;
 549   if (SK_write(sockfd, str, strlen(str), timeout, &count_sent) <= 0) {
 550       return -1;
 551   } else {
 552       return count_sent;
 553   }
 554 } /* SK_puts() */
 555 
 556 /* SK_putc() */
 557 /*++++++++++++++++++++++++++++++++++++++
 558   
 559   This function writes a single character out to a socket.
 560 
 561    int SK_putc       Returns the number of characters written.
 562 
 563    int sockfd        socket
 564 
 565    char ch           character
 566 
 567    const struct timeval *timeout   Maximum time to wait between each 
 568                                    write() call, or NULL for "forever".
 569 
 570   ++++++++++++++++++++++++++++++++++++++*/
 571 int 
 572 SK_putc(int sockfd, char ch, const struct timeval *timeout) 
     /* [<][>][^][v][top][bottom][index][help] */
 573 {
 574   int count_sent;
 575   SK_write(sockfd, &ch, 1, timeout, &count_sent);
 576   return count_sent;
 577 }/* SK_putc() */
 578 
 579 /*++++++++++++++++++++++++++++++++++++++
 580 
 581    This function reads a single character from a socket.
 582 
 583    returns EOF when no character can be read. 
 584 
 585   ++++++++++++++++++++++++++++++++++++++*/
 586 int SK_getc(int  sockfd) {
     /* [<][>][^][v][top][bottom][index][help] */
 587   char ch;
 588 
 589   if( read(sockfd, &ch, 1) <= 0 ) {
 590     return EOF;
 591   }
 592   else {
 593     return ch;
 594   }
 595 }/* SK_getc() */
 596 
 597 /* SK_getpeername() */
 598 /*++++++++++++++++++++++++++++++++++++++
 599 
 600   This function will tell you who is at the other end of a connected stream socket.
 601   
 602   char *SK_getpeername     Returns allocated string with the IP in it, 
 603                            or "--" if the descriptor is not a socket,
 604                            or NULL on error.
 605 
 606   int    sockfd            The socket or file descriptor.
 607 
 608   +html+ <PRE>
 609   Authors:
 610         ottrey,
 611         marek (modified error handling, made MT-Safe).
 612   +html+ </PRE>
 613 
 614   ++++++++++++++++++++++++++++++++++++++*/
 615 char *SK_getpeername(int  sockfd) 
     /* [<][>][^][v][top][bottom][index][help] */
 616 {
 617   char *hostaddress=NULL;
 618   struct sockaddr_in addr_in;
 619   int namelen=sizeof(addr_in);
 620  
 621   if (getpeername(sockfd, (struct sockaddr *)&addr_in, &namelen) == 0) {
 622 
 623     hostaddress = (char *)UT_malloc(INET_ADDRSTRLEN);
 624     inet_ntop(AF_INET, &(addr_in.sin_addr),  hostaddress, INET_ADDRSTRLEN);
 625   }
 626   else {
 627     int er = errno;
 628     
 629     if( er == ENOTSOCK ) {
 630       hostaddress = wr_string("--");
 631     }
 632     else {
 633       /* XXX: hack to avoid crash in the case where peer disconnects */
 634       /* To fix this, the socket interface needs to deal with a structure
 635          containing not only the file descriptor, but also the address of
 636          the host and the peer.  Other goodies, like the current time, 
 637          time of last operation, and last errno could also be included
 638          for good measure. */
 639       hostaddress = UT_strdup("127.0.0.1");
 640     }
 641   }
 642 
 643   return hostaddress;
 644   
 645 } /* SK_getpeername() */
 646 
 647 
 648 /* SK_getpeerip */
 649 /*++++++++++++++++++++++++++++++++++++++
 650   
 651   This function will check the ip of the connected peer and store it in the
 652   ip_addr_t structure defined in the IP module.
 653 
 654   int SK_getpeerip    returns 0 on success, -1 on failure.
 655 
 656   int  sockfd         The socket descriptor (file will result in -1)
 657 
 658   ip_addr_t *ip       Pointer to where the address should be stored.
 659 
 660   +html+ <PRE>
 661   Author:
 662         marek
 663   +html+ </PRE>
 664   ++++++++++++++++++++++++++++++++++++++*/
 665 
 666 int SK_getpeerip(int  sockfd, ip_addr_t *ip) {
     /* [<][>][^][v][top][bottom][index][help] */
 667   struct sockaddr_in addr_in;
 668   int namelen=sizeof(addr_in);
 669   int ret=-1;
 670 
 671   memset(& addr_in, 0, sizeof(struct sockaddr_in));
 672 
 673   if (getpeername(sockfd, (struct sockaddr *)(& addr_in), &namelen) != -1) {
 674     ret=0;
 675     IP_addr_s2b(ip, &addr_in, namelen);
 676   } else {
 677       /* XXX: hack to avoid crash in the case where peer disconnects */
 678       /* To fix this, the socket interface needs to deal with a structure
 679          containing not only the file descriptor, but also the address of
 680          the host and the peer.  Other goodies, like the current time, 
 681          time of last operation, and last errno could also be included
 682          for good measure. */
 683       ret = 0;
 684       addr_in.sin_family = AF_INET;
 685       addr_in.sin_addr.s_addr = INADDR_LOOPBACK;
 686       addr_in.sin_port = 0;
 687       IP_addr_s2b(ip, &addr_in, namelen);
 688   }
 689   
 690   return ret;
 691 }
 692 

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