1    | /***************************************
2    |   $Revision: 1.10 $
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   | #include "memwrap.h"
32   | 
33   | extern int h_errno;
34   | 
35   | 
36   | /*+ String sizes +*/
37   | #define STR_S   63
38   | #define STR_M   255
39   | #define STR_L   1023
40   | #define STR_XL  4095
41   | #define STR_XXL 16383
42   | 
43   | static void log_print(const char *arg) {
44   |   FILE *logf;
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 reuse_addr = 1;
170  | 
171  |   /* Setup internet address information.  
172  |      This is used with the bind() call */
173  |   memset((char *) &address, 0, sizeof(address));
174  |   address.sin_family = AF_INET;
175  |   address.sin_port = port;
176  |   address.sin_addr.s_addr = bind_address;
177  | 
178  |   /* Map all of the signals and exit routine */
179  |   atexit(func_atexit);
180  |   /* signal.h has a full list of signal names */
181  |   //signal(SIGHUP, func_sighup); This should be handled in a different way (thread)
182  |   //signal(SIGINT, func_sigint);
183  | 
184  |   listening_socket = socket(AF_INET, socket_type, 0);
185  |   if (listening_socket < 0) {
186  |     perror("socket");
187  |     exit(EXIT_FAILURE);
188  |   }
189  | 
190  |   setsockopt(listening_socket, SOL_SOCKET, SO_REUSEADDR, (void *)&reuse_addr, sizeof(reuse_addr));
191  | 
192  |   if (bind(listening_socket, (struct sockaddr *) &address, sizeof(address)) < 0) {
193  |     perror("bind");
194  |     close(listening_socket);
195  |     exit(EXIT_FAILURE);
196  |   }
197  | 
198  | 
199  |   if (socket_type == SOCK_STREAM) {
200  |     listen(listening_socket, 5); /* Queue up to five connections before
201  |                                   having them automatically rejected. */
202  |   }
203  | 
204  |   return listening_socket;
205  | } /* SK_getsock() */
206  | 
207  | /*++++++++++++++++++++++++++++++++++++++
208  | 
209  |    Wait for an incoming connection on the specified socket
210  | 
211  |    int	SK_accept_connection The socket for communicating to the client
212  | 
213  |    int  listening_socket     The socket that the server is bound to
214  | 
215  |   More:
216  |   +html+ <PRE>
217  |   Authors:
218  | 	joao
219  |   +html+ </PRE>
220  |   ++++++++++++++++++++++++++++++++++++++*/
221  | int SK_accept_connection(int listening_socket) {
222  |   int connected_socket = -1;
223  |   char print_buf[STR_L];
224  | 
225  |   while(connected_socket < 0) {
226  |     sprintf(print_buf, "Going to accept connections on socket : %d\n",listening_socket); log_print(print_buf); strcpy(print_buf, "");
227  | /* XXX joao - ? - why is this here?
228  | fflush(NULL);
229  | */
230  | 
231  |     connected_socket = accept(listening_socket, NULL, NULL);
232  |     if (connected_socket < 0) {
233  |       /* Either a real error occured, or blocking was interrupted for
234  |          some reason.  Only abort execution if a real error occured. */
235  |       if (errno != EINTR) {
236  |         perror("accept");
237  |         close(listening_socket);
238  |         exit(EXIT_FAILURE);
239  |       } else {
240  |         continue;    /* don't return - do the accept again */
241  |       }
242  |     }
243  |   }
244  |   sprintf(print_buf, "client connected.\n"); log_print(print_buf); strcpy(print_buf, "");
245  | 
246  |   return connected_socket;
247  | }
248  | 
249  | /* sock_read() */
250  | /*++++++++++++++++++++++++++++++++++++++
251  | 
252  |    This is just like the read() system call, except that it will make
253  |    sure that all your data goes through the socket.
254  | 
255  |    int    sock_read  The number of bytes read.
256  | 
257  |    int    sockfd    The socket file descriptor.
258  | 
259  |    char   *buf      The buffer to be read from the socket.
260  | 
261  |    size_t count     The number of bytes in the buffer.
262  | 
263  |   More:
264  |   +html+ <PRE>
265  |   Authors:
266  |         ottrey
267  |   +html+ </PRE>
268  |   ++++++++++++++++++++++++++++++++++++++*/
269  | static int sock_read(int sockfd, char *buf, size_t count, unsigned timeout) {
270  |   size_t bytes_read = 0;
271  |   int this_read;
272  | 
273  |   while (bytes_read < count) {
274  |     do
275  |       this_read = read(sockfd, buf, count - bytes_read);
276  |     while ( (this_read < 0) && (errno == EINTR) );
277  |     if (this_read < 0)
278  |       return this_read;
279  |     else if (this_read == 0)
280  |       return bytes_read;
281  |     bytes_read += this_read;
282  |     buf += this_read;
283  |   }
284  | 
285  |   return count;
286  | 
287  | } /* sock_read() */
288  | 
289  | 
290  | /* sock_write() */
291  | /*++++++++++++++++++++++++++++++++++++++
292  | 
293  |    This is just like the write() system call, accept that it will
294  |    make sure that all data is transmitted.
295  | 
296  |    int    sockfd  The socket file descriptor.
297  | 
298  |    char   *buf    The buffer to be written to the socket.
299  | 
300  |    size_t count   The number of bytes in the buffer.
301  | 
302  |   More:
303  |   +html+ <PRE>
304  |   Authors:
305  |         ottrey
306  | 
307  |   +html+ </PRE><DL COMPACT>
308  |   +html+ <DT>Online References:
309  |   +html+ <DD><UL>
310  |   +html+ </UL></DL>
311  | 
312  |   ++++++++++++++++++++++++++++++++++++++*/
313  | static int sock_write(int sockfd, const char *buf, size_t count, unsigned timeout) {
314  |   size_t  bytes_sent = 0;
315  |   int     this_write;
316  | 
317  | /*
318  |   printf("sock_write = { sockfd=[%d], buf=[%s], count=[%d]\n", sockfd, buf, count);
319  | */
320  |   while (bytes_sent < count) {
321  |     do
322  |       this_write = write(sockfd, buf, count - bytes_sent);
323  |     while ( (this_write < 0) && (errno == EINTR) );
324  |     if (this_write <= 0)
325  |       return this_write;
326  |     bytes_sent += this_write;
327  |     buf += this_write;
328  |   }
329  |   return count;
330  | } /* sock_write() */
331  | 
332  | 
333  | /* SK_gets() */
334  | /*++++++++++++++++++++++++++++++++++++++
335  | 
336  |    This function reads from a socket, until it recieves a linefeed
337  |    character.  It fills the buffer "str" up to the maximum size "count".
338  | 
339  |    int SK_gets  The total_count of bytes read.
340  | 
341  |    int    sockfd    The socket file descriptor.
342  | 
343  |    char   *str      The buffer to be written from the socket.
344  | 
345  |    size_t count     The number of bytes in the buffer.
346  | 
347  |   More:
348  |   +html+ <PRE>
349  |   Authors:
350  |         ottrey
351  | 
352  |   Side Effects:
353  |         This function will return -1 if the socket is closed during the read operation.
354  | 
355  |         Note that if a single line exceeds the length of count, the extra data
356  |         will be read and discarded!  You have been warned.
357  | 
358  |   To Do:
359  |         Capture the control-c properly!
360  | 
361  |   +html+ </PRE>
362  | 
363  |   ++++++++++++++++++++++++++++++++++++++*/
364  | int SK_gets(int sockfd, char *str, size_t count, unsigned timeout) {
365  |   int bytes_read;
366  |   int total_count = 0;
367  |   char *current_position;
368  |   char last_read = 0;
369  | 
370  |   int control_c = 0;
371  | 
372  |   current_position = str;
373  |   while (last_read != 10) {
374  |     bytes_read = read(sockfd, &last_read, 1);
375  |     if (bytes_read <= 0) {
376  |       /* The other side may have closed unexpectedly */
377  |       return SK_DISCONNECT; 
378  |       /* Is this effective on other platforms than linux? */
379  |     }
380  |     if ( (total_count < count) && (last_read != 10) && (last_read !=13) ) {
381  |       *current_position = last_read;
382  |       current_position++;
383  |       total_count++;
384  |     }
385  | 
386  |     if (last_read == -1) {
387  |       bytes_read = read(sockfd, &last_read, 1);
388  |       if (last_read == -12) {
389  |         printf("Client pressed Control-c.\n");
390  |         control_c = 1;
391  |         printf("returning SK_INTERRUPT\n");
392  |         return SK_INTERRUPT;
393  |       }
394  |     }
395  |   }
396  |   if (count > 0) {
397  |     *current_position = 0;
398  |   }
399  | 
400  |   return total_count;
401  | 
402  | } /* SK_gets() */
403  | 
404  | 
405  | /* SK_puts() */
406  | /*++++++++++++++++++++++++++++++++++++++
407  | 
408  |    This function writes a character string out to a socket.
409  | 
410  |    int SK_puts  The total_count of bytes written, 
411  |                 or errors (represented as negative numbers)
412  | 
413  |    int    sockfd    The socket file descriptor.
414  | 
415  |    char   *str      The buffer to be written from the socket.
416  | 
417  |    unsigned timeout  timeout in seconds
418  | 
419  |   More:
420  |   +html+ <PRE>
421  |   Authors:
422  |         ottrey
423  | 
424  |   Side Effects:
425  |         This function will return -1 if the socket is closed during the write operation.
426  | 
427  |         Note that if a single line exceeds the length of count, the extra data
428  |         will be read and discarded!  You have been warned.
429  | 
430  |   +html+ </PRE>
431  | 
432  |   ++++++++++++++++++++++++++++++++++++++*/
433  | int SK_puts(int sockfd, const char *str, unsigned timeout) {
434  | 
435  |   return sock_write(sockfd, str, strlen(str), timeout);
436  | 
437  | } /* SK_puts() */
438  | 
439  | /* SK_putc() */
440  | /*++++++++++++++++++++++++++++++++++++++
441  | 
442  |    int SK_putc This function writes a single character out to a socket.
443  | 
444  |    int sockfd        socket
445  |    char ch           character
446  |    unsigned timeout  timeout in seconds
447  | 
448  |    return number of chars written 
449  | 
450  |   ++++++++++++++++++++++++++++++++++++++*/
451  | int SK_putc(int sockfd, char ch, unsigned timeout) {
452  |   return sock_write(sockfd, &ch, 1, timeout);
453  | }/* SK_putc() */
454  | 
455  | /*++++++++++++++++++++++++++++++++++++++
456  | 
457  |    This function reads a single character from a socket.
458  | 
459  |    returns EOF when no character can be read. 
460  | 
461  |   ++++++++++++++++++++++++++++++++++++++*/
462  | int SK_getc(int sockfd, unsigned timeout) {
463  |   char ch;
464  | 
465  |   if( read(sockfd, &ch, 1) <= 0 ) {
466  |     return EOF;
467  |   }
468  |   else {
469  |     return ch;
470  |   }
471  | }/* SK_getc() */
472  | 
473  | /* SK_getpeername() */
474  | /*++++++++++++++++++++++++++++++++++++++
475  | 
476  |    This function will tell you who is at the other end of a connected stream socket.
477  |    XXX It's not working.
478  |    XXX ? MB it is...
479  | 
480  |    int    sockfd    The socket file descriptor.
481  | 
482  |   More:
483  |   +html+ <PRE>
484  |   Authors:
485  |         ottrey
486  |   +html+ </PRE>
487  | 
488  |   ++++++++++++++++++++++++++++++++++++++*/
489  | char *SK_getpeername(int sockfd) 
490  | {
491  |   char *hostaddress=NULL;
492  |   struct sockaddr_in addr_in;
493  |   int namelen=sizeof(addr_in);
494  |  
495  |   if (getpeername(sockfd, (struct sockaddr *)&addr_in, &namelen) != -1) {
496  |     //hostaddress = (char *)malloc(16); /* max length of a valid IPv4 + \0 */
497  |     dieif( wr_malloc((void **)&hostaddress, 16) != UT_OK); 
498  |     
499  |     strcpy(hostaddress, inet_ntoa(addr_in.sin_addr));  /* XXX MT-UNSAFE */
500  |   }
501  | 
502  |   return hostaddress;
503  |   
504  | } /* SK_getpeername() */
505  | 
506  | /* SK_getpeerip */
507  | int SK_getpeerip(int sockfd, ip_addr_t *ip) {
508  |   struct sockaddr_in addr_in;
509  |   int namelen=sizeof(addr_in);
510  |   int ret=-1;
511  | 
512  |   memset(& addr_in, 0, sizeof(struct sockaddr_in));
513  | 
514  |   if (getpeername(sockfd, (struct sockaddr *)(& addr_in), &namelen) != -1) {
515  |     ret=0;
516  |     IP_addr_s2b(ip, &addr_in, namelen);
517  |   }
518  |   
519  |   return ret;
520  | }
521  | 
522  | /*-------------------------------------------------------------------
523  |  *   CD varieties of the functions: broken connections get registered
524  |  *   in the connection structure within the query environment 
525  |  *   as side effects.
526  |  * -----------------------------------------------------------------*/
527  | 
528  | /* SK_cd_puts() */
529  | /*++++++++++++++++++++++++++++++++++++++
530  | 
531  |    This function writes a character string out to a socket.
532  | 
533  |    int SK_qe_puts  The total_count of bytes written, 
534  |                 or errors (represented as negative numbers)
535  | 
536  |    sk_conn_st *condat connection data
537  | 
538  |    char   *str       The buffer to be written from the socket.
539  | 
540  |    unsigned timeout  timeout in seconds
541  | 
542  |   More:
543  |        if the connection structure has bad status for this connection
544  |        from previous calls, no write will be attempted.
545  | 
546  |   +html+ <PRE>
547  |   Authors:
548  |         marek
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  |   int res=SK_puts(condat->sock, str, condat->wr_timeout );
559  | 
560  |   if( res < 0 ){
561  |     switch( - res ) {
562  |       /* dont know what to do and how to log */
563  |     case SK_DISCONNECT:
564  |     case SK_INTERRUPT:
565  |       /*("Thread received a control-c\n");*/
566  |     case SK_TIMEOUT:
567  |       /*("Reading timed out\n");*/
568  |       break;
569  |     default:
570  |       /* unexpected error code. bail out */
571  |       die;
572  |     }
573  |   }
574  | } /* SK_cd_puts() */
575  | 
576  | /* SK_cd_gets() */
577  | /*++++++++++++++++++++++++++++++++++++++
578  | 
579  |    Wrapper around SK_gets.
580  | 
581  |    int SK_qe_gets  The total_count of bytes read, 
582  |                    or errors (represented as negative numbers)
583  | 
584  |    sk_conn_st *condat connection data
585  | 
586  |    char   *str       The buffer to be written from the socket.
587  | 
588  |   More:
589  |        if the connection structure has bad status for this connection
590  |        from previous calls, no write will be attempted.
591  | 
592  |   +html+ <PRE>
593  |   Authors:
594  |         marek
595  | 	
596  |   Side Effects:
597  |        broken connections get registered
598  |        in the connection structure within the query environment 
599  |        
600  |   +html+ </PRE>
601  | 
602  |   ++++++++++++++++++++++++++++++++++++++*/
603  | int SK_cd_gets(sk_conn_st *condat, char *str, size_t count) {
604  |   int res=SK_gets(condat->sock, str, count, condat->wr_timeout);
605  | 		  
606  |   if( res < 0 ){
607  |     switch( res ) {
608  |       /* dont know what to do and how to log */
609  |     case SK_DISCONNECT:
610  |     case SK_INTERRUPT:
611  |       /*("Thread received a control-c\n");*/
612  |     case SK_TIMEOUT:
613  |       /*("Reading timed out\n");*/
614  |       break;
615  |     default:
616  |       /* unexpected error code. bail out */
617  |       die;
618  |     }
619  |   }
620  | } /* SK_cd_gets() */
621  | 
622  | 
623  | int SK_cd_close(sk_conn_st *condat) {
624  |   SK_close(condat->sock);
625  | } /* SK_cd_close() */