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_
4 #define DLIB_SOCKETS_KERNEl_2_
5 
6 #ifdef DLIB_ISO_CPP_ONLY
7 #error "DLIB_ISO_CPP_ONLY is defined so you can't use this OS dependent code.  Turn DLIB_ISO_CPP_ONLY off if you want to use it."
8 #endif
9 
10 #include "../platform.h"
11 
12 #include "sockets_kernel_abstract.h"
13 
14 #define _BSD_SOCKLEN_T_
15 
16 #include <ctime>
17 #include <memory>
18 #include <string>
19 
20 #include <sys/types.h>
21 #include <sys/socket.h>
22 #include <errno.h>
23 
24 #ifndef HPUX
25 #include <sys/select.h>
26 #endif
27 #include <arpa/inet.h>
28 #include <signal.h>
29 #include <inttypes.h>
30 #include <netdb.h>
31 #include <unistd.h>
32 #include <sys/param.h>
33 
34 #include <netinet/in.h>
35 
36 #include "../threads.h"
37 #include "../algs.h"
38 
39 
40 
41 
42 namespace dlib
43 {
44 
45 // ----------------------------------------------------------------------------------------
46 
47     // forward declarations
48     class socket_factory;
49     class listener;
50 
51 // ----------------------------------------------------------------------------------------
52 
53     // lookup functions
54 
55     int
56     get_local_hostname (
57         std::string& hostname
58     );
59 
60 // -----------------
61 
62     int
63     hostname_to_ip (
64         const std::string& hostname,
65         std::string& ip,
66         int n = 0
67     );
68 
69 // -----------------
70 
71     int
72     ip_to_hostname (
73         const std::string& ip,
74         std::string& hostname
75     );
76 
77 // ----------------------------------------------------------------------------------------
78 // ----------------------------------------------------------------------------------------
79     // connection object
80 // ----------------------------------------------------------------------------------------
81 // ----------------------------------------------------------------------------------------
82 
83     class connection
84     {
85         /*!
86             INITIAL_VALUE
87                 sd                      == false
88                 sdo                     == false
89                 sdr                     == 0
90 
91 
92             CONVENTION
93                 connection_socket       == the socket handle for this connection.
94                 connection_foreign_port == the port that foreign host is using for
95                                            this connection
96                 connection_foreign_ip   == a string containing the IP address of the
97                                            foreign host
98                 connection_local_port   == the port that the local host is using for
99                                            this connection
100                 connection_local_ip     == a string containing the IP address of the
101                                            local interface being used by this connection
102 
103                 sd                      == if shutdown() has been called then true
104                                            else false
105                 sdo                     == if shutdown_outgoing() has been called then true
106                                            else false
107                 sdr                     == the return value of shutdown() if it has been
108                                            called.  if it hasn't been called then 0
109 
110 
111         !*/
112 
113         friend class listener;                // make listener a friend of connection
114         // make create_connection a friend of connection
115         friend int create_connection (
116             connection*& new_connection,
117             unsigned short foreign_port,
118             const std::string& foreign_ip,
119             unsigned short local_port,
120             const std::string& local_ip
121         );
122 
123     public:
124 
125         ~connection();
126 
127         void* user_data;
128 
129         long write (
130             const char* buf,
131             long num
132         );
133 
134         long read (
135             char* buf,
136             long num
137         );
138 
139         long read (
140             char* buf,
141             long num,
142             unsigned long timeout
143         );
144 
get_local_port()145         int get_local_port (
146         ) const { return connection_local_port; }
147 
get_foreign_port()148         int get_foreign_port (
149         ) const { return connection_foreign_port; }
150 
get_local_ip()151         const std::string& get_local_ip (
152         ) const { return connection_local_ip; }
153 
get_foreign_ip()154         const std::string& get_foreign_ip (
155         ) const { return connection_foreign_ip; }
156 
shutdown_outgoing()157         int shutdown_outgoing (
158         )
159         {
160             sd_mutex.lock();
161             if (sdo || sd)
162             {
163                 sd_mutex.unlock();
164                 return sdr;
165             }
166             sdo = true;
167             sdr = ::shutdown(connection_socket,SHUT_WR);
168             int temp = sdr;
169             sd_mutex.unlock();
170             return temp;
171         }
172 
shutdown()173         int shutdown (
174         )
175         {
176             sd_mutex.lock();
177             if (sd)
178             {
179                 sd_mutex.unlock();
180                 return sdr;
181             }
182             sd = true;
183             sdr = ::shutdown(connection_socket,SHUT_RDWR);
184             int temp = sdr;
185             sd_mutex.unlock();
186             return temp;
187         }
188 
189         int disable_nagle(
190         );
191 
192         typedef int socket_descriptor_type;
193 
get_socket_descriptor()194         socket_descriptor_type get_socket_descriptor (
195         ) const { return connection_socket; }
196 
197     private:
198 
199         bool readable (
200             unsigned long timeout
201         ) const;
202         /*!
203             requires
204                 - timeout < 2000000
205             ensures
206                 - returns true if a read call on this connection will not block.
207                 - returns false if a read call on this connection will block or if
208                   there was an error.
209         !*/
210 
sd_called()211         bool sd_called (
212         )const
213         /*!
214             ensures
215                 - returns true if shutdown() has been called else
216                 - returns false
217         !*/
218         {
219             sd_mutex.lock();
220             bool temp = sd;
221             sd_mutex.unlock();
222             return temp;
223         }
224 
sdo_called()225         bool sdo_called (
226         )const
227         /*!
228             ensures
229                 - returns true if shutdown_outgoing() or shutdown() has been called
230                   else returns false
231         !*/
232         {
233             sd_mutex.lock();
234             bool temp = false;
235             if (sdo || sd)
236                 temp = true;
237             sd_mutex.unlock();
238             return temp;
239         }
240 
241 
242         // data members
243         int connection_socket;
244         const int connection_foreign_port;
245         const std::string connection_foreign_ip;
246         const int connection_local_port;
247         const std::string connection_local_ip;
248 
249         bool sd;  // called shutdown
250         bool sdo; // called shutdown_outgoing
251         int sdr; // return value for shutdown
252         mutex sd_mutex; // a lock for the three above vars
253 
254         connection(
255             int sock,
256             int foreign_port,
257             const std::string& foreign_ip,
258             int local_port,
259             const std::string& local_ip
260         );
261         /*!
262             requires
263                 - sock is a socket handle
264                 - sock is the handle for the connection between foreign_ip:foreign_port
265                   and local_ip:local_port
266             ensures
267                 - *this is initialized correctly with the above parameters
268         !*/
269 
270 
271         // restricted functions
272         connection();
273         connection(connection&);        // copy constructor
274         connection& operator=(connection&);    // assignement opertor
275     };
276 
277 // ----------------------------------------------------------------------------------------
278 // ----------------------------------------------------------------------------------------
279     // listener object
280 // ----------------------------------------------------------------------------------------
281 // ----------------------------------------------------------------------------------------
282 
283     class listener
284     {
285         /*!
286             CONVENTION
287                 if (inaddr_any == false)
288                 {
289                     listening_ip == a string containing the address the listener is
290                                     listening on
291                 }
292                 else
293                 {
294                     the listener is listening on all interfaces
295                 }
296 
297                 listening_port == the port the listener is listening on
298                 listening_socket == the listening socket handle for this object
299         !*/
300 
301         // make the create_listener a friend of listener
302         friend int create_listener (
303             listener*& new_listener,
304             unsigned short port,
305             const std::string& ip
306         );
307 
308     public:
309 
310         ~listener();
311 
312         int accept (
313             connection*& new_connection,
314             unsigned long timeout = 0
315         );
316 
317         int accept (
318             std::unique_ptr<connection>& new_connection,
319             unsigned long timeout = 0
320         );
321 
get_listening_port()322         int get_listening_port (
323         ) const { return listening_port; }
324 
get_listening_ip()325         const std::string& get_listening_ip (
326         ) const { return listening_ip; }
327 
328     private:
329 
330         // data members
331         int listening_socket;
332         const int listening_port;
333         const std::string listening_ip;
334         const bool inaddr_any;
335 
336         listener(
337             int sock,
338             int port,
339             const std::string& ip
340         );
341         /*!
342             requires
343                 - sock is a socket handle
344                 - sock is listening on the port and ip(may be "") indicated in the above
345                   parameters
346             ensures
347                 - *this is initialized correctly with the above parameters
348         !*/
349 
350 
351         // restricted functions
352         listener();
353         listener(listener&);        // copy constructor
354         listener& operator=(listener&);    // assignement opertor
355     };
356 
357 // ----------------------------------------------------------------------------------------
358 
359     int create_listener (
360         listener*& new_listener,
361         unsigned short port,
362         const std::string& ip = ""
363     );
364 
365     int create_connection (
366         connection*& new_connection,
367         unsigned short foreign_port,
368         const std::string& foreign_ip,
369         unsigned short local_port = 0,
370         const std::string& local_ip = ""
371     );
372 
373     int create_listener (
374         std::unique_ptr<listener>& new_listener,
375         unsigned short port,
376         const std::string& ip = ""
377     );
378 
379     int create_connection (
380         std::unique_ptr<connection>& new_connection,
381         unsigned short foreign_port,
382         const std::string& foreign_ip,
383         unsigned short local_port = 0,
384         const std::string& local_ip = ""
385     );
386 
387 // ----------------------------------------------------------------------------------------
388 
389 }
390 
391 #ifdef NO_MAKEFILE
392 #include "sockets_kernel_2.cpp"
393 #endif
394 
395 #endif // DLIB_SOCKETS_KERNEl_2_
396 
397