Source File modules/sk/cd_socket.c

    1    | /***************************************
    2    |   $Revision: 1.2 $
    3    |
    4    |   Socket module - cd_socket.c - basic read/write socket routines defined
    5    |                                 in terms of connection data structures
    6    | 				with timeouts and storing information about
    7    | 				broken connections.
    8    |
    9    |   Status: NOT REVUED, TESTED
    10   |
    11   |   Design and implementation by Marek Bukowy.
    12   |
    13   |   ******************/ /******************
    14   |   Copyright (c) 1999, 2000                           RIPE NCC
    15   |
    16   |   All Rights Reserved
    17   |
    18   |   Permission to use, copy, modify, and distribute this software and its
    19   |   documentation for any purpose and without fee is hereby granted,
    20   |   provided that the above copyright notice appear in all copies and that
    21   |   both that copyright notice and this permission notice appear in
    22   |   supporting documentation, and that the name of the author not be
    23   |   used in advertising or publicity pertaining to distribution of the
    24   |   software without specific, written prior permission.
    25   |
    26   |   THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
    27   |   ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL
    28   |   AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
    29   |   DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
    30   |   AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    31   |   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    32   |   ***************************************/
    33   | #include "sk.h"
    34   | #include "stubs.h"
    35   | #include "memwrap.h"
    36   | /*+
    37   |  * -------------------------------------------------------------------
    38   |  * CD (connection data structure) varieties of the functions:
    39   |  *   broken connections get registered in the connection structure
    40   |  *   as side effects.
    41   |  * by marek
    42   |  * -----------------------------------------------------------------
    43   | +*/
    44   |
    45   | /* SK_cd_make */
    46   | /*++++++++++++++++++++++++++++++++++++++
    47   |
    48   |   Construct a connection data given the socket or file descriptor.
    49   |   Also performs the getpeername check and stores the IP in an allocated
    50   |   string.
    51   |
    52   |   sk_conn_st *condat    pointer to where the data is to be stored.
    53   |
    54   |   int  sock             The socket or file descriptor.
    55   |
    56   |   unsigned timeout      Read timeout (used in SK_cd_gets) in seconds.
    57   |                         Value of 0 disables the timeout.
    58   |   ++++++++++++++++++++++++++++++++++++++*/
    59   | void SK_cd_make(sk_conn_st *condat, int  sock, unsigned timeout)
    60   | {
    61   |   memset(condat, 0, sizeof(sk_conn_st));
    62   |
    63   |   condat->sock = sock;
    64   |
    65   |   condat->ip = SK_getpeername(sock);
    66   |   dieif(condat->ip == NULL);
    67   |
    68   |   SK_getpeerip(sock, &(condat->rIP));
    69   |   condat->eIP =  condat->rIP;
    70   |
    71   |   condat->rd_timeout.tv_sec = timeout;
    72   | }
    73   |
    74   |
    75   | /*++++++++++++++++++++++++++++++++++++++
    76   |   Destroys the data allocated and anchored by the connection data structure.
    77   |
    78   |   sk_conn_st *condat   Pointer to the connection data structure.
    79   |
    80   |   ++++++++++++++++++++++++++++++++++++++*/
    81   | void SK_cd_free(sk_conn_st *condat)
    82   | {
    83   |   wr_free(condat->ip);
    84   | }
    85   |
    86   | /* SK_cd_puts() */
    87   | /*++++++++++++++++++++++++++++++++++++++
    88   |
    89   |    This function writes a character string out to a socket, unless
    90   |    the connection is broken.
    91   |
    92   |    int SK_cd_puts         Returns the total_count of bytes written,
    93   |                           or inverted error codes (negative numbers):
    94   | 			  (- SK_DISCONNECT) on broken connection,
    95   | 			  (- SK_INTERRUPT)  on control-c received,
    96   | 			  (- SK_TIMEOUT)    on timeout.
    97   |
    98   |    sk_conn_st *condat     Pointer to the connection data structure.
    99   |
    100  |    char   *str            The buffer to be written to the socket.
    101  |
    102  |   More:
    103  |        if the connection structure has bad status for this connection
    104  |        from previous calls, no write will be attempted.
    105  |
    106  |   +html+ <PRE>
    107  |   Author:
    108  |         marek
    109  |
    110  |   Side Effects:
    111  |        broken connections get registered in the connection structure
    112  |
    113  |   +html+ </PRE>
    114  |
    115  |   ++++++++++++++++++++++++++++++++++++++*/
    116  | int SK_cd_puts(sk_conn_st *condat, const char *str)
    117  | {
    118  |   int res;
    119  |
    120  |   if( condat->rtc != 0 ) {
    121  |     return (-condat->rtc);
    122  |   }
    123  |
    124  |   res = SK_puts(condat->sock, str);
    125  |
    126  |   if( res < 0 ){
    127  |     /* set the corresponding rtc flag */
    128  |     condat->rtc |= (-res);
    129  |
    130  |     switch( - res ) {
    131  |       /* dont know what to do and how to log */
    132  |     case SK_DISCONNECT:
    133  |     case SK_INTERRUPT:
    134  |       /*("Thread received a control-c\n");*/
    135  |     case SK_TIMEOUT:
    136  |       /*("Reading timed out\n");*/
    137  |       break;
    138  |     default:
    139  |       /* unexpected error code. bail out */
    140  |       die;
    141  |     }
    142  |   }
    143  |   return res;
    144  | } /* SK_cd_puts() */
    145  |
    146  | /* SK_cd_gets() */
    147  | /*++++++++++++++++++++++++++++++++++++++
    148  |
    149  |   Read from a socket, until a linefeed character is received or the buffer
    150  |   fills up to the maximum size "count". If the connection data has non-zero
    151  |   timeout value for reading, it is used here between calls to read
    152  |   the next 1 character.
    153  |
    154  |    int SK_cd_gets      Returns the total_count of bytes read,
    155  |                        or inverted error codes (negative numbers):
    156  | 		       (- SK_DISCONNECT) on broken connection,
    157  | 		       (- SK_TIMEOUT)    on timeout.
    158  |
    159  |    sk_conn_st *condat  connection data
    160  |
    161  |    char   *str         The buffer to store the data received from
    162  |                        the socket.
    163  |
    164  |    size_t count        size of the buffer.
    165  |
    166  |   More:
    167  |        if the connection structure has bad status for this connection
    168  |        from previous calls, no read will be attempted.
    169  |
    170  |   +html+ <PRE>
    171  |   Author:
    172  |         marek
    173  |
    174  |   Side Effects:
    175  |        broken connections get registered in the connection structure.
    176  |
    177  |   +html+ </PRE>
    178  |
    179  |   ++++++++++++++++++++++++++++++++++++++*/
    180  | int SK_cd_gets(sk_conn_st *condat, char *str, size_t count)
    181  | {
    182  |   fd_set rset;
    183  |   struct timeval *ptm = & condat->rd_timeout;
    184  |   int readcount = 0;
    185  |
    186  |   memset( str, 0, count);
    187  |   /* leave space for \0 */
    188  |   count--;
    189  |
    190  |   FD_ZERO( &rset );
    191  |   FD_SET( condat->sock, &rset );
    192  |
    193  |   if( ptm->tv_sec == 0 && ptm->tv_usec == 0) { /* if timeout undefined,
    194  | 						  do blocking I/O */
    195  |     ptm = NULL;
    196  |   }
    197  |
    198  |   do {
    199  |     char buf[2];
    200  |     int sel = select( (condat->sock)+1, &rset, NULL, NULL, ptm);
    201  |     int ern = errno;
    202  |
    203  |     dieif(sel < 0); /* we don't expect problems */
    204  |
    205  |     if( sel == 0 ) {
    206  |       condat->rtc |= SK_TIMEOUT;
    207  |       break;
    208  |     }
    209  |
    210  |     else {
    211  |       if(read( condat->sock, buf, 1) == 0 ) {
    212  | 	condat->rtc |= SK_DISCONNECT;
    213  | 	break;
    214  |       }
    215  |       str[readcount] = buf[0];
    216  |       readcount++;
    217  |       if( buf[0] == '\n' ) {
    218  | 	break;
    219  |       }
    220  |     }
    221  |   } while( readcount < count );
    222  |
    223  |   return readcount;
    224  |
    225  | } /* SK_cd_gets() */
    226  |
    227  |
    228  | /*++++++++++++++++++++++++++++++++++++++
    229  |   Wrapper around the close(2) system call,
    230  |
    231  |   int SK_cd_close         returns the error codes of close(2).
    232  |
    233  |   sk_conn_st *condat      Pointer to the connection data structure.
    234  |
    235  |     +html+ <PRE>
    236  |   Author:
    237  |         marek
    238  |     +html+ </PRE>
    239  |   ++++++++++++++++++++++++++++++++++++++*/
    240  | int SK_cd_close(sk_conn_st *condat) {
    241  |   return SK_close(condat->sock);
    242  | } /* SK_cd_close() */
    243  |
    244  |
    245  | /* SK_cd_printf() */
    246  | /*++++++++++++++++++++++++++++++++++++++
    247  |
    248  |   Printf-like function to print to socket/file specified by connection
    249  |   data structure. First writes the text to a temporary buffer, then
    250  |   uses SK_cd_puts to print it. Maintains a 2K static buffer, and allocates
    251  |   more memory if this is not enough.
    252  |
    253  |   int SK_cd_printf       Returns the SK_cd_puts error code/return value.
    254  |
    255  |   sk_conn_st *condat     Pointer to the connection data structure.
    256  |
    257  |   char *txt              Format text to be written
    258  |
    259  |   ...                    more arguments (like printf)
    260  |
    261  |
    262  |     +html+ <PRE>
    263  |   Author:
    264  |         marek
    265  |     +html+ </PRE>
    266  |   ++++++++++++++++++++++++++++++++++++++*/
    267  | int SK_cd_printf(sk_conn_st *condat, char *txt, ...)
    268  | {
    269  | #define SKBUFLEN 2047
    270  |   va_list   ap;
    271  |   char      buffer[SKBUFLEN+1];
    272  |   unsigned  len;
    273  |   char      *newbuf = NULL;
    274  |   char      *finalbuf = buffer; /* points to where the text REALLY is */
    275  |
    276  |   /* vsnprintf returns the number of character it WOULD write if it could.
    277  |      So we assume the buffer to be of adequate size for most cases,
    278  |      and if it isn't, then we allocate to newbuf and call v*printf again
    279  |   */
    280  |   va_start(ap, txt);
    281  |   len = vsnprintf(buffer, SKBUFLEN, txt, ap);
    282  |   va_end(ap);
    283  |
    284  |   if( len > SKBUFLEN ) {
    285  |     dieif(!NOERR(wr_malloc( (void **)& newbuf, len+1)));
    286  |
    287  |     va_start(ap, txt);
    288  |     vsnprintf(newbuf, len, txt, ap);
    289  |     va_end(ap);
    290  |
    291  |     finalbuf = newbuf;
    292  |   }
    293  |   /* terminate */
    294  |   finalbuf[len] = 0;
    295  |
    296  |   /* reuse len */
    297  |   len = SK_cd_puts(condat, finalbuf);
    298  |
    299  |   if(newbuf != NULL) {
    300  |     wr_free(newbuf);
    301  |   }
    302  |
    303  |   return len;
    304  | } /* SK_cd_printf() */