## modules/sk/cd_socket.c

/* [<][>][^][v][top][bottom][index][help] */

## DEFINITIONS

This source file includes following functions.

1. SK_cd_make
2. SK_cd_free
3. SK_cd_puts
4. sk_fill_rd_buf
5. main
6. SK_cd_gets
7. SK_cd_close
8. SK_cd_printf

       1 /***************************************
       2   $Revision: 1.8 $
       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)
         /* [<][>][^][v][top][bottom][index][help] */
      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   condat->rd_buf_len = 0;
      74 }
      75
      76
      77 /*++++++++++++++++++++++++++++++++++++++
      78   Destroys the data allocated and anchored by the connection data structure.
      79
      80   sk_conn_st *condat   Pointer to the connection data structure.
      81
      82   ++++++++++++++++++++++++++++++++++++++*/
      83 void SK_cd_free(sk_conn_st *condat)
         /* [<][>][^][v][top][bottom][index][help] */
      84 {
      85   UT_free(condat->ip);
      86 }
      87
      88 /* SK_cd_puts() */
      89 /*++++++++++++++++++++++++++++++++++++++
      90
      91    This function writes a character string out to a socket, unless
      92    the connection is broken.
      93
      94    int SK_cd_puts         Returns the total_count of bytes written,
      95                           or inverted error codes (negative numbers):
      96                           (- SK_DISCONNECT) on broken connection,
      97                           (- SK_INTERRUPT)  on control-c received,
      98                           (- SK_TIMEOUT)    on timeout.
      99
     100    sk_conn_st *condat     Pointer to the connection data structure.
     101
     102    char   *str            The buffer to be written to the socket.
     103
     104   More:
     105        if the connection structure has bad status for this connection
     106        from previous calls, no write will be attempted.
     107
     108   +html+ <PRE>
     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)
         /* [<][>][^][v][top][bottom][index][help] */
     117 {
     118   int res;
     119   struct timeval *ptm;
     120
     121   /* if we're not connected, return our status */
     122   if (condat->rtc != 0)  {
     123     return (-condat->rtc);
     124   }
     125
     126   /* bad design to use 0 to mean "infinity", but we'll keep it because
     127      that's the current implementation - shane */
     128   ptm = &condat->rd_timeout;
     129   if ((ptm->tv_sec == 0) && (ptm->tv_usec == 0)) { /* if timeout 0,
     130                                                       do blocking I/O */
     131     ptm = NULL;
     132   }
     133
     134   /* use SK_puts() to do the actual work */
     135   res = SK_puts(condat->sock, str, ptm);
     136
     137   /* if timed out (or some other error), then set the rtc variable */
     138   if (res < 0) {
     139     condat->rtc |= SK_DISCONNECT;
     140     res = -SK_DISCONNECT;
     141   }
     142
     143   /* return documented value */
     144   return res;
     145 } /* SK_cd_puts() */
     146
     147 /* fill the input buffer as much as possible */
     148 static int
     149 sk_fill_rd_buf (sk_conn_st *condat)
         /* [<][>][^][v][top][bottom][index][help] */
     150 {
     151     fd_set rset;
     152     struct timeval *ptm;
     153     int select_ret;
     154     int rd_buf_free;
     155     int read_ret;
     156
     157     ptm = &(condat->rd_timeout);
     158     /* if timeout is 0, do blocking I/O - bogus, but that's how it is */
     159     if ((ptm->tv_sec == 0) && (ptm->tv_usec == 0)) {
     160         ptm = NULL;
     161     }
     162     FD_ZERO(&rset);
     163     FD_SET(condat->sock, &rset);
     164
     165     /* wait for input to become available */
     166     select_ret = select(condat->sock + 1, &rset, NULL, NULL, ptm);
     167     if (select_ret < 0) {
     168         /* unfortunate, but bad things happen to good sockets - SK */
     169         ER_perror(FAC_SK, SK_SELECT, "(%d) %s", errno, strerror(errno));
     170         return -1;
     171     }
     172     if (select_ret == 0) {
     173         condat->rtc |= SK_TIMEOUT;
     174         return -1;
     175     }
     176
     177     /* calculate maximum amount to read */
     178     rd_buf_free = sizeof(condat->rd_buf) - (condat->rd_buf_len);
     179
     180     /* read up to that much, if available */
     181     read_ret = read(condat->sock,
     182                     condat->rd_buf + condat->rd_buf_len,
     183                     rd_buf_free);
     184     if (read_ret <= 0) {
     185         condat->rtc |= SK_DISCONNECT;
     186         return -1;
     187     }
     188     condat->rd_buf_len += read_ret;
     189
     190     /* return the fact that we got data */
     191     return read_ret;
     192 }
     193
     194 #undef TEST_SK_FILL_RD_BUF
     195
     196 /* test sk_fill_rd_buf() function - full path coverage */
     197 #ifdef TEST_SK_FILL_RD_BUF
     198 #include <unistd.h>
     199 #include <stdio.h>
     200 #include <errno.h>
     201 #include <string.h>
     202
     203 int
     204 main ()
         /* [<][>][^][v][top][bottom][index][help] */
     205 {
     206     sk_conn_st conn;
     207     int pfd[2];
     208     int tmp_fd;
     209     int bogus_fd;
     210     int i;
     211     int buf[INPUT_BUF_LEN+INPUT_BUF_LEN+100];
     212     int fill_buf_ret;
     213
     214     /* test with bogus file descriptor and 0 timeout value */
     215     tmp_fd = open("/dev/null", O_RDONLY);
     216     if (tmp_fd == -1) {
     217         fprintf(stderr, "Error %d creating bogus file descriptor; %s\n",
     218                 errno, strerror(errno));
     219         exit(1);
     220     }
     221     bogus_fd = tmp_fd;
     222     close(tmp_fd);
     223     SK_cd_make(&conn, bogus_fd, 0);
     224     if (sk_fill_rd_buf(&conn) != -1) {
     225         fprintf(stderr, "Filling buffer with bogus file descriptor worked\n");
     226         exit(1);
     227     }
     228
     229     /* create a pipe for further testing */
     230     if (pipe(pfd) != 0) {
     231         fprintf(stderr, "Error %d creating pipe; %s\n", errno, strerror(errno));
     232         exit(1);
     233     }
     234     /* real file descriptor and non-0 timeout value */
     235     SK_cd_make(&conn, pfd[0], 1);
     236
     237     /* test timeout */
     238     if (sk_fill_rd_buf(&conn) != -1) {
     239         fprintf(stderr, "Buffer filling failed to timeout properly\n");
     240         exit(1);
     241     }
     242     if (conn.rtc != SK_TIMEOUT) {
     243         fprintf(stderr, "Timeout didn't set flag properly\n");
     244         exit(1);
     245     }
     246
     247     /* test EOF input */
     248     close(pfd[1]);
     249     conn.rtc = 0;
     250     if (sk_fill_rd_buf(&conn) != -1) {
     251         fprintf(stderr, "Buffer filling failed to timeout properly\n");
     252         exit(1);
     253     }
     254     if (conn.rtc != SK_DISCONNECT) {
     255         fprintf(stderr, "Disconnect didn't set flag properly\n");
     256         exit(1);
     257     }
     258
     259     /* test empty buffer reading various values */
     260     {
     261         int lengths[] =
     262             { 1, 100, INPUT_BUF_LEN-1, INPUT_BUF_LEN,
     263               INPUT_BUF_LEN+1, INPUT_BUF_LEN+100 };
     264         for (i=0; i<sizeof(lengths)/sizeof(lengths[0]); i++) {
     265             close(pfd[0]);
     266             close(pfd[1]);
     267             if (pipe(pfd) != 0) {
     268                 fprintf(stderr, "Error %d creating pipe; %s\n",
     269                         errno, strerror(errno));
     270                 exit(1);
     271             }
     272             SK_cd_make(&conn, pfd[0], 0);
     273             memset(buf, i+1, lengths[i]);
     274             if (write(pfd[1], buf, lengths[i]) != lengths[i]) {
     275                 fprintf(stderr, "Error %d writing to pipe; %s\n",
     276                         errno, strerror(errno));
     277                 exit(1);
     278             }
     279             fill_buf_ret = sk_fill_rd_buf(&conn);
     280             if (fill_buf_ret == -1) {
     281                 fprintf(stderr, "Error filling buffer\n");
     282                 exit(1);
     283             }
     284             if (lengths[i] < INPUT_BUF_LEN) {
     285                 if (fill_buf_ret != lengths[i]) {
     286                     fprintf(stderr, "Error filling buffer\n");
     287                     exit(1);
     288                 }
     289                 if (memcmp(buf, conn.rd_buf, lengths[i]) != 0) {
     290                     fprintf(stderr, "Error with buffer contents\n");
     291                     exit(1);
     292                 }
     293             } else {
     294                 if (fill_buf_ret != INPUT_BUF_LEN) {
     295                     fprintf(stderr, "Error filling buffer\n");
     296                     exit(1);
     297                 }
     298                 if (memcmp(buf, conn.rd_buf, INPUT_BUF_LEN) != 0) {
     299                     fprintf(stderr, "Error with buffer contents\n");
     300                     exit(1);
     301                 }
     302             }
     303         }
     304     }
     305
     306     return 0;
     307 }
     308 #endif
     309
     310 /* SK_cd_gets() */
     311 /*++++++++++++++++++++++++++++++++++++++
     312
     313   Read from a socket, until a linefeed character is received or the buffer
     314   fills up to the maximum size "count". If the connection data has non-zero
     315   timeout value for reading, it is used here between calls to read
     316   the next 1 character.
     317
     318    int SK_cd_gets      Returns the total_count of bytes read,
     319                        or inverted error codes (negative numbers):
     320                        (- SK_DISCONNECT) on broken connection,
     321                        (- SK_TIMEOUT)    on timeout.
     322
     323    sk_conn_st *condat  connection data
     324
     325    char   *str         The buffer to store the data received from
     326                        the socket.
     327
     328    size_t count        size of the buffer.
     329
     330   More:
     331        if the connection structure has bad status for this connection
     332        from previous calls, no read will be attempted.
     333
     334   +html+ <PRE>
     335   Author:
     336         marek
     337
     338   Side Effects:
     339        broken connections get registered in the connection structure.
     340
     341   +html+ </PRE>
     342
     343   ++++++++++++++++++++++++++++++++++++++*/
     344 int SK_cd_gets(sk_conn_st *condat, char *str, size_t count)
         /* [<][>][^][v][top][bottom][index][help] */
     345 {
     346     char *eol;
     347     int line_len;
     348     int amt_to_copy;
     349
     350     /* leave space for terminating '\0' */
     351     count--;
     352
     353     /* we must always return a NUL-terminated string */
     354     str[0] = '\0';
     355
     356     /* track current line length */
     357     line_len = 0;
     358
     359     /* get input if none available */
     360     if (condat->rd_buf_len <= 0) {
     361         if (sk_fill_rd_buf(condat) == -1) {
     362             return line_len;
     363         }
     364     }
     365
     366     for (;;) {
     367         /* we should always have something in the buffer here */
     368         dieif(condat->rd_buf_len <= 0);
     369
     370         /* check for end of line */
     371         eol = memchr(condat->rd_buf, '\n', condat->rd_buf_len);
     372
     373         /* figure out how much of the buffer to copy */
     374         if (eol == NULL) {
     375             /* no newline -> copy all available, if room */
     376             amt_to_copy = (count - line_len);
     377             if (amt_to_copy > condat->rd_buf_len) {
     378                 amt_to_copy = condat->rd_buf_len;
     379             }
     380         } else {
     381             /* newline -> copy line if room */
     382             amt_to_copy = eol - condat->rd_buf + 1;
     383             if (amt_to_copy > (count - line_len)) {
     384                 amt_to_copy = count - line_len;
     385             }
     386         }
     387
     388         /* copy data to string */
     389         memcpy(str + line_len, condat->rd_buf, amt_to_copy);
     390         line_len += amt_to_copy;
     391         str[line_len] = '\0';
     392
     393         /* remove data from input buffer */
     394         memmove(condat->rd_buf,
     395                 condat->rd_buf + amt_to_copy,
     396                 condat->rd_buf_len - amt_to_copy);
     397         condat->rd_buf_len -= amt_to_copy;
     398
     399         /* if we got a newline or our buffer is full, exit */
     400         if ((eol != NULL) || (line_len >= count)) {
     401             return line_len;
     402         }
     403
     404         /* otherwise get more input */
     405         if (sk_fill_rd_buf(condat) == -1) {
     406             return line_len;
     407         }
     408     }
     409
     410 } /* SK_cd_gets() */
     411
     412
     413 /*++++++++++++++++++++++++++++++++++++++
     414   Wrapper around the close(2) system call,
     415
     416   int SK_cd_close         returns the error codes of close(2).
     417
     418   sk_conn_st *condat      Pointer to the connection data structure.
     419
     420     +html+ <PRE>
     421   Author:
     422         marek
     423     +html+ </PRE>
     424   ++++++++++++++++++++++++++++++++++++++*/
     425 int SK_cd_close(sk_conn_st *condat) {
         /* [<][>][^][v][top][bottom][index][help] */
     426   return SK_close(condat->sock);
     427 } /* SK_cd_close() */
     428
     429
     430 /* SK_cd_printf() */
     431 /*++++++++++++++++++++++++++++++++++++++
     432
     433   Printf-like function to print to socket/file specified by connection
     434   data structure. First writes the text to a temporary buffer, then
     435   uses SK_cd_puts to print it. Maintains a 2K static buffer, and allocates
     436   more memory if this is not enough.
     437
     438   int SK_cd_printf       Returns the SK_cd_puts error code/return value.
     439
     440   sk_conn_st *condat     Pointer to the connection data structure.
     441
     442   char *txt              Format text to be written
     443
     444   ...                    more arguments (like printf)
     445
     446
     447     +html+ <PRE>
     448   Author:
     449         marek
     450     +html+ </PRE>
     451   ++++++++++++++++++++++++++++++++++++++*/
     452 int SK_cd_printf(sk_conn_st *condat, char *txt, ...)
         /* [<][>][^][v][top][bottom][index][help] */
     453 {
     454 #define SKBUFLEN 2047
     455   va_list   ap;
     456   char      buffer[SKBUFLEN+1];
     457   unsigned  len;
     458   char      *newbuf = NULL;
     459   char      *finalbuf = buffer; /* points to where the text REALLY is */
     460
     461   /* vsnprintf returns the number of character it WOULD write if it could.
     462      So we assume the buffer to be of adequate size for most cases,
     463      and if it isn't, then we allocate to newbuf and call v*printf again
     464   */
     465   va_start(ap, txt);
     466   len = vsnprintf(buffer, SKBUFLEN, txt, ap);
     467   va_end(ap);
     468
     469   if( len > SKBUFLEN ) {
     470     newbuf = (char *)UT_malloc(len+1);
     471
     472     va_start(ap, txt);
     473     vsnprintf(newbuf, len+1, txt, ap);
     474     va_end(ap);
     475
     476     finalbuf = newbuf;
     477   }
     478   /* terminate */
     479   finalbuf[len] = 0;
     480
     481   /* reuse len */
     482   len = SK_cd_puts(condat, finalbuf);
     483
     484   if(newbuf != NULL) {
     485     UT_free(newbuf);
     486   }
     487
     488   return len;
     489 } /* SK_cd_printf() */
     490

/* [<][>][^][v][top][bottom][index][help] */