1 | /*************************************** 2 | $Revision: 1.15 $ 3 | 4 | Example code: A socket module. 5 | 6 | Status: NOT REVUED, NOT TESTED 7 | 8 | +html+ <DL COMPACT> 9 | +html+ <DT>Online References: 10 | +html+ <DD><UL> 11 | +html+ <LI>Adapted from <A HREF="http://www.ibrado.com/sock-faq/sfaq.html#faq65">sample source code</A>. 12 | +html+ </UL> 13 | +html+ </DL> 14 | +html+ <PRE> 15 | +html+ </PRE> 16 | 17 | ******************/ /****************** 18 | Modification History: 19 | ottrey (08/03/1999) Created from sockhelp.c. 20 | ottrey (08/03/1998) Heavily butchered. 21 | joao (22/06/1999) Modified socket creation and accepts. 22 | ******************/ /****************** 23 | REMINDER: PUT THE PROPER COPYRIGHT NOTICE HERE 24 | ***************************************/ 25 | #include <arpa/inet.h> 26 | #include "socket.h" 27 | #include "constants.h" 28 | #include "stubs.h" 29 | 30 | #include "iproutines.h" 31 | #include "memwrap.h" 32 | 33 | extern int h_errno; 34 | 35 | 36 | /*+ String sizes +*/ 37 | #define STR_S 63 38 | #define STR_M 255 39 | #define STR_L 1023 40 | #define STR_XL 4095 41 | #define STR_XXL 16383 42 | 43 | /* SK_atoport() */ 44 | /*++++++++++++++++++++++++++++++++++++++ 45 | Take a service name, and a service type, and return a port number. If the 46 | service name is not found, it tries it as a decimal number. The number 47 | returned is byte ordered for the network. 48 | 49 | char *service Service name (or port number). 50 | 51 | char *proto Protocol (eg "tcp"). 52 | 53 | More: 54 | +html+ <PRE> 55 | Authors: 56 | ottrey 57 | 58 | +html+ </PRE><DL COMPACT> 59 | +html+ <DT>Online References: 60 | +html+ <DD><UL> 61 | +html+ </UL></DL> 62 | 63 | ++++++++++++++++++++++++++++++++++++++*/ 64 | int SK_atoport(const char *service, const char *proto) { 65 | int port; 66 | long int lport; 67 | struct servent *serv; 68 | char *errpos; 69 | struct servent result; 70 | char buffer[STR_XXL]; 71 | 72 | /* First try to read it from /etc/services */ 73 | 74 | /* serv = getservbyname(service, proto); */ 75 | serv = getservbyname_r(service, proto, &result, buffer, sizeof(buffer)); 76 | if (serv != NULL) 77 | port = serv->s_port; 78 | else { /* Not in services, maybe a number? */ 79 | lport = strtol(service,&errpos,0); 80 | if ( (errpos[0] != 0) || (lport < 1) || (lport > 65535) ) 81 | return -1; /* Invalid port address */ 82 | port = htons(lport); 83 | } 84 | return port; 85 | } /* SK_atoport() */ 86 | 87 | 88 | /* SK_close_listening_socket() */ 89 | /*++++++++++++++++++++++++++++++++++++++ 90 | XXX Note: Not sure how long this function will last. Shouldn't _really_ need it. 91 | 92 | More: 93 | +html+ <PRE> 94 | Authors: 95 | ottrey 96 | 97 | +html+ </PRE><DL COMPACT> 98 | +html+ <DT>Online References: 99 | +html+ <DD><UL> 100 | +html+ </UL></DL> 101 | 102 | ++++++++++++++++++++++++++++++++++++++*/ 103 | /*void SK_close_listening_socket() { 104 | close(listening_socket); 105 | } */ /* SK_close_listening_socket */ 106 | 107 | static void func_atexit(void) { 108 | ER_dbg_va(FAC_SK, ASP_SK_GEN,"func_atexit() called"); 109 | } 110 | 111 | static void func_sighup(int n) { 112 | ER_dbg_va(FAC_SK, ASP_SK_GEN,"func_sighup(%d) called", n); 113 | } 114 | 115 | static void func_sigint(int n) { 116 | ER_dbg_va(FAC_SK, ASP_SK_GEN,"func_sigint(%d) called", n); 117 | } 118 | 119 | 120 | void SK_close(int socket) { 121 | ER_dbg_va(FAC_SK, ASP_SK_GEN, "Closing socket... %d", socket); 122 | 123 | close(socket); 124 | } 125 | 126 | /* SK_getsock() */ 127 | /*++++++++++++++++++++++++++++++++++++++ 128 | 129 | This function creates a socket and binds to it 130 | 131 | int SK_getsock The new socket 132 | 133 | int socket_type SOCK_STREAM or SOCK_DGRAM (TCP or UDP sockets) 134 | 135 | u_short port The port to listen on. Remember that ports < 1024 are 136 | reserved for the root user. Must be passed in network byte 137 | order (see "man htons"). 138 | 139 | uint32_t bind_address Address to bind to, in network order. 140 | More: 141 | +html+ <PRE> 142 | Authors: 143 | ottrey 144 | joao 145 | 146 | +html+ </PRE><DL COMPACT> 147 | +html+ <DT>Online References: 148 | +html+ <DD><UL> 149 | +html+ </UL></DL> 150 | 151 | ++++++++++++++++++++++++++++++++++++++*/ 152 | int SK_getsock(int socket_type, u_short port, uint32_t bind_address) { 153 | struct sockaddr_in address; 154 | int listening_socket; 155 | int reuse_addr = 1; 156 | 157 | /* Setup internet address information. 158 | This is used with the bind() call */ 159 | memset((char *) &address, 0, sizeof(address)); 160 | address.sin_family = AF_INET; 161 | address.sin_port = port; 162 | address.sin_addr.s_addr = bind_address; 163 | 164 | /* Map all of the signals and exit routine */ 165 | atexit(func_atexit); 166 | /* signal.h has a full list of signal names */ 167 | 168 | listening_socket = socket(AF_INET, socket_type, 0); 169 | if (listening_socket < 0) { 170 | perror("socket"); 171 | exit(EXIT_FAILURE); 172 | } 173 | 174 | setsockopt(listening_socket, SOL_SOCKET, SO_REUSEADDR, (void *)&reuse_addr, sizeof(reuse_addr)); 175 | 176 | if (bind(listening_socket, (struct sockaddr *) &address, sizeof(address)) < 0) { 177 | perror("bind"); 178 | close(listening_socket); 179 | exit(EXIT_FAILURE); 180 | } 181 | 182 | 183 | if (socket_type == SOCK_STREAM) { 184 | listen(listening_socket, 5); /* Queue up to five connections before 185 | having them automatically rejected. */ 186 | } 187 | 188 | return listening_socket; 189 | } /* SK_getsock() */ 190 | 191 | /*++++++++++++++++++++++++++++++++++++++ 192 | 193 | Wait for an incoming connection on the specified socket 194 | 195 | int SK_accept_connection The socket for communicating to the client 196 | 197 | int listening_socket The socket that the server is bound to 198 | 199 | More: 200 | +html+ <PRE> 201 | Authors: 202 | joao 203 | +html+ </PRE> 204 | ++++++++++++++++++++++++++++++++++++++*/ 205 | int SK_accept_connection(int listening_socket) { 206 | int connected_socket = -1; 207 | 208 | while(connected_socket < 0) { 209 | 210 | ER_dbg_va(FAC_SK, ASP_SK_GEN, 211 | "Going to accept connections on socket : %d",listening_socket); 212 | 213 | /* XXX joao - ? - why is this here? 214 | fflush(NULL); 215 | */ 216 | 217 | connected_socket = accept(listening_socket, NULL, NULL); 218 | if (connected_socket < 0) { 219 | /* Either a real error occured, or blocking was interrupted for 220 | some reason. Only abort execution if a real error occured. */ 221 | if (errno != EINTR) { 222 | perror("accept"); 223 | close(listening_socket); 224 | return(-1); 225 | /* no exit, just return with error */ 226 | } else { 227 | continue; /* don't return - do the accept again */ 228 | } 229 | } 230 | } 231 | 232 | ER_dbg_va(FAC_SK, ASP_SK_GEN, "client connected on socket %d", 233 | connected_socket 234 | ); 235 | 236 | return connected_socket; 237 | } 238 | 239 | /* SK_read() */ 240 | /*++++++++++++++++++++++++++++++++++++++ 241 | 242 | This is just like the read() system call, except that it will make 243 | sure that all your data goes through the socket. 244 | 245 | int SK_read The number of bytes read. 246 | 247 | int sockfd The socket file descriptor. 248 | 249 | char *buf The buffer to be read from the socket. 250 | 251 | size_t count The number of bytes in the buffer. 252 | 253 | More: 254 | +html+ <PRE> 255 | Authors: 256 | ottrey 257 | +html+ </PRE> 258 | ++++++++++++++++++++++++++++++++++++++*/ 259 | int SK_read(int sockfd, char *buf, size_t count) { 260 | size_t bytes_read = 0; 261 | int this_read; 262 | 263 | while (bytes_read < count) { 264 | do 265 | this_read = read(sockfd, buf, count - bytes_read); 266 | while ( (this_read < 0) && (errno == EINTR) ); 267 | if (this_read < 0) 268 | return this_read; 269 | else if (this_read == 0) 270 | return bytes_read; 271 | bytes_read += this_read; 272 | buf += this_read; 273 | } 274 | 275 | return count; 276 | 277 | } /* SK_read() */ 278 | 279 | 280 | /* SK_write() */ 281 | /*++++++++++++++++++++++++++++++++++++++ 282 | 283 | This is just like the write() system call, accept that it will 284 | make sure that all data is transmitted. 285 | 286 | int sockfd The socket file descriptor. 287 | 288 | char *buf The buffer to be written to the socket. 289 | 290 | size_t count The number of bytes in the buffer. 291 | 292 | More: 293 | +html+ <PRE> 294 | Authors: 295 | ottrey 296 | 297 | +html+ </PRE><DL COMPACT> 298 | +html+ <DT>Online References: 299 | +html+ <DD><UL> 300 | +html+ </UL></DL> 301 | 302 | ++++++++++++++++++++++++++++++++++++++*/ 303 | int SK_write(int sockfd, const char *buf, size_t count) { 304 | size_t bytes_sent = 0; 305 | int this_write; 306 | 307 | 308 | ER_dbg_va(FAC_SK, ASP_SK_WRIT, 309 | "SK_write = { sockfd=[%d], buf=[%s], count=[%d]", 310 | sockfd, buf, count); 311 | 312 | while (bytes_sent < count) { 313 | do 314 | this_write = write(sockfd, buf, count - bytes_sent); 315 | while ( (this_write < 0) && (errno == EINTR) ); 316 | if (this_write <= 0) 317 | return this_write; 318 | bytes_sent += this_write; 319 | buf += this_write; 320 | } 321 | return count; 322 | } /* SK_write() */ 323 | 324 | 325 | /* SK_gets() */ 326 | /*++++++++++++++++++++++++++++++++++++++ 327 | 328 | This function reads from a socket, until it recieves a linefeed 329 | character. It fills the buffer "str" up to the maximum size "count". 330 | 331 | int SK_gets The total_count of bytes read. 332 | 333 | int sockfd The socket file descriptor. 334 | 335 | char *str The buffer to be written from the socket. 336 | 337 | size_t count The number of bytes in the buffer. 338 | 339 | More: 340 | +html+ <PRE> 341 | Authors: 342 | ottrey 343 | 344 | Side Effects: 345 | This function will return -1 if the socket is closed during the read operation. 346 | 347 | Note that if a single line exceeds the length of count, the extra data 348 | will be read and discarded! You have been warned. 349 | 350 | To Do: 351 | Capture the control-c properly! 352 | 353 | +html+ </PRE> 354 | 355 | ++++++++++++++++++++++++++++++++++++++*/ 356 | int SK_gets(int sockfd, char *str, size_t count) { 357 | int bytes_read; 358 | int total_count = 0; 359 | char *current_position; 360 | char last_read = 0; 361 | 362 | int control_c = 0; 363 | 364 | current_position = str; 365 | while (last_read != 10) { 366 | bytes_read = read(sockfd, &last_read, 1); 367 | if (bytes_read <= 0) { 368 | /* The other side may have closed unexpectedly */ 369 | return SK_DISCONNECT; 370 | /* Is this effective on other platforms than linux? */ 371 | } 372 | if ( (total_count < count) && (last_read != 10) && (last_read !=13) ) { 373 | *current_position = last_read; 374 | current_position++; 375 | total_count++; 376 | } 377 | 378 | if (last_read == -1) { 379 | bytes_read = read(sockfd, &last_read, 1); 380 | if (last_read == -12) { 381 | ER_dbg_va(FAC_SK, ASP_SK_GEN,"Client pressed Control-c"); 382 | control_c = 1; 383 | ER_dbg_va(FAC_SK, ASP_SK_GEN,"returning SK_INTERRUPT"); 384 | return SK_INTERRUPT; 385 | } 386 | } 387 | } 388 | if (count > 0) { 389 | *current_position = 0; 390 | } 391 | 392 | return total_count; 393 | 394 | } /* SK_gets() */ 395 | 396 | 397 | /* SK_puts() */ 398 | /*++++++++++++++++++++++++++++++++++++++ 399 | 400 | This function writes a character string out to a socket. 401 | 402 | int SK_puts The total_count of bytes written, 403 | or errors (represented as negative numbers) 404 | 405 | int sockfd The socket file descriptor. 406 | 407 | char *str The buffer to be written from the socket. 408 | 409 | More: 410 | +html+ <PRE> 411 | Authors: 412 | ottrey 413 | 414 | Side Effects: 415 | This function will return -1 if the socket is closed during the write operation. 416 | 417 | Note that if a single line exceeds the length of count, the extra data 418 | will be read and discarded! You have been warned. 419 | 420 | +html+ </PRE> 421 | 422 | ++++++++++++++++++++++++++++++++++++++*/ 423 | int SK_puts(int sockfd, const char *str) { 424 | 425 | return SK_write(sockfd, str, strlen(str)); 426 | 427 | } /* SK_puts() */ 428 | 429 | /* SK_putc() */ 430 | /*++++++++++++++++++++++++++++++++++++++ 431 | 432 | int SK_putc This function writes a single character out to a socket. 433 | 434 | int sockfd socket 435 | char ch character 436 | 437 | return number of chars written 438 | 439 | ++++++++++++++++++++++++++++++++++++++*/ 440 | int SK_putc(int sockfd, char ch) { 441 | return SK_write(sockfd, &ch, 1); 442 | }/* SK_putc() */ 443 | 444 | /*++++++++++++++++++++++++++++++++++++++ 445 | 446 | This function reads a single character from a socket. 447 | 448 | returns EOF when no character can be read. 449 | 450 | ++++++++++++++++++++++++++++++++++++++*/ 451 | int SK_getc(int sockfd) { 452 | char ch; 453 | 454 | if( read(sockfd, &ch, 1) <= 0 ) { 455 | return EOF; 456 | } 457 | else { 458 | return ch; 459 | } 460 | }/* SK_getc() */ 461 | 462 | /* SK_getpeername() */ 463 | /*++++++++++++++++++++++++++++++++++++++ 464 | 465 | This function will tell you who is at the other end of a connected stream socket. 466 | XXX It's not working. 467 | XXX ? MB it is... 468 | 469 | int sockfd The socket file descriptor. 470 | 471 | More: 472 | +html+ <PRE> 473 | Authors: 474 | ottrey 475 | +html+ </PRE> 476 | 477 | ++++++++++++++++++++++++++++++++++++++*/ 478 | char *SK_getpeername(int sockfd) 479 | { 480 | char *hostaddress=NULL; 481 | struct sockaddr_in addr_in; 482 | int namelen=sizeof(addr_in); 483 | 484 | if (getpeername(sockfd, (struct sockaddr *)&addr_in, &namelen) != -1) { 485 | 486 | dieif( wr_malloc((void **)&hostaddress, 16) != UT_OK); 487 | 488 | strcpy(hostaddress, inet_ntoa(addr_in.sin_addr)); /* XXX MT-UNSAFE */ 489 | } 490 | 491 | return hostaddress; 492 | 493 | } /* SK_getpeername() */ 494 | 495 | /* SK_getpeerip */ 496 | int SK_getpeerip(int sockfd, ip_addr_t *ip) { 497 | struct sockaddr_in addr_in; 498 | int namelen=sizeof(addr_in); 499 | int ret=-1; 500 | 501 | memset(& addr_in, 0, sizeof(struct sockaddr_in)); 502 | 503 | if (getpeername(sockfd, (struct sockaddr *)(& addr_in), &namelen) != -1) { 504 | ret=0; 505 | IP_addr_s2b(ip, &addr_in, namelen); 506 | } 507 | 508 | return ret; 509 | } 510 | 511 | /*------------------------------------------------------------------- 512 | * CD varieties of the functions: broken connections get registered 513 | * in the connection structure within the query environment 514 | * as side effects. 515 | * -----------------------------------------------------------------*/ 516 | 517 | /* SK_cd_puts() */ 518 | /*++++++++++++++++++++++++++++++++++++++ 519 | 520 | This function writes a character string out to a socket. 521 | 522 | int SK_qe_puts The total_count of bytes written, 523 | or errors (represented as negative numbers) 524 | 525 | sk_conn_st *condat connection data 526 | 527 | char *str The buffer to be written from the socket. 528 | 529 | More: 530 | if the connection structure has bad status for this connection 531 | from previous calls, no write will be attempted. 532 | 533 | +html+ <PRE> 534 | Authors: 535 | marek 536 | 537 | Side Effects: 538 | broken connections get registered 539 | in the connection structure within the query environment 540 | 541 | +html+ </PRE> 542 | 543 | ++++++++++++++++++++++++++++++++++++++*/ 544 | int SK_cd_puts(sk_conn_st *condat, const char *str) { 545 | int res=SK_puts(condat->sock, str); 546 | 547 | if( res < 0 ){ 548 | switch( - res ) { 549 | /* dont know what to do and how to log */ 550 | case SK_DISCONNECT: 551 | case SK_INTERRUPT: 552 | /*("Thread received a control-c\n");*/ 553 | case SK_TIMEOUT: 554 | /*("Reading timed out\n");*/ 555 | break; 556 | default: 557 | /* unexpected error code. bail out */ 558 | die; 559 | } 560 | } 561 | } /* SK_cd_puts() */ 562 | 563 | /* SK_cd_gets() */ 564 | /*++++++++++++++++++++++++++++++++++++++ 565 | 566 | Wrapper around SK_gets. 567 | 568 | int SK_qe_gets The total_count of bytes read, 569 | or errors (represented as negative numbers) 570 | 571 | sk_conn_st *condat connection data 572 | 573 | char *str The buffer to be written from the socket. 574 | 575 | More: 576 | if the connection structure has bad status for this connection 577 | from previous calls, no write will be attempted. 578 | 579 | +html+ <PRE> 580 | Authors: 581 | marek 582 | 583 | Side Effects: 584 | broken connections get registered 585 | in the connection structure within the query environment 586 | 587 | +html+ </PRE> 588 | 589 | ++++++++++++++++++++++++++++++++++++++*/ 590 | int SK_cd_gets(sk_conn_st *condat, char *str, size_t count) { 591 | int res=SK_gets(condat->sock, str, count); 592 | 593 | if( res < 0 ){ 594 | switch( res ) { 595 | /* dont know what to do and how to log */ 596 | case SK_DISCONNECT: 597 | case SK_INTERRUPT: 598 | /*("Thread received a control-c\n");*/ 599 | case SK_TIMEOUT: 600 | /*("Reading timed out\n");*/ 601 | break; 602 | default: 603 | /* unexpected error code. bail out */ 604 | die; 605 | } 606 | } 607 | } /* SK_cd_gets() */ 608 | 609 | 610 | int SK_cd_close(sk_conn_st *condat) { 611 | SK_close(condat->sock); 612 | } /* SK_cd_close() */