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