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