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