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