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