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