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