1717#include <stdlib.h>
1818#include <string.h>
1919#include <ctype.h>
20+ #include <sys/time.h>
21+ #include <sys/types.h>
22+ #include <unistd.h>
2023
2124#include <fcntl.h>
2225#include <unistd.h>
@@ -31,15 +34,66 @@ struct tcp_sock_t *tcp_open(uint16_t port)
3134{
3235 struct tcp_sock_t * this = calloc (1 , sizeof * this );
3336 if (this == NULL ) {
34- ERR ("callocing this failed" );
37+ ERR ("IPv4: callocing this failed" );
38+ goto error ;
39+ }
40+
41+ // Open [S]ocket [D]escriptor
42+ this -> sd = -1 ;
43+ this -> sd = socket (AF_INET , SOCK_STREAM , 0 );
44+ if (this -> sd < 0 ) {
45+ ERR ("IPv4 socket open failed" );
46+ goto error ;
47+ }
48+
49+ // Configure socket params
50+ struct sockaddr_in addr ;
51+ memset (& addr , 0 , sizeof addr );
52+ addr .sin_family = AF_INET ;
53+ addr .sin_port = htons (port );
54+ addr .sin_addr .s_addr = htonl (0x7F000001 );
55+
56+ // Bind to localhost
57+ if (bind (this -> sd ,
58+ (struct sockaddr * )& addr ,
59+ sizeof addr ) < 0 ) {
60+ if (g_options .only_desired_port == 1 )
61+ ERR ("IPv4 bind on port failed. "
62+ "Requested port may be taken or require root permissions." );
63+ goto error ;
64+ }
65+
66+ // Let kernel over-accept max number of connections
67+ if (listen (this -> sd , HTTP_MAX_PENDING_CONNS ) < 0 ) {
68+ ERR ("IPv4 listen failed on socket" );
69+ goto error ;
70+ }
71+
72+ return this ;
73+
74+ error :
75+ if (this != NULL ) {
76+ if (this -> sd != -1 ) {
77+ close (this -> sd );
78+ }
79+ free (this );
80+ }
81+ return NULL ;
82+ }
83+
84+ struct tcp_sock_t * tcp6_open (uint16_t port )
85+ {
86+ struct tcp_sock_t * this = calloc (1 , sizeof * this );
87+ if (this == NULL ) {
88+ ERR ("IPv6: callocing this failed" );
3589 goto error ;
3690 }
3791
3892 // Open [S]ocket [D]escriptor
3993 this -> sd = -1 ;
4094 this -> sd = socket (AF_INET6 , SOCK_STREAM , 0 );
4195 if (this -> sd < 0 ) {
42- ERR ("sockect open failed" );
96+ ERR ("Ipv6 socket open failed" );
4397 goto error ;
4498 }
4599
@@ -48,21 +102,21 @@ struct tcp_sock_t *tcp_open(uint16_t port)
48102 memset (& addr , 0 , sizeof addr );
49103 addr .sin6_family = AF_INET6 ;
50104 addr .sin6_port = htons (port );
51- addr .sin6_addr = in6addr_any ;
105+ addr .sin6_addr = in6addr_loopback ;
52106
53107 // Bind to localhost
54108 if (bind (this -> sd ,
55109 (struct sockaddr * )& addr ,
56110 sizeof addr ) < 0 ) {
57111 if (g_options .only_desired_port == 1 )
58- ERR ("Bind on port failed. "
112+ ERR ("IPv6 bind on port failed. "
59113 "Requested port may be taken or require root permissions." );
60114 goto error ;
61115 }
62116
63117 // Let kernel over-accept max number of connections
64118 if (listen (this -> sd , HTTP_MAX_PENDING_CONNS ) < 0 ) {
65- ERR ("listen failed on socket" );
119+ ERR ("IPv6 listen failed on socket" );
66120 goto error ;
67121 }
68122
@@ -179,20 +233,58 @@ void tcp_packet_send(struct tcp_conn_t *conn, struct http_packet_t *pkt)
179233}
180234
181235
182- struct tcp_conn_t * tcp_conn_accept (struct tcp_sock_t * sock )
236+ struct tcp_conn_t * tcp_conn_select (struct tcp_sock_t * sock ,
237+ struct tcp_sock_t * sock6 )
183238{
184239 struct tcp_conn_t * conn = calloc (1 , sizeof * conn );
185240 if (conn == NULL ) {
186241 ERR ("Calloc for connection struct failed" );
187242 goto error ;
188243 }
244+ fd_set rfds ;
245+ struct timeval tv ;
246+ int retval = 0 ;
247+ int nfds = 0 ;
248+ while (retval == 0 ) {
249+ FD_ZERO (& rfds );
250+ if (sock ) {
251+ FD_SET (sock -> sd , & rfds );
252+ nfds = sock -> sd ;
253+ }
254+ if (sock6 ) {
255+ FD_SET (sock6 -> sd , & rfds );
256+ if (sock6 -> sd > nfds )
257+ nfds = sock6 -> sd ;
258+ }
259+ if (nfds == 0 ) {
260+ ERR ("No valid TCP socket supplied." );
261+ goto error ;
262+ }
263+ nfds += 1 ;
264+ /* Wait up to five seconds. */
265+ tv .tv_sec = 5 ;
266+ tv .tv_usec = 0 ;
267+ retval = select (nfds , & rfds , NULL , NULL , & tv );
268+ if (retval == -1 ) {
269+ ERR ("Failed to open tcp connection" );
270+ goto error ;
271+ }
272+ }
189273
190- conn -> sd = accept (sock -> sd , NULL , NULL );
274+ if (sock && FD_ISSET (sock -> sd , & rfds )) {
275+ conn -> sd = accept (sock -> sd , NULL , NULL );
276+ NOTE ("Using IPv4" );
277+ } else if (sock6 && FD_ISSET (sock6 -> sd , & rfds )) {
278+ conn -> sd = accept (sock6 -> sd , NULL , NULL );
279+ NOTE ("Using IPv6" );
280+ } else {
281+ ERR ("select failed" );
282+ goto error ;
283+ }
191284 if (conn -> sd < 0 ) {
192285 ERR ("accept failed" );
193286 goto error ;
194287 }
195-
196288 return conn ;
197289
198290error :
0 commit comments