1 // Copyright (C) 2003 Davis E. King (davis@dlib.net), Miguel Grinberg 2 // License: Boost Software License See LICENSE.txt for the full license. 3 #ifndef DLIB_SOCKETS_KERNEL_2_CPp_ 4 #define DLIB_SOCKETS_KERNEL_2_CPp_ 5 6 #include "../platform.h" 7 8 #ifdef DLIB_POSIX 9 10 11 #include "sockets_kernel_2.h" 12 #include <fcntl.h> 13 #include "../set.h" 14 #include <netinet/tcp.h> 15 #include <string.h> 16 17 18 19 namespace dlib 20 { 21 // ---------------------------------------------------------------------------------------- 22 23 #ifdef HPUX 24 typedef int dsocklen_t; 25 #else 26 typedef socklen_t dsocklen_t; 27 #endif 28 29 // ---------------------------------------------------------------------------------------- 30 // stuff to ensure that the signal SIGPIPE is ignored before any connections are made 31 // so that when a connection object is shutdown the program won't end on a broken pipe 32 33 namespace sockets_kernel_2_mutex 34 { 35 mutex startup_lock; 36 } 37 38 sockets_startup()39 void sockets_startup() 40 { 41 // mutex crap to make this function thread safe 42 sockets_kernel_2_mutex::startup_lock.lock(); 43 static bool init = false; 44 if (init == false) 45 { 46 init = true; 47 signal( SIGPIPE, SIG_IGN); 48 } 49 sockets_kernel_2_mutex::startup_lock.unlock(); 50 } 51 52 53 // ---------------------------------------------------------------------------------------- 54 55 // lookup functions 56 57 int get_local_hostname(std::string & hostname)58 get_local_hostname ( 59 std::string& hostname 60 ) 61 { 62 try 63 { 64 char temp[MAXHOSTNAMELEN]; 65 66 if (gethostname(temp,MAXHOSTNAMELEN) == -1) 67 { 68 return OTHER_ERROR; 69 } 70 // ensure that NUL is at the end of the string 71 temp[MAXHOSTNAMELEN-1] = '\0'; 72 73 hostname = temp; 74 } 75 catch (...) 76 { 77 return OTHER_ERROR; 78 } 79 80 return 0; 81 } 82 83 // ----------------- 84 85 // cygwin currently doesn't support the getaddrinfo stuff 86 #ifndef __CYGWIN__ 87 88 int hostname_to_ip(const std::string & hostname,std::string & ip,int n)89 hostname_to_ip ( 90 const std::string& hostname, 91 std::string& ip, 92 int n 93 ) 94 { 95 try 96 { 97 set<std::string>::kernel_1a sos; 98 99 if (hostname.empty()) 100 return OTHER_ERROR; 101 102 addrinfo* result = 0; 103 if (getaddrinfo(hostname.c_str(),0,0,&result)) 104 { 105 return OTHER_ERROR; 106 } 107 addrinfo* result_orig = result; 108 109 // loop over all the addrinfo structures and add them to the set. the reason for doing 110 // this dumb crap is because different platforms return all kinds of weird garbage. many 111 // return the same ip multiple times, etc. 112 while (result != 0) 113 { 114 char temp[16]; 115 inet_ntop ( 116 AF_INET, 117 &((reinterpret_cast<sockaddr_in*>(result->ai_addr))->sin_addr), 118 temp,16 119 ); 120 121 result = result->ai_next; 122 123 ip.assign(temp); 124 if (sos.is_member(ip) == false && ip != "0.0.0.0") 125 sos.add(ip); 126 } 127 128 freeaddrinfo(result_orig); 129 130 // now return the nth unique ip address 131 int i = 0; 132 while (sos.move_next()) 133 { 134 if (i == n) 135 { 136 ip = sos.element(); 137 return 0; 138 } 139 ++i; 140 } 141 142 return OTHER_ERROR; 143 } 144 catch (...) 145 { 146 return OTHER_ERROR; 147 } 148 return 0; 149 } 150 151 152 // ----------------- 153 154 int ip_to_hostname(const std::string & ip,std::string & hostname)155 ip_to_hostname ( 156 const std::string& ip, 157 std::string& hostname 158 ) 159 { 160 161 try 162 { 163 164 if (ip.empty()) 165 return OTHER_ERROR; 166 167 sockaddr_in sa; 168 sa.sin_family = AF_INET; 169 inet_pton(AF_INET,ip.c_str(),&sa.sin_addr); 170 171 char temp[NI_MAXHOST]; 172 if ( getnameinfo ( 173 reinterpret_cast<sockaddr*>(&sa),sizeof(sockaddr_in), 174 temp, 175 NI_MAXHOST, 176 0, 177 0, 178 NI_NAMEREQD 179 ) 180 ) 181 { 182 return OTHER_ERROR; 183 } 184 185 hostname.assign(temp); 186 187 } 188 catch (...) 189 { 190 return OTHER_ERROR; 191 } 192 return 0; 193 } 194 #else 195 int hostname_to_ip(const std::string & hostname,std::string & ip,int n)196 hostname_to_ip ( 197 const std::string& hostname, 198 std::string& ip, 199 int n 200 ) 201 { 202 try 203 { 204 // lock this mutex since gethostbyname isn't really thread safe 205 auto_mutex M(sockets_kernel_2_mutex::startup_lock); 206 207 // if no hostname was given then return error 208 if ( hostname.empty()) 209 return OTHER_ERROR; 210 211 hostent* address; 212 address = gethostbyname(hostname.c_str()); 213 214 if (address == 0) 215 { 216 return OTHER_ERROR; 217 } 218 219 // find the nth address 220 in_addr* addr = reinterpret_cast<in_addr*>(address->h_addr_list[0]); 221 for (int i = 1; i <= n; ++i) 222 { 223 addr = reinterpret_cast<in_addr*>(address->h_addr_list[i]); 224 225 // if there is no nth address then return error 226 if (addr == 0) 227 return OTHER_ERROR; 228 } 229 230 char* resolved_ip = inet_ntoa(*addr); 231 232 // check if inet_ntoa returned an error 233 if (resolved_ip == NULL) 234 { 235 return OTHER_ERROR; 236 } 237 238 ip.assign(resolved_ip); 239 240 } 241 catch(...) 242 { 243 return OTHER_ERROR; 244 } 245 246 return 0; 247 } 248 249 // ----------------- 250 251 int ip_to_hostname(const std::string & ip,std::string & hostname)252 ip_to_hostname ( 253 const std::string& ip, 254 std::string& hostname 255 ) 256 { 257 try 258 { 259 // lock this mutex since gethostbyaddr isn't really thread safe 260 auto_mutex M(sockets_kernel_2_mutex::startup_lock); 261 262 // if no ip was given then return error 263 if (ip.empty()) 264 return OTHER_ERROR; 265 266 hostent* address; 267 unsigned long ipnum = inet_addr(ip.c_str()); 268 269 // if inet_addr couldn't convert ip then return an error 270 if (ipnum == INADDR_NONE) 271 { 272 return OTHER_ERROR; 273 } 274 address = gethostbyaddr(reinterpret_cast<char*>(&ipnum),4,AF_INET); 275 276 // check if gethostbyaddr returned an error 277 if (address == 0) 278 { 279 return OTHER_ERROR; 280 } 281 hostname.assign(address->h_name); 282 283 } 284 catch (...) 285 { 286 return OTHER_ERROR; 287 } 288 return 0; 289 290 } 291 292 #endif // __CYGWIN__ 293 294 // ---------------------------------------------------------------------------------------- 295 296 connection:: connection(int sock,int foreign_port,const std::string & foreign_ip,int local_port,const std::string & local_ip)297 connection( 298 int sock, 299 int foreign_port, 300 const std::string& foreign_ip, 301 int local_port, 302 const std::string& local_ip 303 ) : 304 connection_socket(sock), 305 connection_foreign_port(foreign_port), 306 connection_foreign_ip(foreign_ip), 307 connection_local_port(local_port), 308 connection_local_ip(local_ip), 309 sd(false), 310 sdo(false), 311 sdr(0) 312 {} 313 314 // ---------------------------------------------------------------------------------------- 315 316 int connection:: disable_nagle()317 disable_nagle() 318 { 319 int flag = 1; 320 if(setsockopt( connection_socket, IPPROTO_TCP, TCP_NODELAY, (char *)&flag, sizeof(flag) )) 321 { 322 return OTHER_ERROR; 323 } 324 325 return 0; 326 } 327 328 // ---------------------------------------------------------------------------------------- 329 330 long connection:: write(const char * buf,long num)331 write ( 332 const char* buf, 333 long num 334 ) 335 { 336 const long old_num = num; 337 long status; 338 const long max_send_length = 1024*1024*100; 339 while (num > 0) 340 { 341 // Make sure to cap the max value num can take on so that if it is 342 // really large (it might be big on 64bit platforms) so that the OS 343 // can't possibly get upset about it being large. 344 const long length = std::min(max_send_length, num); 345 if ( (status = ::send(connection_socket,buf,length,0)) <=0) 346 { 347 // if send was interupted by a signal then restart it 348 if (errno == EINTR) 349 { 350 continue; 351 } 352 else 353 { 354 // check if shutdown or shutdown_outgoing have been called 355 if (sdo_called()) 356 return SHUTDOWN; 357 else 358 return OTHER_ERROR; 359 } 360 } 361 num -= status; 362 buf += status; 363 } 364 return old_num; 365 } 366 367 // ---------------------------------------------------------------------------------------- 368 369 long connection:: read(char * buf,long num)370 read ( 371 char* buf, 372 long num 373 ) 374 { 375 long status; 376 const long max_recv_length = 1024*1024*100; 377 while (true) 378 { 379 // Make sure to cap the max value num can take on so that if it is 380 // really large (it might be big on 64bit platforms) so that the OS 381 // can't possibly get upset about it being large. 382 const long length = std::min(max_recv_length, num); 383 status = recv(connection_socket,buf,length,0); 384 if (status == -1) 385 { 386 // if recv was interupted then try again 387 if (errno == EINTR) 388 continue; 389 else 390 { 391 if (sd_called()) 392 return SHUTDOWN; 393 else 394 return OTHER_ERROR; 395 } 396 } 397 else if (status == 0 && sd_called()) 398 { 399 return SHUTDOWN; 400 } 401 402 return status; 403 } // while (true) 404 } 405 // ---------------------------------------------------------------------------------------- 406 407 long connection:: read(char * buf,long num,unsigned long timeout)408 read ( 409 char* buf, 410 long num, 411 unsigned long timeout 412 ) 413 { 414 long status; 415 const long max_recv_length = 1024*1024*100; 416 417 if (readable(timeout) == false) 418 return TIMEOUT; 419 420 // Make sure to cap the max value num can take on so that if it is 421 // really large (it might be big on 64bit platforms) so that the OS 422 // can't possibly get upset about it being large. 423 const long length = std::min(max_recv_length, num); 424 status = recv(connection_socket,buf,length,0); 425 if (status == -1) 426 { 427 // if recv was interupted then call this a timeout 428 if (errno == EINTR) 429 { 430 return TIMEOUT; 431 } 432 else 433 { 434 if (sd_called()) 435 return SHUTDOWN; 436 else 437 return OTHER_ERROR; 438 } 439 } 440 else if (status == 0 && sd_called()) 441 { 442 return SHUTDOWN; 443 } 444 445 return status; 446 } 447 448 // ---------------------------------------------------------------------------------------- 449 450 bool connection:: readable(unsigned long timeout) const451 readable ( 452 unsigned long timeout 453 ) const 454 { 455 fd_set read_set; 456 // initialize read_set 457 FD_ZERO(&read_set); 458 459 // add the listening socket to read_set 460 FD_SET(connection_socket, &read_set); 461 462 // setup a timeval structure 463 timeval time_to_wait; 464 time_to_wait.tv_sec = static_cast<long>(timeout/1000); 465 time_to_wait.tv_usec = static_cast<long>((timeout%1000)*1000); 466 467 // wait on select 468 int status = select(connection_socket+1,&read_set,0,0,&time_to_wait); 469 470 // if select timed out or there was an error 471 if (status <= 0) 472 return false; 473 474 // socket is ready to be read 475 return true; 476 } 477 478 // ---------------------------------------------------------------------------------------- 479 480 connection:: ~connection()481 ~connection ( 482 ) 483 { 484 while (true) 485 { 486 int status = ::close(connection_socket); 487 if (status == -1 && errno == EINTR) 488 continue; 489 break; 490 } 491 } 492 493 494 // ---------------------------------------------------------------------------------------- 495 // ---------------------------------------------------------------------------------------- 496 // listener object 497 // ---------------------------------------------------------------------------------------- 498 // ---------------------------------------------------------------------------------------- 499 500 listener:: listener(int sock,int port,const std::string & ip)501 listener( 502 int sock, 503 int port, 504 const std::string& ip 505 ) : 506 listening_socket(sock), 507 listening_port(port), 508 listening_ip(ip), 509 inaddr_any(listening_ip.empty()) 510 {} 511 512 // ---------------------------------------------------------------------------------------- 513 514 listener:: ~listener()515 ~listener ( 516 ) 517 { 518 while (true) 519 { 520 int status = ::close(listening_socket); 521 if (status == -1 && errno == EINTR) 522 continue; 523 break; 524 } 525 } 526 527 // ---------------------------------------------------------------------------------------- 528 529 int listener:: accept(std::unique_ptr<connection> & new_connection,unsigned long timeout)530 accept ( 531 std::unique_ptr<connection>& new_connection, 532 unsigned long timeout 533 ) 534 { 535 new_connection.reset(0); 536 connection* con; 537 int status = this->accept(con, timeout); 538 539 if (status == 0) 540 new_connection.reset(con); 541 542 return status; 543 } 544 545 // ---------------------------------------------------------------------------------------- 546 547 int listener:: accept(connection * & new_connection,unsigned long timeout)548 accept ( 549 connection*& new_connection, 550 unsigned long timeout 551 ) 552 { 553 int incoming; 554 sockaddr_in incomingAddr; 555 dsocklen_t length = sizeof(sockaddr_in); 556 557 // implement timeout with select if timeout is > 0 558 if (timeout > 0) 559 { 560 561 fd_set read_set; 562 // initialize read_set 563 FD_ZERO(&read_set); 564 565 // add the listening socket to read_set 566 FD_SET(listening_socket, &read_set); 567 568 timeval time_to_wait; 569 570 571 // loop on select so if its interupted then we can start it again 572 while (true) 573 { 574 575 // setup a timeval structure 576 time_to_wait.tv_sec = static_cast<long>(timeout/1000); 577 time_to_wait.tv_usec = static_cast<long>((timeout%1000)*1000); 578 579 // wait on select 580 int status = select(listening_socket+1,&read_set,0,0,&time_to_wait); 581 582 // if select timed out 583 if (status == 0) 584 return TIMEOUT; 585 586 // if select returned an error 587 if (status == -1) 588 { 589 // if select was interupted or the connection was aborted 590 // then go back to select 591 if (errno == EINTR || 592 errno == ECONNABORTED || 593 #ifdef EPROTO 594 errno == EPROTO || 595 #endif 596 errno == ECONNRESET 597 ) 598 { 599 continue; 600 } 601 else 602 { 603 return OTHER_ERROR; 604 } 605 } 606 607 // accept the new connection 608 incoming=::accept ( 609 listening_socket, 610 reinterpret_cast<sockaddr*>(&incomingAddr), 611 &length 612 ); 613 614 // if there was an error return OTHER_ERROR 615 if ( incoming == -1 ) 616 { 617 // if accept was interupted then go back to accept 618 if (errno == EINTR || 619 errno == ECONNABORTED || 620 #ifdef EPROTO 621 errno == EPROTO || 622 #endif 623 errno == ECONNRESET 624 ) 625 { 626 continue; 627 } 628 else 629 { 630 return OTHER_ERROR; 631 } 632 } 633 634 // if there were no errors then quit loop 635 break; 636 637 } 638 639 } 640 // else if there is no time out then just go into accept 641 else 642 { 643 while (true) 644 { 645 // call accept to get a new connection 646 incoming=::accept ( 647 listening_socket, 648 reinterpret_cast<sockaddr*>(&incomingAddr), 649 &length 650 ); 651 652 // if there was an error return OTHER_ERROR 653 if ( incoming == -1 ) 654 { 655 // if accept was interupted then go back to accept 656 if (errno == EINTR || 657 errno == ECONNABORTED || 658 #ifdef EPROTO 659 errno == EPROTO || 660 #endif 661 errno == ECONNRESET 662 ) 663 { 664 continue; 665 } 666 else 667 { 668 return OTHER_ERROR; 669 } 670 } 671 break; 672 } 673 674 } 675 676 677 // get the port of the foreign host into foreign_port 678 int foreign_port = ntohs(incomingAddr.sin_port); 679 680 // get the IP of the foreign host into foreign_ip 681 char foreign_ip[16]; 682 inet_ntop(AF_INET,&incomingAddr.sin_addr,foreign_ip,16); 683 684 685 686 // get the local ip for this connection into local_ip 687 char temp_local_ip[16]; 688 std::string local_ip; 689 if (inaddr_any == true) 690 { 691 sockaddr_in local_info; 692 length = sizeof(sockaddr_in); 693 // get the local sockaddr_in structure associated with this new connection 694 if ( getsockname ( 695 incoming, 696 reinterpret_cast<sockaddr*>(&local_info), 697 &length 698 ) == -1 699 ) 700 { // an error occurred 701 while (true) 702 { 703 int status = ::close(incoming); 704 if (status == -1 && errno == EINTR) 705 continue; 706 break; 707 } 708 return OTHER_ERROR; 709 } 710 local_ip = const_cast<char*> ( 711 inet_ntop(AF_INET,&local_info.sin_addr,temp_local_ip,16) 712 ); 713 } 714 else 715 { 716 local_ip = listening_ip; 717 } 718 719 720 721 // set the SO_OOBINLINE option 722 int flag_value = 1; 723 if (setsockopt(incoming,SOL_SOCKET,SO_OOBINLINE,reinterpret_cast<const void*>(&flag_value),sizeof(int))) 724 { 725 while (true) 726 { 727 int status = ::close(incoming); 728 if (status == -1 && errno == EINTR) 729 continue; 730 break; 731 } 732 return OTHER_ERROR; 733 } 734 735 736 737 // make a new connection object for this new connection 738 try 739 { 740 new_connection = new connection ( 741 incoming, 742 foreign_port, 743 foreign_ip, 744 listening_port, 745 local_ip 746 ); 747 } 748 catch (...) 749 { 750 while (true) 751 { 752 int status = ::close(incoming); 753 if (status == -1 && errno == EINTR) 754 continue; 755 break; 756 } 757 return OTHER_ERROR; 758 } 759 760 return 0; 761 } 762 763 // ---------------------------------------------------------------------------------------- 764 // ---------------------------------------------------------------------------------------- 765 // socket creation functions 766 // ---------------------------------------------------------------------------------------- 767 // ---------------------------------------------------------------------------------------- 768 769 static void close_socket(int sock)770 close_socket ( 771 int sock 772 ) 773 /*! 774 requires 775 - sock == a socket 776 ensures 777 - sock has been closed 778 !*/ 779 { 780 while (true) 781 { 782 int status = ::close(sock); 783 if (status == -1 && errno == EINTR) 784 continue; 785 break; 786 } 787 } 788 789 // ---------------------------------------------------------------------------------------- 790 create_listener(std::unique_ptr<listener> & new_listener,unsigned short port,const std::string & ip)791 int create_listener ( 792 std::unique_ptr<listener>& new_listener, 793 unsigned short port, 794 const std::string& ip 795 ) 796 { 797 new_listener.reset(); 798 listener* temp; 799 int status = create_listener(temp,port,ip); 800 801 if (status == 0) 802 new_listener.reset(temp); 803 804 return status; 805 } 806 create_listener(listener * & new_listener,unsigned short port,const std::string & ip)807 int create_listener ( 808 listener*& new_listener, 809 unsigned short port, 810 const std::string& ip 811 ) 812 { 813 sockets_startup(); 814 815 816 sockaddr_in sa; // local socket structure 817 memset(&sa,'\0',sizeof(sockaddr_in)); // initialize sa 818 819 820 int sock = socket (AF_INET, SOCK_STREAM, 0); // get a new socket 821 822 // if socket() returned an error then return OTHER_ERROR 823 if (sock == -1) 824 { 825 return OTHER_ERROR; 826 } 827 828 // set the local socket structure 829 sa.sin_family = AF_INET; 830 sa.sin_port = htons(port); 831 if (ip.empty()) 832 { 833 // if the listener should listen on any IP 834 sa.sin_addr.s_addr = htons(INADDR_ANY); 835 } 836 else 837 { 838 // if there is a specific ip to listen on 839 sa.sin_addr.s_addr = inet_addr(ip.c_str()); 840 841 // if inet_addr couldn't convert the ip then return an error 842 if ( sa.sin_addr.s_addr == ( in_addr_t)(-1)) 843 { 844 close_socket(sock); 845 return OTHER_ERROR; 846 } 847 } 848 849 // set the SO_REUSEADDR option 850 int flag_value = 1; 851 if (setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,reinterpret_cast<const void*>(&flag_value),sizeof(int))) 852 { 853 close_socket(sock); 854 return OTHER_ERROR; 855 } 856 857 858 // bind the new socket to the requested port and ip 859 if (bind(sock,reinterpret_cast<sockaddr*>(&sa),sizeof(sockaddr_in)) == -1) 860 { // if there was an error 861 close_socket(sock); 862 863 // if the port is already bound then return PORTINUSE 864 if (errno == EADDRINUSE) 865 return PORTINUSE; 866 else 867 return OTHER_ERROR; 868 } 869 870 871 // tell the new socket to listen 872 if ( listen(sock,SOMAXCONN) == -1) 873 { 874 // if there was an error return OTHER_ERROR 875 close_socket(sock); 876 877 // if the port is already bound then return PORTINUSE 878 if (errno == EADDRINUSE) 879 return PORTINUSE; 880 else 881 return OTHER_ERROR; 882 } 883 884 // determine the used local port if necessary 885 if (port == 0) 886 { 887 sockaddr_in local_info; 888 dsocklen_t length = sizeof(sockaddr_in); 889 if ( getsockname( 890 sock, 891 reinterpret_cast<sockaddr*>(&local_info), 892 &length 893 ) == -1) 894 { 895 close_socket(sock); 896 return OTHER_ERROR; 897 } 898 port = ntohs(local_info.sin_port); 899 } 900 901 // initialize a listener object on the heap with the new socket 902 try { new_listener = new listener(sock,port,ip); } 903 catch(...) { close_socket(sock); return OTHER_ERROR; } 904 905 return 0; 906 } 907 908 // ---------------------------------------------------------------------------------------- 909 create_connection(std::unique_ptr<connection> & new_connection,unsigned short foreign_port,const std::string & foreign_ip,unsigned short local_port,const std::string & local_ip)910 int create_connection ( 911 std::unique_ptr<connection>& new_connection, 912 unsigned short foreign_port, 913 const std::string& foreign_ip, 914 unsigned short local_port, 915 const std::string& local_ip 916 ) 917 { 918 new_connection.reset(); 919 connection* temp; 920 int status = create_connection(temp,foreign_port, foreign_ip, local_port, local_ip); 921 922 if (status == 0) 923 new_connection.reset(temp); 924 925 return status; 926 } 927 928 int create_connection(connection * & new_connection,unsigned short foreign_port,const std::string & foreign_ip,unsigned short local_port,const std::string & local_ip)929 create_connection ( 930 connection*& new_connection, 931 unsigned short foreign_port, 932 const std::string& foreign_ip, 933 unsigned short local_port, 934 const std::string& local_ip 935 ) 936 { 937 sockets_startup(); 938 939 sockaddr_in local_sa; // local socket structure 940 sockaddr_in foreign_sa; // foreign socket structure 941 memset(&local_sa,'\0',sizeof(sockaddr_in)); // initialize local_sa 942 memset(&foreign_sa,'\0',sizeof(sockaddr_in)); // initialize foreign_sa 943 944 dsocklen_t length; 945 946 int sock = socket (AF_INET, SOCK_STREAM, 0); // get a new socket 947 948 // if socket() returned an error then return OTHER_ERROR 949 if (sock == -1 ) 950 { 951 return OTHER_ERROR; 952 } 953 954 // set the foreign socket structure 955 foreign_sa.sin_family = AF_INET; 956 foreign_sa.sin_port = htons(foreign_port); 957 foreign_sa.sin_addr.s_addr = inet_addr(foreign_ip.c_str()); 958 959 // if inet_addr couldn't convert the ip then return an error 960 if ( foreign_sa.sin_addr.s_addr == ( in_addr_t)(-1)) 961 { 962 close_socket(sock); 963 return OTHER_ERROR; 964 } 965 966 967 // set up the local socket structure 968 local_sa.sin_family = AF_INET; 969 970 // set the local port 971 local_sa.sin_port = htons(local_port); 972 973 // set the local ip 974 if (local_ip.empty()) 975 { 976 // if the listener should listen on any IP 977 local_sa.sin_addr.s_addr = htons(INADDR_ANY); 978 } 979 else 980 { 981 // if there is a specific ip to listen on 982 local_sa.sin_addr.s_addr = inet_addr(local_ip.c_str()); 983 984 // if inet_addr couldn't convert the ip then return an error 985 if ( local_sa.sin_addr.s_addr == ( in_addr_t)(-1)) 986 { 987 close_socket(sock); 988 return OTHER_ERROR; 989 } 990 } 991 992 993 994 995 996 // bind the new socket to the requested local port and local ip 997 if ( bind(sock,reinterpret_cast<sockaddr*>(&local_sa),sizeof(sockaddr_in)) == -1) 998 { // if there was an error 999 close_socket(sock); 1000 1001 // if the port is already bound then return PORTINUSE 1002 if (errno == EADDRINUSE) 1003 return PORTINUSE; 1004 else 1005 return OTHER_ERROR; 1006 } 1007 1008 // connect the socket 1009 if ( connect ( 1010 sock, 1011 reinterpret_cast<sockaddr*>(&foreign_sa), 1012 sizeof(sockaddr_in) 1013 ) == -1 1014 ) 1015 { 1016 close_socket(sock); 1017 // if the port is already bound then return PORTINUSE 1018 if (errno == EADDRINUSE) 1019 return PORTINUSE; 1020 else 1021 return OTHER_ERROR; 1022 } 1023 1024 1025 // determine the local port and IP and store them in used_local_ip 1026 // and used_local_port 1027 int used_local_port; 1028 char temp_used_local_ip[16]; 1029 std::string used_local_ip; 1030 sockaddr_in local_info; 1031 1032 // determine the port 1033 if (local_port == 0) 1034 { 1035 length = sizeof(sockaddr_in); 1036 if ( getsockname( 1037 sock, 1038 reinterpret_cast<sockaddr*>(&local_info), 1039 &length 1040 ) == -1) 1041 { 1042 close_socket(sock); 1043 return OTHER_ERROR; 1044 } 1045 used_local_port = ntohs(local_info.sin_port); 1046 } 1047 else 1048 { 1049 used_local_port = local_port; 1050 } 1051 1052 // determine the ip 1053 if (local_ip.empty()) 1054 { 1055 // if local_port is not 0 then we must fill the local_info structure 1056 if (local_port != 0) 1057 { 1058 length = sizeof(sockaddr_in); 1059 if ( getsockname ( 1060 sock, 1061 reinterpret_cast<sockaddr*>(&local_info), 1062 &length 1063 ) == -1 1064 ) 1065 { 1066 close_socket(sock); 1067 return OTHER_ERROR; 1068 } 1069 } 1070 used_local_ip = inet_ntop(AF_INET,&local_info.sin_addr,temp_used_local_ip,16); 1071 } 1072 else 1073 { 1074 used_local_ip = local_ip; 1075 } 1076 1077 1078 // set the SO_OOBINLINE option 1079 int flag_value = 1; 1080 if (setsockopt(sock,SOL_SOCKET,SO_OOBINLINE,reinterpret_cast<const void*>(&flag_value),sizeof(int))) 1081 { 1082 close_socket(sock); 1083 return OTHER_ERROR; 1084 } 1085 1086 1087 // initialize a connection object on the heap with the new socket 1088 try 1089 { 1090 new_connection = new connection ( 1091 sock, 1092 foreign_port, 1093 foreign_ip, 1094 used_local_port, 1095 used_local_ip 1096 ); 1097 } 1098 catch(...) {close_socket(sock); return OTHER_ERROR; } 1099 1100 return 0; 1101 } 1102 1103 // ---------------------------------------------------------------------------------------- 1104 1105 } 1106 1107 #endif // DLIB_POSIX 1108 1109 #endif // DLIB_SOCKETS_KERNEL_2_CPp_ 1110 1111