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) {
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) {
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, 
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) {
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)
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) {
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, 
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) {
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) 
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) 
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) {
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) 
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) {
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  |