1    | /***************************************
2    |   $Revision: 1.15 $
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                           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 "sk.h"
38   | #include "constants.h"
39   | #include "stubs.h"
40   | 
41   | #include "memwrap.h"
42   | 
43   | /*+ String sizes +*/
44   | #define STR_S   63
45   | #define STR_XXL 16383
46   | 
47   | /* SK_atoport() */
48   | /*++++++++++++++++++++++++++++++++++++++
49   |    Take a service name, and a service type, and return a port number.  If the
50   |    service name is not found, it tries it as a decimal number.  The number
51   |    returned is byte ordered for the network.
52   | 
53   |   char *service   Service name (or port number).
54   | 
55   |   char *proto     Protocol (eg "tcp").
56   | 
57   |   Author:
58   |         ottrey.
59   | 
60   |   ++++++++++++++++++++++++++++++++++++++*/
61   | int SK_atoport(const char *service, const char *proto) {
62   |   unsigned port;
63   |   long int lport;
64   |   struct servent *serv;
65   |   char *errpos;
66   |   struct servent result;
67   |   char buffer[STR_XXL];
68   | 
69   |   /* First try to read it from /etc/services */
70   | 
71   | #ifdef __linux__
72   |   if(getservbyname_r(service, proto, &result, buffer, sizeof(buffer), &serv) < 0) serv = NULL;
73   | #else  
74   |   serv = getservbyname_r(service, proto, &result, buffer, sizeof(buffer));
75   | #endif
76   |   
77   |   if (serv != NULL)
78   |     port = serv->s_port;
79   |   else { /* Not in services, maybe a number? */
80   |     lport = strtol(service,&errpos,0);
81   |     if ( (errpos[0] != 0) || (lport < 1) || (lport > 65535) )
82   |       return -1; /* Invalid port address */
83   |     port = htons(lport);
84   |   }
85   |   return port;
86   | } /* SK_atoport() */
87   | 
88   | 
89   | /* SK_close() */
90   | /*++++++++++++++++++++++++++++++++++++++
91   |   
92   |   int SK_close     wrapper around closing the socket. Returns the value
93   |                    returned by close(2)
94   | 
95   |   int socket       socket to be closed
96   | 
97   |   Author:
98   |         ottrey
99   |   ++++++++++++++++++++++++++++++++++++++*/
100  | int SK_close(int socket) {
101  |   ER_dbg_va(FAC_SK, ASP_SK_GEN, "Closing socket... %d", socket);
102  | 
103  |   return close(socket);
104  | }
105  | 
106  | /* SK_getsock() */
107  | /*++++++++++++++++++++++++++++++++++++++
108  | 
109  |    int  SK_getsock        This function creates a socket and binds to it. 
110  |                           Returns the number of the created 
111  | 			  descriptor/listening socket.
112  | 
113  |    int socket_type        SOCK_STREAM or SOCK_DGRAM (TCP or UDP sockets)
114  | 
115  |    unsigned  port         The port to listen on. Ports < 1024 are
116  |                           reserved for the root user. Host byte order.
117  | 
118  |    int backlog            Size of the backlog queue to be set on that
119  |                           socket.
120  | 
121  |    uint32_t bind_address  Address to bind to, in network order.
122  | 
123  |   Authors:
124  |         ottrey,
125  | 	joao,
126  | 	marek (added htons conversion for port).
127  | 
128  |   ++++++++++++++++++++++++++++++++++++++*/
129  | int  SK_getsock(int socket_type, unsigned h_port, int backlog, 
130  | 		uint32_t bind_address) {
131  |   struct sockaddr_in address;
132  |   int listening_socket;
133  |   int reuse_addr = 1;
134  |   u_short port = htons(h_port);
135  | 
136  |   /* Setup internet address information.  
137  |      This is used with the bind() call */
138  |   memset((char *) &address, 0, sizeof(address));
139  |   address.sin_family = AF_INET;
140  |   address.sin_port = port;
141  |   address.sin_addr.s_addr = bind_address;
142  | 
143  |   /* Map all of the signals and exit routine */
144  | 
145  |   listening_socket = socket(AF_INET, socket_type, 0);
146  |   if (listening_socket < 0) {
147  |     perror("socket");
148  |     exit(EXIT_FAILURE);
149  |   }
150  | 
151  |   setsockopt(listening_socket, SOL_SOCKET, SO_REUSEADDR, (void *)&reuse_addr, sizeof(reuse_addr));
152  | 
153  |   if (bind(listening_socket, (struct sockaddr *) &address, sizeof(address)) < 0) {
154  |     perror("bind");
155  |     close(listening_socket);
156  |     exit(EXIT_FAILURE);
157  |   }
158  | 
159  | 
160  |   if (socket_type == SOCK_STREAM) {
161  |     listen(listening_socket, backlog); /* Queue up to five connections before
162  |                                   having them automatically rejected. */
163  |   }
164  | 
165  |   return listening_socket;
166  | } /* SK_getsock() */
167  | 
168  | /*++++++++++++++++++++++++++++++++++++++
169  | 
170  |    Wait for an incoming connection on the specified socket
171  | 
172  |    int	SK_accept_connection The socket for communicating to the client
173  | 
174  |    int  listening_socket     The socket that the server is bound to
175  | 
176  |   Authors:
177  | 	joao,
178  | 	marek.
179  |   ++++++++++++++++++++++++++++++++++++++*/
180  | int SK_accept_connection(int listening_socket) {
181  |   int connected_socket = -1;
182  |   int num_errors = 0;
183  | 
184  | #define MAX_ACCEPT_ERRORS 3
185  | 
186  |   for (;;) {
187  |     
188  |     ER_dbg_va(FAC_SK, ASP_SK_GEN, 
189  | 	      "Going to accept connections on socket : %d",listening_socket);
190  | 
191  |     connected_socket = accept(listening_socket, NULL, NULL);
192  |     if (connected_socket < 0) {
193  |       /* Either a real error occured, or blocking was interrupted for
194  |          some reason.  Only abort execution if a real error occured. */
195  |       switch(errno) {
196  |       case EINTR:        /* Interrupted system call */
197  |       case ECONNABORTED: /* Software caused connection abort */
198  | 	/* no warning */
199  | 	continue;    /* don't return - do the accept again */
200  |       default: 
201  | 	/* special case: shutdown of the server - just return */
202  | 	if( CO_get_do_server() == 0 ) {
203  | 	  return -1;
204  | 	}
205  | 	else { /* real error */
206  | 	  if( ++num_errors < MAX_ACCEPT_ERRORS ) {
207  | 	    /* warn */
208  | 	    ER_perror(FAC_SK, SK_ACERW, "(%d) %s", errno, strerror(errno));
209  | 	  }
210  | 	  else {
211  | 	    /* crash */
212  | 	    ER_perror(FAC_SK, SK_ACERF, 
213  | 	        "too many accept() errors (maximum is %d)", MAX_ACCEPT_ERRORS);
214  | 	    die;
215  | 	  }
216  | 	}
217  |       }
218  |     } 
219  |     else { /* success */
220  |        ER_dbg_va(FAC_SK, ASP_SK_GEN, "client connected on socket %d", 
221  | 	    connected_socket
222  | 	    );
223  | 
224  |        return connected_socket;
225  |     }
226  | 
227  |   }
228  | }
229  | 
230  | 
231  | /*++++++++++++++++++++++++++++++++++++++
232  |   
233  |   er_ret_t SK_connect       wrapper around connect(), doing non-blocking 
234  |                             connection with timeout 
235  | 
236  |   int *sock         pointer to the storage for socket descriptor 
237  |    
238  |   char *hostname    host to connect to
239  | 
240  |   int port          port to connect to
241  | 
242  |   int timeout       in seconds
243  | 
244  |   Author: marek
245  | 
246  |   ++++++++++++++++++++++++++++++++++++++*/
247  | er_ret_t SK_connect(int  *sock, char *hostname, unsigned int port, unsigned int timeout)
248  | {
249  |   struct sockaddr_in sin;
250  |   struct hostent *hp;
251  |   int s;
252  |   int flags;
253  |   struct timeval ptm;
254  |   fd_set rset, wset;
255  |   int gs, sel, er, erlen=sizeof(er);
256  |   int error;
257  |   struct hostent result;
258  |   char aliasbuf[8192]; /* Stevens, UNIX net. prog., p.304 */
259  | 
260  |   /* look up the host name */
261  | #ifdef __linux__
262  |   er = (gethostbyname_r(hostname,  &result, aliasbuf, 
263  | 			sizeof(aliasbuf), &hp, &error) < 0 );
264  | #else /* default is Solaris implementation */                             
265  |   hp = gethostbyname_r(hostname,  &result, aliasbuf, 
266  | 		       sizeof(aliasbuf), &error);
267  |   er = ( hp == NULL ); 
268  | #endif      
269  |   
270  |   if( er ) {
271  |     return SK_BADHOST;
272  |   }
273  |   
274  |   /* create a socket */
275  |   s = socket(AF_INET, SOCK_STREAM, 0);
276  |   if (s < 0) {
277  |     return SK_SOCKET;
278  |   }
279  |   
280  |   /* bind to it */
281  |   bzero((caddr_t)&sin, sizeof (sin));
282  |   sin.sin_family = hp->h_addrtype;
283  |   if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
284  |     close(s);
285  |     return SK_BIND;
286  |   }
287  |   bcopy(hp->h_addr, (char *)&sin.sin_addr, hp->h_length);
288  |   sin.sin_port=htons(port);
289  | 
290  |   /* connect in non-blocking mode */
291  |   flags = fcntl(s, F_GETFL, 0);
292  |   fcntl(s, F_SETFL, flags | O_NONBLOCK );
293  | 
294  |   if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0
295  |       && errno != EINPROGRESS ) {
296  |     close(s);
297  |     return SK_CONNECT;
298  |   }
299  |   
300  |   /* now wait for success */
301  |   FD_ZERO( &rset );
302  |   FD_SET( s, &rset );
303  |   wset = rset;
304  |   ptm.tv_usec = 0;
305  |   ptm.tv_sec = timeout;
306  |   
307  |   if( (sel=select(s+1,  &rset, &wset, NULL, &ptm)) == 0 ) {
308  |     /* timeout */
309  |     close(s);
310  |     return SK_TIMEOUT;
311  |   }
312  |   dieif( sel < 0 ); /* we don't expect problems with select */
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  | /* SK_read() */
329  | /*++++++++++++++++++++++++++++++++++++++
330  | 
331  |    This is just like the read() system call, except that it will make
332  |    sure that all your data goes through the socket.
333  | 
334  |    int    SK_read   Returns the number of bytes read.
335  | 
336  |    int    sockfd    The socket file descriptor.
337  | 
338  |    char   *buf      The buffer to be read from the socket.
339  | 
340  |    size_t count     The number of bytes in the buffer.
341  | 
342  |   Author:
343  |         ottrey
344  | 
345  |   ++++++++++++++++++++++++++++++++++++++*/
346  | int SK_read(int sockfd, char *buf, size_t count) {
347  |   size_t bytes_read = 0;
348  |   int this_read;
349  | 
350  |   while (bytes_read < count) {
351  |     do
352  |       this_read = read(sockfd, buf, count - bytes_read);
353  |     while ( (this_read < 0) && (errno == EINTR) );
354  |     if (this_read < 0)
355  |       return this_read;
356  |     else if (this_read == 0)
357  |       return bytes_read;
358  |     bytes_read += this_read;
359  |     buf += this_read;
360  |   }
361  | 
362  |   return count;
363  | 
364  | } /* SK_read() */
365  | 
366  | 
367  | /* SK_write() */
368  | /*++++++++++++++++++++++++++++++++++++++
369  | 
370  |    This is just like the write() system call, except that it will
371  |    make sure that all data is transmitted.
372  | 
373  |    int SK_write   Returns the number of bytes written.
374  | 
375  |    int    sockfd  The socket file descriptor.
376  | 
377  |    char   *buf    The buffer to be written to the socket.
378  | 
379  |    size_t count   The number of bytes in the buffer.
380  | 
381  |   Author:
382  |         ottrey
383  | 
384  |   ++++++++++++++++++++++++++++++++++++++*/
385  | int SK_write(int  sockfd, const char *buf, size_t count) {
386  |   size_t  bytes_sent = 0;
387  |   int     this_write;
388  | 
389  |   
390  |   ER_dbg_va(FAC_SK, ASP_SK_WRIT,
391  | 	    "SK_write = { sockfd=[%d], buf=[%s], count=[%d]", 
392  | 	    sockfd, buf, count);
393  | 
394  |   while (bytes_sent < count) {
395  |     do
396  |       this_write = write(sockfd, buf, count - bytes_sent);
397  |     while ( (this_write < 0) && (errno == EINTR) );
398  |     if (this_write <= 0)
399  |       return this_write;
400  |     bytes_sent += this_write;
401  |     buf += this_write;
402  |   }
403  |   return count;
404  | } /* SK_write() */
405  | 
406  | 
407  | /* SK_gets() */
408  | /*++++++++++++++++++++++++++++++++++++++
409  | 
410  |    This function reads from a socket, until it recieves a linefeed
411  |    character.  It fills the buffer "str" up to the maximum size "count".
412  | 
413  |    int SK_gets      Returns the total_count of bytes read.
414  | 
415  |    int    sockfd    The socket file descriptor.
416  | 
417  |    char   *str      The buffer to be written from the socket.
418  | 
419  |    size_t count     The number of bytes in the buffer.
420  | 
421  | 
422  |   Authors:
423  |         ottrey,
424  | 	marek (modified for meaningful error codes).
425  | 
426  |   Side Effects:
427  |         This function will return -1 if the socket is closed during the read operation.
428  | 
429  |         Note that if a single line exceeds the length of count, the extra data
430  |         will be read and discarded!  You have been warned.
431  | 
432  |   ++++++++++++++++++++++++++++++++++++++*/
433  | int SK_gets(int  sockfd, char *str, size_t count) {
434  |   int bytes_read;
435  |   int total_count = 0;
436  |   char *current_position;
437  |   char last_read = 0;
438  | 
439  |   int control_c = 0;
440  | 
441  |   current_position = str;
442  |   while (last_read != 10) {
443  | 
444  |     bytes_read = read(sockfd, &last_read, 1);
445  |     if (bytes_read <= 0) {
446  |       /* The other side may have closed unexpectedly */
447  |       return SK_DISCONNECT; 
448  |       /* Is this effective on other platforms than linux? */
449  |     }
450  |     if ( (total_count < count) && (last_read != 10) && (last_read !=13) ) {
451  |       *current_position = last_read;
452  |       current_position++;
453  |       total_count++;
454  |     }
455  | 
456  |     if (last_read == -1) {
457  |       bytes_read = read(sockfd, &last_read, 1);
458  |       if (last_read == -12) {
459  |         ER_dbg_va(FAC_SK, ASP_SK_GEN,"Client pressed Control-c");
460  |         control_c = 1;
461  |         ER_dbg_va(FAC_SK, ASP_SK_GEN,"returning SK_INTERRUPT");
462  |         return SK_INTERRUPT;
463  |       }
464  |     }
465  |   }
466  |   if (count > 0) {
467  |     *current_position = 0;
468  |   }
469  | 
470  |   return total_count;
471  | 
472  | } /* SK_gets() */
473  | 
474  | 
475  | /* SK_puts() */
476  | /*++++++++++++++++++++++++++++++++++++++
477  | 
478  |    This function writes a character string out to a socket.
479  | 
480  |    int SK_puts  The total_count of bytes written, 
481  |                 or errors (represented as negative numbers)
482  | 
483  |    int    sockfd    The socket file descriptor.
484  | 
485  |    char   *str      The buffer to be written from the socket.
486  | 
487  |   More:
488  |   +html+ <PRE>
489  |   Authors:
490  |         ottrey
491  | 
492  |   Side Effects:
493  |         This function will return -1 if the socket is closed during the write operation.
494  |   +html+ </PRE>
495  | 
496  |   ++++++++++++++++++++++++++++++++++++++*/
497  | int SK_puts(int  sockfd, const char *str) {
498  | 
499  |   return SK_write(sockfd, str, strlen(str));
500  | 
501  | } /* SK_puts() */
502  | 
503  | /* SK_putc() */
504  | /*++++++++++++++++++++++++++++++++++++++
505  |   
506  |   This function writes a single character out to a socket.
507  | 
508  |    int SK_putc       Returns the number of characters written.
509  | 
510  |    int sockfd        socket
511  | 
512  |    char ch           character
513  | 
514  |   ++++++++++++++++++++++++++++++++++++++*/
515  | int SK_putc(int  sockfd, char ch) {
516  |   return SK_write(sockfd, &ch, 1);
517  | }/* SK_putc() */
518  | 
519  | /*++++++++++++++++++++++++++++++++++++++
520  | 
521  |    This function reads a single character from a socket.
522  | 
523  |    returns EOF when no character can be read. 
524  | 
525  |   ++++++++++++++++++++++++++++++++++++++*/
526  | int SK_getc(int  sockfd) {
527  |   char ch;
528  | 
529  |   if( read(sockfd, &ch, 1) <= 0 ) {
530  |     return EOF;
531  |   }
532  |   else {
533  |     return ch;
534  |   }
535  | }/* SK_getc() */
536  | 
537  | /* SK_getpeername() */
538  | /*++++++++++++++++++++++++++++++++++++++
539  | 
540  |   This function will tell you who is at the other end of a connected stream socket.
541  |   
542  |   char *SK_getpeername     Returns allocated string with the IP in it, 
543  |                            or "--" if the descriptor is not a socket,
544  | 			   or NULL on error.
545  | 
546  |   int    sockfd            The socket or file descriptor.
547  | 
548  |   +html+ <PRE>
549  |   Authors:
550  |         ottrey,
551  | 	marek (modified error handling, made MT-Safe).
552  |   +html+ </PRE>
553  | 
554  |   ++++++++++++++++++++++++++++++++++++++*/
555  | char *SK_getpeername(int  sockfd) 
556  | {
557  |   char *hostaddress=NULL;
558  |   struct sockaddr_in addr_in;
559  |   int namelen=sizeof(addr_in);
560  |  
561  |   if (getpeername(sockfd, (struct sockaddr *)&addr_in, &namelen) == 0) {
562  | 
563  |     dieif( wr_malloc((void **)&hostaddress, INET_ADDRSTRLEN) != UT_OK); 
564  |     inet_ntop(AF_INET, &(addr_in.sin_addr),  hostaddress, INET_ADDRSTRLEN);
565  |   }
566  |   else {
567  |     int er = errno;
568  |     
569  |     if( er == ENOTSOCK ) {
570  |       hostaddress = wr_string("--");
571  |     }
572  |     else {
573  |       return NULL;
574  |     }
575  |   }
576  | 
577  |   return hostaddress;
578  |   
579  | } /* SK_getpeername() */
580  | 
581  | 
582  | /* SK_getpeerip */
583  | /*++++++++++++++++++++++++++++++++++++++
584  |   
585  |   This function will check the ip of the connected peer and store it in the
586  |   ip_addr_t structure defined in the IP module.
587  | 
588  |   int SK_getpeerip    returns 0 on success, -1 on failure.
589  | 
590  |   int  sockfd         The socket descriptor (file will result in -1)
591  | 
592  |   ip_addr_t *ip       Pointer to where the address should be stored.
593  | 
594  |   +html+ <PRE>
595  |   Author:
596  | 	marek
597  |   +html+ </PRE>
598  |   ++++++++++++++++++++++++++++++++++++++*/
599  | 
600  | int SK_getpeerip(int  sockfd, ip_addr_t *ip) {
601  |   struct sockaddr_in addr_in;
602  |   int namelen=sizeof(addr_in);
603  |   int ret=-1;
604  | 
605  |   memset(& addr_in, 0, sizeof(struct sockaddr_in));
606  | 
607  |   if (getpeername(sockfd, (struct sockaddr *)(& addr_in), &namelen) != -1) {
608  |     ret=0;
609  |     IP_addr_s2b(ip, &addr_in, namelen);
610  |   }
611  |   
612  |   return ret;
613  | }
614  |