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() */