1    | /***************************************
2    |   $Revision: 1.1 $
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  |   FD_ZERO( &rset );
188  |   FD_SET( condat->sock, &rset );
189  | 
190  |   if( ptm->tv_sec == 0 && ptm->tv_usec == 0) { /* if timeout undefined, 
191  | 						  do blocking I/O */
192  |     ptm = NULL;
193  |   }
194  | 
195  |   do {
196  |     char buf[2];
197  |     int sel = select( (condat->sock)+1, &rset, NULL, NULL, ptm);
198  |     int ern = errno;
199  | 
200  |     dieif(sel < 0); /* we don't expect problems */
201  |       
202  |     if( sel == 0 ) {      
203  |       condat->rtc |= SK_TIMEOUT;
204  |       break;
205  |     }
206  | 
207  |     else { 
208  |       if(read( condat->sock, buf, 1) == 0 ) {
209  | 	condat->rtc |= SK_DISCONNECT;
210  | 	break;
211  |       }
212  |       str[readcount] = buf[0];
213  |       readcount++;
214  |       if( buf[0] == '\n' ) {
215  | 	break;
216  |       }
217  |     } 
218  |   } while( readcount < count );
219  | 	 
220  |   return readcount;
221  | 
222  | } /* SK_cd_gets() */
223  | 
224  | 
225  | /*++++++++++++++++++++++++++++++++++++++
226  |   Wrapper around the close(2) system call, 
227  | 
228  |   int SK_cd_close         returns the error codes of close(2).
229  | 
230  |   sk_conn_st *condat      Pointer to the connection data structure.
231  | 
232  |     +html+ <PRE>
233  |   Author:
234  |         marek
235  |     +html+ </PRE>
236  |   ++++++++++++++++++++++++++++++++++++++*/
237  | int SK_cd_close(sk_conn_st *condat) {
238  |   return SK_close(condat->sock);
239  | } /* SK_cd_close() */
240  | 
241  | 
242  | /* SK_cd_printf() */
243  | /*++++++++++++++++++++++++++++++++++++++
244  | 
245  |   Printf-like function to print to socket/file specified by connection
246  |   data structure. First writes the text to a temporary buffer, then
247  |   uses SK_cd_puts to print it. Maintains a 2K static buffer, and allocates
248  |   more memory if this is not enough.
249  | 
250  |   int SK_cd_printf       Returns the SK_cd_puts error code/return value.
251  | 
252  |   sk_conn_st *condat     Pointer to the connection data structure.
253  | 
254  |   char *txt              Format text to be written
255  | 
256  |   ...                    more arguments (like printf)
257  | 
258  |   
259  |     +html+ <PRE>
260  |   Author:
261  |         marek
262  |     +html+ </PRE>
263  |   ++++++++++++++++++++++++++++++++++++++*/
264  | int SK_cd_printf(sk_conn_st *condat, char *txt, ...)
265  | {
266  | #define SKBUFLEN 2047
267  |   va_list   ap;
268  |   char      buffer[SKBUFLEN+1];
269  |   unsigned  len;
270  |   char      *newbuf = NULL;
271  |   char      *finalbuf = buffer; /* points to where the text REALLY is */
272  |  
273  |   /* vsnprintf returns the number of character it WOULD write if it could.
274  |      So we assume the buffer to be of adequate size for most cases,
275  |      and if it isn't, then we allocate to newbuf and call v*printf again 
276  |   */
277  |   va_start(ap, txt);
278  |   len = vsnprintf(buffer, SKBUFLEN, txt, ap);
279  |   va_end(ap);
280  |   
281  |   if( len > SKBUFLEN ) {
282  |     dieif(!NOERR(wr_malloc( (void **)& newbuf, len+1)));
283  |     
284  |     va_start(ap, txt);
285  |     vsnprintf(newbuf, len, txt, ap);
286  |     va_end(ap);   
287  |     
288  |     finalbuf = newbuf;
289  |   }  
290  |   /* terminate */
291  |   finalbuf[len] = 0;
292  | 
293  |   /* reuse len */
294  |   len = SK_cd_puts(condat, finalbuf);
295  | 
296  |   if(newbuf != NULL) {
297  |     wr_free(newbuf);
298  |   }
299  | 
300  |   return len;
301  | } /* SK_cd_printf() */