Source File modules/sk/socket.c

    1    | /***************************************
    2    |   $Revision: 1.16 $
    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_cd_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() */
    613  |
    614  |
    615  | int SK_cd_printf(sk_conn_st *condat, char *txt, ...)
    616  | {
    617  | #define SKBUFLEN 2047
    618  |   va_list   ap;
    619  |   char      buffer[SKBUFLEN+1];
    620  |   int       len;
    621  |   char      *newbuf = NULL;
    622  |   char      *finalbuf = buffer; /* points to where the text REALLY is */
    623  |
    624  |   /* vsnprintf returns the number of character it WOULD write if it could.
    625  |      So we assume the buffer to be of adequate size for most cases,
    626  |      and if it isn't, then we allocate to newbuf and call v*printf again
    627  |   */
    628  |   va_start(ap, txt);
    629  |   len = vsnprintf(buffer, SKBUFLEN, txt, ap);
    630  |   va_end(ap);
    631  |
    632  |   if( len > SKBUFLEN ) {
    633  |     dieif(!NOERR(wr_malloc( (void **)& newbuf, len+1)));
    634  |
    635  |     va_start(ap, txt);
    636  |     vsnprintf(newbuf, len, txt, ap);
    637  |     va_end(ap);
    638  |
    639  |     finalbuf = newbuf;
    640  |   }
    641  |   /* terminate */
    642  |   finalbuf[len] = 0;
    643  |
    644  |   /* reuse len */
    645  |   len = SK_cd_puts(condat, finalbuf);
    646  |
    647  |   if(newbuf != NULL) {
    648  |     wr_free(newbuf);
    649  |   }
    650  |
    651  |   return len;
    652  | }