1    | /***************************************
2    |   $Revision: 1.7 $
3    | 
4    |   Example code: A socket module.
5    | 
6    |   Status: NOT REVUED, NOT TESTED
7    | 
8    |   +html+ <DL COMPACT>
9    |   +html+ <DT>Online References:
10   |   +html+ <DD><UL>
11   |   +html+   <LI>Adapted from <A HREF="http://www.ibrado.com/sock-faq/sfaq.html#faq65">sample source code</A>.
12   |   +html+ </UL>
13   |   +html+ </DL>
14   |   +html+ <PRE>
15   |   +html+ </PRE>
16   |  
17   |   ******************/ /******************
18   |   Modification History:
19   |         ottrey (08/03/1999) Created from sockhelp.c.
20   |         ottrey (08/03/1998) Heavily butchered.
21   |         joao   (22/06/1999) Modified socket creation and accepts.
22   |   ******************/ /******************
23   |  REMINDER: PUT THE PROPER COPYRIGHT NOTICE HERE
24   |   ***************************************/
25   | #include <arpa/inet.h>
26   | #include "socket.h"
27   | #include "constants.h"
28   | #include "stubs.h"
29   | 
30   | #include "iproutines.h"
31   | 
32   | extern int h_errno;
33   | 
34   | 
35   | /*+ String sizes +*/
36   | #define STR_S   63
37   | #define STR_M   255
38   | #define STR_L   1023
39   | #define STR_XL  4095
40   | #define STR_XXL 16383
41   | 
42   | static void log_print(const char *arg) {
43   |   FILE *logf;
44   |   char *str;
45   | 
46   |   if (CO_get_socket_logging() == 1) {
47   |     if (strcmp(CO_get_socket_logfile(), "stdout") == 0) {
48   |       printf(arg);
49   |     }
50   |     else {
51   |       logf = fopen(CO_get_socket_logfile(), "a");
52   |       fprintf(logf, arg);
53   |       fclose(logf);
54   |     }
55   |   }
56   | 
57   | } /* log_print() */
58   |  
59   | /* SK_atoport() */
60   | /*++++++++++++++++++++++++++++++++++++++
61   |    Take a service name, and a service type, and return a port number.  If the
62   |    service name is not found, it tries it as a decimal number.  The number
63   |    returned is byte ordered for the network.
64   | 
65   |   char *service   Service name (or port number).
66   | 
67   |   char *proto     Protocol (eg "tcp").
68   | 
69   |   More:
70   |   +html+ <PRE>
71   |   Authors:
72   |         ottrey
73   | 
74   |   +html+ </PRE><DL COMPACT>
75   |   +html+ <DT>Online References:
76   |   +html+ <DD><UL>
77   |   +html+ </UL></DL>
78   | 
79   |   ++++++++++++++++++++++++++++++++++++++*/
80   | int SK_atoport(const char *service, const char *proto) {
81   |   int port;
82   |   long int lport;
83   |   struct servent *serv;
84   |   char *errpos;
85   | 
86   |   /* First try to read it from /etc/services */
87   |   serv = getservbyname(service, proto);
88   |   if (serv != NULL)
89   |     port = serv->s_port;
90   |   else { /* Not in services, maybe a number? */
91   |     lport = strtol(service,&errpos,0);
92   |     if ( (errpos[0] != 0) || (lport < 1) || (lport > 65535) )
93   |       return -1; /* Invalid port address */
94   |     port = htons(lport);
95   |   }
96   |   return port;
97   | } /* SK_atoport() */
98   | 
99   | 
100  | /* SK_close_listening_socket() */
101  | /*++++++++++++++++++++++++++++++++++++++
102  |   XXX Note: Not sure how long this function will last.  Shouldn't _really_ need it.
103  | 
104  |   More:
105  |   +html+ <PRE>
106  |   Authors:
107  |         ottrey
108  | 
109  |   +html+ </PRE><DL COMPACT>
110  |   +html+ <DT>Online References:
111  |   +html+ <DD><UL>
112  |   +html+ </UL></DL>
113  | 
114  |   ++++++++++++++++++++++++++++++++++++++*/
115  | /*void SK_close_listening_socket() {
116  |   close(listening_socket);         
117  | } */ /* SK_close_listening_socket */
118  | 
119  | static void func_atexit(void) {
120  |   printf("SK: func_atexit() called\n");
121  | }
122  | 
123  | static void func_sighup(int n) {
124  |   printf("SK: func_sighup(%d) called\n", n);
125  | }
126  | 
127  | static void func_sigint(int n) {
128  |   printf("SK: func_sigint(%d) called\n", n);
129  | }
130  | 
131  | 
132  | void SK_close(int socket) {
133  |   char print_buf[STR_M];
134  | 
135  |   sprintf(print_buf, "Closing socket... %d\n", socket); log_print(print_buf); strcpy(print_buf, "");
136  | 
137  |   close(socket);
138  | }
139  | 
140  | /* SK_getsock() */
141  | /*++++++++++++++++++++++++++++++++++++++
142  | 
143  |    This function creates a socket and binds to it
144  | 
145  |    int      SK_getsock       The new socket
146  | 
147  |    int      socket_type      SOCK_STREAM or SOCK_DGRAM (TCP or UDP sockets)
148  | 
149  |    u_short  port             The port to listen on.  Remember that ports < 1024 are
150  |                              reserved for the root user.  Must be passed in network byte
151  |                              order (see "man htons").
152  | 
153  |    uint32_t bind_address     Address to bind to, in network order.
154  |   More:
155  |   +html+ <PRE>
156  |   Authors:
157  |         ottrey
158  | 	joao
159  | 
160  |   +html+ </PRE><DL COMPACT>
161  |   +html+ <DT>Online References:
162  |   +html+ <DD><UL>
163  |   +html+ </UL></DL>
164  | 
165  |   ++++++++++++++++++++++++++++++++++++++*/
166  | int SK_getsock(int socket_type, u_short port, uint32_t bind_address) {
167  |   struct sockaddr_in address;
168  |   int listening_socket;
169  |   int new_process;
170  |   int reuse_addr = 1;
171  | 
172  |   /* Setup internet address information.  
173  |      This is used with the bind() call */
174  |   memset((char *) &address, 0, sizeof(address));
175  |   address.sin_family = AF_INET;
176  |   address.sin_port = port;
177  |   address.sin_addr.s_addr = bind_address;
178  | 
179  |   /* Map all of the signals and exit routine */
180  |   atexit(func_atexit);
181  |   /* signal.h has a full list of signal names */
182  |   signal(SIGHUP, func_sighup);
183  |   signal(SIGINT, func_sigint);
184  | 
185  |   listening_socket = socket(AF_INET, socket_type, 0);
186  |   if (listening_socket < 0) {
187  |     perror("socket");
188  |     exit(EXIT_FAILURE);
189  |   }
190  | 
191  |   setsockopt(listening_socket, SOL_SOCKET, SO_REUSEADDR, (void *)&reuse_addr, sizeof(reuse_addr));
192  | 
193  |   if (bind(listening_socket, (struct sockaddr *) &address, sizeof(address)) < 0) {
194  |     perror("bind");
195  |     close(listening_socket);
196  |     exit(EXIT_FAILURE);
197  |   }
198  | 
199  | 
200  |   if (socket_type == SOCK_STREAM) {
201  |     listen(listening_socket, 5); /* Queue up to five connections before
202  |                                   having them automatically rejected. */
203  |   }
204  | 
205  |   return listening_socket;
206  | } /* SK_getsock() */
207  | 
208  | /*++++++++++++++++++++++++++++++++++++++
209  | 
210  |    Wait for an incoming connection on the specified socket
211  | 
212  |    int	SK_accept_connection The socket for communicating to the client
213  | 
214  |    int  listening_socket     The socket that the server is bound to
215  | 
216  |   More:
217  |   +html+ <PRE>
218  |   Authors:
219  | 	joao
220  |   +html+ </PRE>
221  |   ++++++++++++++++++++++++++++++++++++++*/
222  | int SK_accept_connection(int listening_socket) {
223  |   int connected_socket = -1;
224  |   char print_buf[STR_L];
225  | 
226  |   while(connected_socket < 0) {
227  |     sprintf(print_buf, "Going to accept connections on socket : %d\n",listening_socket); log_print(print_buf); strcpy(print_buf, "");
228  | /* XXX joao - ? - why is this here?
229  | fflush(NULL);
230  | */
231  | 
232  |     connected_socket = accept(listening_socket, NULL, NULL);
233  |     if (connected_socket < 0) {
234  |       /* Either a real error occured, or blocking was interrupted for
235  |          some reason.  Only abort execution if a real error occured. */
236  |       if (errno != EINTR) {
237  |         perror("accept");
238  |         close(listening_socket);
239  |         exit(EXIT_FAILURE);
240  |       } else {
241  |         continue;    /* don't return - do the accept again */
242  |       }
243  |     }
244  |   }
245  |   sprintf(print_buf, "client connected.\n"); log_print(print_buf); strcpy(print_buf, "");
246  | 
247  |   return connected_socket;
248  | }
249  | 
250  | /* sock_read() */
251  | /*++++++++++++++++++++++++++++++++++++++
252  | 
253  |    This is just like the read() system call, except that it will make
254  |    sure that all your data goes through the socket.
255  | 
256  |    int    sock_read  The number of bytes read.
257  | 
258  |    int    sockfd    The socket file descriptor.
259  | 
260  |    char   *buf      The buffer to be read from the socket.
261  | 
262  |    size_t count     The number of bytes in the buffer.
263  | 
264  |   More:
265  |   +html+ <PRE>
266  |   Authors:
267  |         ottrey
268  |   +html+ </PRE>
269  |   ++++++++++++++++++++++++++++++++++++++*/
270  | static int sock_read(int sockfd, char *buf, size_t count, unsigned timeout) {
271  |   size_t bytes_read = 0;
272  |   int this_read;
273  | 
274  |   while (bytes_read < count) {
275  |     do
276  |       this_read = read(sockfd, buf, count - bytes_read);
277  |     while ( (this_read < 0) && (errno == EINTR) );
278  |     if (this_read < 0)
279  |       return this_read;
280  |     else if (this_read == 0)
281  |       return bytes_read;
282  |     bytes_read += this_read;
283  |     buf += this_read;
284  |   }
285  | 
286  |   return count;
287  | 
288  | } /* sock_read() */
289  | 
290  | 
291  | /* sock_write() */
292  | /*++++++++++++++++++++++++++++++++++++++
293  | 
294  |    This is just like the write() system call, accept that it will
295  |    make sure that all data is transmitted.
296  | 
297  |    int    sockfd  The socket file descriptor.
298  | 
299  |    char   *buf    The buffer to be written to the socket.
300  | 
301  |    size_t count   The number of bytes in the buffer.
302  | 
303  |   More:
304  |   +html+ <PRE>
305  |   Authors:
306  |         ottrey
307  | 
308  |   +html+ </PRE><DL COMPACT>
309  |   +html+ <DT>Online References:
310  |   +html+ <DD><UL>
311  |   +html+ </UL></DL>
312  | 
313  |   ++++++++++++++++++++++++++++++++++++++*/
314  | static int sock_write(int sockfd, const char *buf, size_t count, unsigned timeout) {
315  |   size_t  bytes_sent = 0;
316  |   int     this_write;
317  | 
318  | /*
319  |   printf("sock_write = { sockfd=[%d], buf=[%s], count=[%d]\n", sockfd, buf, count);
320  | */
321  |   while (bytes_sent < count) {
322  |     do
323  |       this_write = write(sockfd, buf, count - bytes_sent);
324  |     while ( (this_write < 0) && (errno == EINTR) );
325  |     if (this_write <= 0)
326  |       return this_write;
327  |     bytes_sent += this_write;
328  |     buf += this_write;
329  |   }
330  |   return count;
331  | } /* sock_write() */
332  | 
333  | 
334  | /* SK_gets() */
335  | /*++++++++++++++++++++++++++++++++++++++
336  | 
337  |    This function reads from a socket, until it recieves a linefeed
338  |    character.  It fills the buffer "str" up to the maximum size "count".
339  | 
340  |    int SK_gets  The total_count of bytes read.
341  | 
342  |    int    sockfd    The socket file descriptor.
343  | 
344  |    char   *str      The buffer to be written from the socket.
345  | 
346  |    size_t count     The number of bytes in the buffer.
347  | 
348  |   More:
349  |   +html+ <PRE>
350  |   Authors:
351  |         ottrey
352  | 
353  |   Side Effects:
354  |         This function will return -1 if the socket is closed during the read operation.
355  | 
356  |         Note that if a single line exceeds the length of count, the extra data
357  |         will be read and discarded!  You have been warned.
358  | 
359  |   To Do:
360  |         Capture the control-c properly!
361  | 
362  |   +html+ </PRE>
363  | 
364  |   ++++++++++++++++++++++++++++++++++++++*/
365  | int SK_gets(int sockfd, char *str, size_t count, unsigned timeout) {
366  |   int bytes_read;
367  |   int total_count = 0;
368  |   char *current_position;
369  |   char last_read = 0;
370  | 
371  |   int control_c = 0;
372  | 
373  |   current_position = str;
374  |   while (last_read != 10) {
375  |     bytes_read = read(sockfd, &last_read, 1);
376  |     if (bytes_read <= 0) {
377  |       /* The other side may have closed unexpectedly */
378  |       return SK_DISCONNECT; 
379  |       /* Is this effective on other platforms than linux? */
380  |     }
381  |     if ( (total_count < count) && (last_read != 10) && (last_read !=13) ) {
382  |       *current_position = last_read;
383  |       current_position++;
384  |       total_count++;
385  |     }
386  | 
387  |     if (last_read == -1) {
388  |       bytes_read = read(sockfd, &last_read, 1);
389  |       if (last_read == -12) {
390  |         printf("Client pressed Control-c.\n");
391  |         control_c = 1;
392  |         printf("returning SK_INTERRUPT\n");
393  |         return SK_INTERRUPT;
394  |       }
395  |     }
396  |   }
397  |   if (count > 0) {
398  |     *current_position = 0;
399  |   }
400  | 
401  |   return total_count;
402  | 
403  | } /* SK_gets() */
404  | 
405  | 
406  | /* SK_puts() */
407  | /*++++++++++++++++++++++++++++++++++++++
408  | 
409  |    This function writes a character string out to a socket.
410  | 
411  |    int SK_puts  The total_count of bytes written, 
412  |                 or errors (represented as negative numbers)
413  | 
414  |    int    sockfd    The socket file descriptor.
415  | 
416  |    char   *str      The buffer to be written from the socket.
417  | 
418  |    unsigned timeout  timeout in seconds
419  | 
420  |   More:
421  |   +html+ <PRE>
422  |   Authors:
423  |         ottrey
424  | 
425  |   Side Effects:
426  |         This function will return -1 if the socket is closed during the write operation.
427  | 
428  |         Note that if a single line exceeds the length of count, the extra data
429  |         will be read and discarded!  You have been warned.
430  | 
431  |   +html+ </PRE>
432  | 
433  |   ++++++++++++++++++++++++++++++++++++++*/
434  | int SK_puts(int sockfd, const char *str, unsigned timeout) {
435  | 
436  |   return sock_write(sockfd, str, strlen(str), timeout);
437  | 
438  | } /* SK_puts() */
439  | 
440  | /* SK_putc() */
441  | /*++++++++++++++++++++++++++++++++++++++
442  | 
443  |    int SK_putc This function writes a single character out to a socket.
444  | 
445  |    int sockfd        socket
446  |    char ch           character
447  |    unsigned timeout  timeout in seconds
448  | 
449  |    return number of chars written 
450  | 
451  |   ++++++++++++++++++++++++++++++++++++++*/
452  | int SK_putc(int sockfd, char ch, unsigned timeout) {
453  |   return sock_write(sockfd, &ch, 1, timeout);
454  | }/* SK_putc() */
455  | 
456  | /*++++++++++++++++++++++++++++++++++++++
457  | 
458  |    This function reads a single character from a socket.
459  | 
460  |    returns EOF when no character can be read. 
461  | 
462  |   ++++++++++++++++++++++++++++++++++++++*/
463  | int SK_getc(int sockfd, unsigned timeout) {
464  |   char ch;
465  | 
466  |   if( read(sockfd, &ch, 1) <= 0 ) {
467  |     return EOF;
468  |   }
469  |   else {
470  |     return ch;
471  |   }
472  | }/* SK_getc() */
473  | 
474  | /* SK_getpeername() */
475  | /*++++++++++++++++++++++++++++++++++++++
476  | 
477  |    This function will tell you who is at the other end of a connected stream socket.
478  |    XXX It's not working.
479  |    XXX ? MB it is...
480  | 
481  |    int    sockfd    The socket file descriptor.
482  | 
483  |   More:
484  |   +html+ <PRE>
485  |   Authors:
486  |         ottrey
487  |   +html+ </PRE>
488  | 
489  |   ++++++++++++++++++++++++++++++++++++++*/
490  | char *SK_getpeername(int sockfd) 
491  | {
492  |   char *hostaddress=NULL;
493  |   struct sockaddr_in addr_in;
494  |   int namelen=sizeof(addr_in);
495  |  
496  |   if (getpeername(sockfd, (struct sockaddr *)&addr_in, &namelen) != -1) {
497  |     hostaddress = (char *)malloc(16); /* max length of a valid IPv4 + \0 */
498  |     strcpy(hostaddress, inet_ntoa(addr_in.sin_addr));  /* XXX MT-UNSAFE */
499  |   }
500  | 
501  |   return hostaddress;
502  |   
503  | } /* SK_getpeername() */
504  | 
505  | /* SK_getpeerip */
506  | int SK_getpeerip(int sockfd, ip_addr_t *ip) {
507  |   struct sockaddr_in addr_in;
508  |   int namelen=sizeof(addr_in);
509  |   int ret=-1;
510  | 
511  |   memset(& addr_in, 0, sizeof(struct sockaddr_in));
512  | 
513  |   if (getpeername(sockfd, (struct sockaddr *)(& addr_in), &namelen) != -1) {
514  |     ret=0;
515  |     IP_addr_s2b(ip, &addr_in, namelen);
516  |   }
517  |   
518  |   return ret;
519  | }
520  | 
521  | /*-------------------------------------------------------------------
522  |  *   CD varieties of the functions: broken connections get registered
523  |  *   in the connection structure within the query environment 
524  |  *   as side effects.
525  |  * -----------------------------------------------------------------*/
526  | 
527  | /* SK_cd_puts() */
528  | /*++++++++++++++++++++++++++++++++++++++
529  | 
530  |    This function writes a character string out to a socket.
531  | 
532  |    int SK_qe_puts  The total_count of bytes written, 
533  |                 or errors (represented as negative numbers)
534  | 
535  |    sk_conn_st *condat connection data
536  | 
537  |    char   *str       The buffer to be written from the socket.
538  | 
539  |    unsigned timeout  timeout in seconds
540  | 
541  |   More:
542  |        if the connection structure has bad status for this connection
543  |        from previous calls, no write will be attempted.
544  | 
545  |   +html+ <PRE>
546  |   Authors:
547  |         marek
548  | 	
549  | 
550  |   Side Effects:
551  |        broken connections get registered
552  |        in the connection structure within the query environment 
553  | 	
554  |   +html+ </PRE>
555  | 
556  |   ++++++++++++++++++++++++++++++++++++++*/
557  | int SK_cd_puts(sk_conn_st *condat, const char *str)
558  | {
559  | int res=SK_puts(condat->sock, str, condat->wr_timeout );
560  | 
561  |   if( res < 0 ){
562  |     switch( - res ) {
563  |       /* dont know what to do and how to log */
564  |     case SK_DISCONNECT:
565  |     case SK_INTERRUPT:
566  |       /*("Thread received a control-c\n");*/
567  |     case SK_TIMEOUT:
568  |       /*("Reading timed out\n");*/
569  |       break;
570  |     default:
571  |       /* unexpected error code. bail out */
572  |       die;
573  |     }
574  |   }
575  | }
576  | 
577  | 
578  | 
579  | /* SK_cd_gets() */
580  | /*++++++++++++++++++++++++++++++++++++++
581  | 
582  |    Wrapper around SK_gets.
583  | 
584  |    int SK_qe_gets  The total_count of bytes read, 
585  |                    or errors (represented as negative numbers)
586  | 
587  |    sk_conn_st *condat connection data
588  | 
589  |    char   *str       The buffer to be written from the socket.
590  | 
591  |   More:
592  |        if the connection structure has bad status for this connection
593  |        from previous calls, no write will be attempted.
594  | 
595  |   +html+ <PRE>
596  |   Authors:
597  |         marek
598  | 	
599  | 
600  |   Side Effects:
601  |        broken connections get registered
602  |        in the connection structure within the query environment 
603  |        
604  |   +html+ </PRE>
605  | 
606  |   ++++++++++++++++++++++++++++++++++++++*/
607  | int SK_cd_gets(sk_conn_st *condat, char *str, size_t count)
608  | {
609  |   int res=SK_gets(condat->sock, str, count, condat->wr_timeout);
610  | 		  
611  |   if( res < 0 ){
612  |     switch( res ) {
613  |       /* dont know what to do and how to log */
614  |     case SK_DISCONNECT:
615  |     case SK_INTERRUPT:
616  |       /*("Thread received a control-c\n");*/
617  |     case SK_TIMEOUT:
618  |       /*("Reading timed out\n");*/
619  |       break;
620  |     default:
621  |       /* unexpected error code. bail out */
622  |       die;
623  |     }
624  |   }
625  | }
626  | 
627  | 
628  | int SK_cd_close(sk_conn_st *condat)
629  | {
630  |   SK_close(condat->sock);
631  | }