1 | /*************************************** 2 | $Revision: 1.10 $ 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 | static void log_print(const char *arg) { 44 | FILE *logf; 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 reuse_addr = 1; 170 | 171 | /* Setup internet address information. 172 | This is used with the bind() call */ 173 | memset((char *) &address, 0, sizeof(address)); 174 | address.sin_family = AF_INET; 175 | address.sin_port = port; 176 | address.sin_addr.s_addr = bind_address; 177 | 178 | /* Map all of the signals and exit routine */ 179 | atexit(func_atexit); 180 | /* signal.h has a full list of signal names */ 181 | //signal(SIGHUP, func_sighup); This should be handled in a different way (thread) 182 | //signal(SIGINT, func_sigint); 183 | 184 | listening_socket = socket(AF_INET, socket_type, 0); 185 | if (listening_socket < 0) { 186 | perror("socket"); 187 | exit(EXIT_FAILURE); 188 | } 189 | 190 | setsockopt(listening_socket, SOL_SOCKET, SO_REUSEADDR, (void *)&reuse_addr, sizeof(reuse_addr)); 191 | 192 | if (bind(listening_socket, (struct sockaddr *) &address, sizeof(address)) < 0) { 193 | perror("bind"); 194 | close(listening_socket); 195 | exit(EXIT_FAILURE); 196 | } 197 | 198 | 199 | if (socket_type == SOCK_STREAM) { 200 | listen(listening_socket, 5); /* Queue up to five connections before 201 | having them automatically rejected. */ 202 | } 203 | 204 | return listening_socket; 205 | } /* SK_getsock() */ 206 | 207 | /*++++++++++++++++++++++++++++++++++++++ 208 | 209 | Wait for an incoming connection on the specified socket 210 | 211 | int SK_accept_connection The socket for communicating to the client 212 | 213 | int listening_socket The socket that the server is bound to 214 | 215 | More: 216 | +html+ <PRE> 217 | Authors: 218 | joao 219 | +html+ </PRE> 220 | ++++++++++++++++++++++++++++++++++++++*/ 221 | int SK_accept_connection(int listening_socket) { 222 | int connected_socket = -1; 223 | char print_buf[STR_L]; 224 | 225 | while(connected_socket < 0) { 226 | sprintf(print_buf, "Going to accept connections on socket : %d\n",listening_socket); log_print(print_buf); strcpy(print_buf, ""); 227 | /* XXX joao - ? - why is this here? 228 | fflush(NULL); 229 | */ 230 | 231 | connected_socket = accept(listening_socket, NULL, NULL); 232 | if (connected_socket < 0) { 233 | /* Either a real error occured, or blocking was interrupted for 234 | some reason. Only abort execution if a real error occured. */ 235 | if (errno != EINTR) { 236 | perror("accept"); 237 | close(listening_socket); 238 | exit(EXIT_FAILURE); 239 | } else { 240 | continue; /* don't return - do the accept again */ 241 | } 242 | } 243 | } 244 | sprintf(print_buf, "client connected.\n"); log_print(print_buf); strcpy(print_buf, ""); 245 | 246 | return connected_socket; 247 | } 248 | 249 | /* sock_read() */ 250 | /*++++++++++++++++++++++++++++++++++++++ 251 | 252 | This is just like the read() system call, except that it will make 253 | sure that all your data goes through the socket. 254 | 255 | int sock_read The number of bytes read. 256 | 257 | int sockfd The socket file descriptor. 258 | 259 | char *buf The buffer to be read from the socket. 260 | 261 | size_t count The number of bytes in the buffer. 262 | 263 | More: 264 | +html+ <PRE> 265 | Authors: 266 | ottrey 267 | +html+ </PRE> 268 | ++++++++++++++++++++++++++++++++++++++*/ 269 | static int sock_read(int sockfd, char *buf, size_t count, unsigned timeout) { 270 | size_t bytes_read = 0; 271 | int this_read; 272 | 273 | while (bytes_read < count) { 274 | do 275 | this_read = read(sockfd, buf, count - bytes_read); 276 | while ( (this_read < 0) && (errno == EINTR) ); 277 | if (this_read < 0) 278 | return this_read; 279 | else if (this_read == 0) 280 | return bytes_read; 281 | bytes_read += this_read; 282 | buf += this_read; 283 | } 284 | 285 | return count; 286 | 287 | } /* sock_read() */ 288 | 289 | 290 | /* sock_write() */ 291 | /*++++++++++++++++++++++++++++++++++++++ 292 | 293 | This is just like the write() system call, accept that it will 294 | make sure that all data is transmitted. 295 | 296 | int sockfd The socket file descriptor. 297 | 298 | char *buf The buffer to be written to the socket. 299 | 300 | size_t count The number of bytes in the buffer. 301 | 302 | More: 303 | +html+ <PRE> 304 | Authors: 305 | ottrey 306 | 307 | +html+ </PRE><DL COMPACT> 308 | +html+ <DT>Online References: 309 | +html+ <DD><UL> 310 | +html+ </UL></DL> 311 | 312 | ++++++++++++++++++++++++++++++++++++++*/ 313 | static int sock_write(int sockfd, const char *buf, size_t count, unsigned timeout) { 314 | size_t bytes_sent = 0; 315 | int this_write; 316 | 317 | /* 318 | printf("sock_write = { sockfd=[%d], buf=[%s], count=[%d]\n", sockfd, buf, count); 319 | */ 320 | while (bytes_sent < count) { 321 | do 322 | this_write = write(sockfd, buf, count - bytes_sent); 323 | while ( (this_write < 0) && (errno == EINTR) ); 324 | if (this_write <= 0) 325 | return this_write; 326 | bytes_sent += this_write; 327 | buf += this_write; 328 | } 329 | return count; 330 | } /* sock_write() */ 331 | 332 | 333 | /* SK_gets() */ 334 | /*++++++++++++++++++++++++++++++++++++++ 335 | 336 | This function reads from a socket, until it recieves a linefeed 337 | character. It fills the buffer "str" up to the maximum size "count". 338 | 339 | int SK_gets The total_count of bytes read. 340 | 341 | int sockfd The socket file descriptor. 342 | 343 | char *str The buffer to be written from the socket. 344 | 345 | size_t count The number of bytes in the buffer. 346 | 347 | More: 348 | +html+ <PRE> 349 | Authors: 350 | ottrey 351 | 352 | Side Effects: 353 | This function will return -1 if the socket is closed during the read operation. 354 | 355 | Note that if a single line exceeds the length of count, the extra data 356 | will be read and discarded! You have been warned. 357 | 358 | To Do: 359 | Capture the control-c properly! 360 | 361 | +html+ </PRE> 362 | 363 | ++++++++++++++++++++++++++++++++++++++*/ 364 | int SK_gets(int sockfd, char *str, size_t count, unsigned timeout) { 365 | int bytes_read; 366 | int total_count = 0; 367 | char *current_position; 368 | char last_read = 0; 369 | 370 | int control_c = 0; 371 | 372 | current_position = str; 373 | while (last_read != 10) { 374 | bytes_read = read(sockfd, &last_read, 1); 375 | if (bytes_read <= 0) { 376 | /* The other side may have closed unexpectedly */ 377 | return SK_DISCONNECT; 378 | /* Is this effective on other platforms than linux? */ 379 | } 380 | if ( (total_count < count) && (last_read != 10) && (last_read !=13) ) { 381 | *current_position = last_read; 382 | current_position++; 383 | total_count++; 384 | } 385 | 386 | if (last_read == -1) { 387 | bytes_read = read(sockfd, &last_read, 1); 388 | if (last_read == -12) { 389 | printf("Client pressed Control-c.\n"); 390 | control_c = 1; 391 | printf("returning SK_INTERRUPT\n"); 392 | return SK_INTERRUPT; 393 | } 394 | } 395 | } 396 | if (count > 0) { 397 | *current_position = 0; 398 | } 399 | 400 | return total_count; 401 | 402 | } /* SK_gets() */ 403 | 404 | 405 | /* SK_puts() */ 406 | /*++++++++++++++++++++++++++++++++++++++ 407 | 408 | This function writes a character string out to a socket. 409 | 410 | int SK_puts The total_count of bytes written, 411 | or errors (represented as negative numbers) 412 | 413 | int sockfd The socket file descriptor. 414 | 415 | char *str The buffer to be written from the socket. 416 | 417 | unsigned timeout timeout in seconds 418 | 419 | More: 420 | +html+ <PRE> 421 | Authors: 422 | ottrey 423 | 424 | Side Effects: 425 | This function will return -1 if the socket is closed during the write operation. 426 | 427 | Note that if a single line exceeds the length of count, the extra data 428 | will be read and discarded! You have been warned. 429 | 430 | +html+ </PRE> 431 | 432 | ++++++++++++++++++++++++++++++++++++++*/ 433 | int SK_puts(int sockfd, const char *str, unsigned timeout) { 434 | 435 | return sock_write(sockfd, str, strlen(str), timeout); 436 | 437 | } /* SK_puts() */ 438 | 439 | /* SK_putc() */ 440 | /*++++++++++++++++++++++++++++++++++++++ 441 | 442 | int SK_putc This function writes a single character out to a socket. 443 | 444 | int sockfd socket 445 | char ch character 446 | unsigned timeout timeout in seconds 447 | 448 | return number of chars written 449 | 450 | ++++++++++++++++++++++++++++++++++++++*/ 451 | int SK_putc(int sockfd, char ch, unsigned timeout) { 452 | return sock_write(sockfd, &ch, 1, timeout); 453 | }/* SK_putc() */ 454 | 455 | /*++++++++++++++++++++++++++++++++++++++ 456 | 457 | This function reads a single character from a socket. 458 | 459 | returns EOF when no character can be read. 460 | 461 | ++++++++++++++++++++++++++++++++++++++*/ 462 | int SK_getc(int sockfd, unsigned timeout) { 463 | char ch; 464 | 465 | if( read(sockfd, &ch, 1) <= 0 ) { 466 | return EOF; 467 | } 468 | else { 469 | return ch; 470 | } 471 | }/* SK_getc() */ 472 | 473 | /* SK_getpeername() */ 474 | /*++++++++++++++++++++++++++++++++++++++ 475 | 476 | This function will tell you who is at the other end of a connected stream socket. 477 | XXX It's not working. 478 | XXX ? MB it is... 479 | 480 | int sockfd The socket file descriptor. 481 | 482 | More: 483 | +html+ <PRE> 484 | Authors: 485 | ottrey 486 | +html+ </PRE> 487 | 488 | ++++++++++++++++++++++++++++++++++++++*/ 489 | char *SK_getpeername(int sockfd) 490 | { 491 | char *hostaddress=NULL; 492 | struct sockaddr_in addr_in; 493 | int namelen=sizeof(addr_in); 494 | 495 | if (getpeername(sockfd, (struct sockaddr *)&addr_in, &namelen) != -1) { 496 | //hostaddress = (char *)malloc(16); /* max length of a valid IPv4 + \0 */ 497 | dieif( wr_malloc((void **)&hostaddress, 16) != UT_OK); 498 | 499 | strcpy(hostaddress, inet_ntoa(addr_in.sin_addr)); /* XXX MT-UNSAFE */ 500 | } 501 | 502 | return hostaddress; 503 | 504 | } /* SK_getpeername() */ 505 | 506 | /* SK_getpeerip */ 507 | int SK_getpeerip(int sockfd, ip_addr_t *ip) { 508 | struct sockaddr_in addr_in; 509 | int namelen=sizeof(addr_in); 510 | int ret=-1; 511 | 512 | memset(& addr_in, 0, sizeof(struct sockaddr_in)); 513 | 514 | if (getpeername(sockfd, (struct sockaddr *)(& addr_in), &namelen) != -1) { 515 | ret=0; 516 | IP_addr_s2b(ip, &addr_in, namelen); 517 | } 518 | 519 | return ret; 520 | } 521 | 522 | /*------------------------------------------------------------------- 523 | * CD varieties of the functions: broken connections get registered 524 | * in the connection structure within the query environment 525 | * as side effects. 526 | * -----------------------------------------------------------------*/ 527 | 528 | /* SK_cd_puts() */ 529 | /*++++++++++++++++++++++++++++++++++++++ 530 | 531 | This function writes a character string out to a socket. 532 | 533 | int SK_qe_puts The total_count of bytes written, 534 | or errors (represented as negative numbers) 535 | 536 | sk_conn_st *condat connection data 537 | 538 | char *str The buffer to be written from the socket. 539 | 540 | unsigned timeout timeout in seconds 541 | 542 | More: 543 | if the connection structure has bad status for this connection 544 | from previous calls, no write will be attempted. 545 | 546 | +html+ <PRE> 547 | Authors: 548 | marek 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 | int res=SK_puts(condat->sock, str, condat->wr_timeout ); 559 | 560 | if( res < 0 ){ 561 | switch( - res ) { 562 | /* dont know what to do and how to log */ 563 | case SK_DISCONNECT: 564 | case SK_INTERRUPT: 565 | /*("Thread received a control-c\n");*/ 566 | case SK_TIMEOUT: 567 | /*("Reading timed out\n");*/ 568 | break; 569 | default: 570 | /* unexpected error code. bail out */ 571 | die; 572 | } 573 | } 574 | } /* SK_cd_puts() */ 575 | 576 | /* SK_cd_gets() */ 577 | /*++++++++++++++++++++++++++++++++++++++ 578 | 579 | Wrapper around SK_gets. 580 | 581 | int SK_qe_gets The total_count of bytes read, 582 | or errors (represented as negative numbers) 583 | 584 | sk_conn_st *condat connection data 585 | 586 | char *str The buffer to be written from the socket. 587 | 588 | More: 589 | if the connection structure has bad status for this connection 590 | from previous calls, no write will be attempted. 591 | 592 | +html+ <PRE> 593 | Authors: 594 | marek 595 | 596 | Side Effects: 597 | broken connections get registered 598 | in the connection structure within the query environment 599 | 600 | +html+ </PRE> 601 | 602 | ++++++++++++++++++++++++++++++++++++++*/ 603 | int SK_cd_gets(sk_conn_st *condat, char *str, size_t count) { 604 | int res=SK_gets(condat->sock, str, count, condat->wr_timeout); 605 | 606 | if( res < 0 ){ 607 | switch( res ) { 608 | /* dont know what to do and how to log */ 609 | case SK_DISCONNECT: 610 | case SK_INTERRUPT: 611 | /*("Thread received a control-c\n");*/ 612 | case SK_TIMEOUT: 613 | /*("Reading timed out\n");*/ 614 | break; 615 | default: 616 | /* unexpected error code. bail out */ 617 | die; 618 | } 619 | } 620 | } /* SK_cd_gets() */ 621 | 622 | 623 | int SK_cd_close(sk_conn_st *condat) { 624 | SK_close(condat->sock); 625 | } /* SK_cd_close() */