Source File modules/sk/socket.c

    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  | }