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