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