Source File sk/cd_socket.c

    1    | /***************************************
    2    |   $Revision: 1.6 $
    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,2001,2002                     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   |
    34   | #include "rip.h"
    35   |
    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   |   UT_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  |
    108  |   Side Effects:
    109  |        broken connections get registered in the connection structure
    110  |
    111  |   +html+ </PRE>
    112  |
    113  |   ++++++++++++++++++++++++++++++++++++++*/
    114  | int SK_cd_puts(sk_conn_st *condat, const char *str)
    115  | {
    116  |   int res;
    117  |   struct timeval *ptm;
    118  |
    119  |   /* if we're not connected, return our status */
    120  |   if (condat->rtc != 0)  {
    121  |     return (-condat->rtc);
    122  |   }
    123  |
    124  |   /* bad design to use 0 to mean "infinity", but we'll keep it because
    125  |      that's the current implementation - shane */
    126  |   ptm = &condat->rd_timeout;
    127  |   if ((ptm->tv_sec == 0) && (ptm->tv_usec == 0)) { /* if timeout 0,
    128  | 						      do blocking I/O */
    129  |     ptm = NULL;
    130  |   }
    131  |
    132  |   /* use SK_puts() to do the actual work */
    133  |   res = SK_puts(condat->sock, str, ptm);
    134  |
    135  |   /* if timed out (or some other error), then set the rtc variable */
    136  |   if (res < 0) {
    137  |     condat->rtc |= SK_DISCONNECT;
    138  |     res = -SK_DISCONNECT;
    139  |   }
    140  |
    141  |   /* return documented value */
    142  |   return res;
    143  | } /* SK_cd_puts() */
    144  |
    145  | /* SK_cd_gets() */
    146  | /*++++++++++++++++++++++++++++++++++++++
    147  |
    148  |   Read from a socket, until a linefeed character is received or the buffer
    149  |   fills up to the maximum size "count". If the connection data has non-zero
    150  |   timeout value for reading, it is used here between calls to read
    151  |   the next 1 character.
    152  |
    153  |    int SK_cd_gets      Returns the total_count of bytes read,
    154  |                        or inverted error codes (negative numbers):
    155  | 		       (- SK_DISCONNECT) on broken connection,
    156  | 		       (- SK_TIMEOUT)    on timeout.
    157  |
    158  |    sk_conn_st *condat  connection data
    159  |
    160  |    char   *str         The buffer to store the data received from
    161  |                        the socket.
    162  |
    163  |    size_t count        size of the buffer.
    164  |
    165  |   More:
    166  |        if the connection structure has bad status for this connection
    167  |        from previous calls, no read will be attempted.
    168  |
    169  |   +html+ <PRE>
    170  |   Author:
    171  |         marek
    172  |
    173  |   Side Effects:
    174  |        broken connections get registered in the connection structure.
    175  |
    176  |   +html+ </PRE>
    177  |
    178  |   ++++++++++++++++++++++++++++++++++++++*/
    179  | int SK_cd_gets(sk_conn_st *condat, char *str, size_t count)
    180  | {
    181  |   fd_set rset;
    182  |   struct timeval *ptm = & condat->rd_timeout;
    183  |   int readcount = 0;
    184  |
    185  |   memset( str, 0, count);
    186  |   /* leave space for \0 */
    187  |   count--;
    188  |
    189  |   FD_ZERO( &rset );
    190  |   FD_SET( condat->sock, &rset );
    191  |
    192  |   if( ptm->tv_sec == 0 && ptm->tv_usec == 0) { /* if timeout undefined,
    193  | 						  do blocking I/O */
    194  |     ptm = NULL;
    195  |   }
    196  |
    197  |   do {
    198  |     char buf[2];
    199  |     int sel = select( (condat->sock)+1, &rset, NULL, NULL, ptm);
    200  |
    201  |     if (sel < 0) {
    202  |       /* unfortunate, but bad things happen to good sockets - SK */
    203  |       ER_perror(FAC_SK, SK_SELECT, "(%d) %s", errno, strerror(errno));
    204  |       break;
    205  |     }
    206  |
    207  |     if( sel == 0 ) {
    208  |       condat->rtc |= SK_TIMEOUT;
    209  |       break;
    210  |     }
    211  |
    212  |     else {
    213  |       if(read( condat->sock, buf, 1) == 0 ) {
    214  | 	condat->rtc |= SK_DISCONNECT;
    215  | 	break;
    216  |       }
    217  |       str[readcount] = buf[0];
    218  |       readcount++;
    219  |       if( buf[0] == '\n' ) {
    220  | 	break;
    221  |       }
    222  |     }
    223  |   } while( readcount < count );
    224  |
    225  |   return readcount;
    226  |
    227  | } /* SK_cd_gets() */
    228  |
    229  |
    230  | /*++++++++++++++++++++++++++++++++++++++
    231  |   Wrapper around the close(2) system call,
    232  |
    233  |   int SK_cd_close         returns the error codes of close(2).
    234  |
    235  |   sk_conn_st *condat      Pointer to the connection data structure.
    236  |
    237  |     +html+ <PRE>
    238  |   Author:
    239  |         marek
    240  |     +html+ </PRE>
    241  |   ++++++++++++++++++++++++++++++++++++++*/
    242  | int SK_cd_close(sk_conn_st *condat) {
    243  |   return SK_close(condat->sock);
    244  | } /* SK_cd_close() */
    245  |
    246  |
    247  | /* SK_cd_printf() */
    248  | /*++++++++++++++++++++++++++++++++++++++
    249  |
    250  |   Printf-like function to print to socket/file specified by connection
    251  |   data structure. First writes the text to a temporary buffer, then
    252  |   uses SK_cd_puts to print it. Maintains a 2K static buffer, and allocates
    253  |   more memory if this is not enough.
    254  |
    255  |   int SK_cd_printf       Returns the SK_cd_puts error code/return value.
    256  |
    257  |   sk_conn_st *condat     Pointer to the connection data structure.
    258  |
    259  |   char *txt              Format text to be written
    260  |
    261  |   ...                    more arguments (like printf)
    262  |
    263  |
    264  |     +html+ <PRE>
    265  |   Author:
    266  |         marek
    267  |     +html+ </PRE>
    268  |   ++++++++++++++++++++++++++++++++++++++*/
    269  | int SK_cd_printf(sk_conn_st *condat, char *txt, ...)
    270  | {
    271  | #define SKBUFLEN 2047
    272  |   va_list   ap;
    273  |   char      buffer[SKBUFLEN+1];
    274  |   unsigned  len;
    275  |   char      *newbuf = NULL;
    276  |   char      *finalbuf = buffer; /* points to where the text REALLY is */
    277  |
    278  |   /* vsnprintf returns the number of character it WOULD write if it could.
    279  |      So we assume the buffer to be of adequate size for most cases,
    280  |      and if it isn't, then we allocate to newbuf and call v*printf again
    281  |   */
    282  |   va_start(ap, txt);
    283  |   len = vsnprintf(buffer, SKBUFLEN, txt, ap);
    284  |   va_end(ap);
    285  |
    286  |   if( len > SKBUFLEN ) {
    287  |     newbuf = (char *)UT_malloc(len+1);
    288  |
    289  |     va_start(ap, txt);
    290  |     vsnprintf(newbuf, len, txt, ap);
    291  |     va_end(ap);
    292  |
    293  |     finalbuf = newbuf;
    294  |   }
    295  |   /* terminate */
    296  |   finalbuf[len] = 0;
    297  |
    298  |   /* reuse len */
    299  |   len = SK_cd_puts(condat, finalbuf);
    300  |
    301  |   if(newbuf != NULL) {
    302  |     UT_free(newbuf);
    303  |   }
    304  |
    305  |   return len;
    306  | } /* SK_cd_printf() */