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