1- /* Copyright (c) 2012, 2018 , Oracle and/or its affiliates. All rights reserved.
1+ /* Copyright (c) 2012, 2019 , Oracle and/or its affiliates. All rights reserved.
22
33 This program is free software; you can redistribute it and/or modify
44 it under the terms of the GNU General Public License, version 2.0,
@@ -1390,6 +1390,33 @@ static result create_server_socket() {
13901390 return fd ;
13911391}
13921392
1393+ static result create_server_socket_v4 () {
1394+ result fd = {0 , 0 };
1395+ /* Create socket */
1396+ if ((fd = xcom_checked_socket (AF_INET , SOCK_STREAM , IPPROTO_TCP )).val < 0 ) {
1397+ G_MESSAGE (
1398+ "Unable to create socket v4"
1399+ "(socket=%d, errno=%d)!" ,
1400+ fd .val , to_errno (GET_OS_ERR ));
1401+ return fd ;
1402+ }
1403+ {
1404+ int reuse = 1 ;
1405+ SET_OS_ERR (0 );
1406+ if (setsockopt (fd .val , SOL_SOCKET , SOCK_OPT_REUSEADDR , (void * )& reuse ,
1407+ sizeof (reuse )) < 0 ) {
1408+ fd .funerr = to_errno (GET_OS_ERR );
1409+ G_MESSAGE (
1410+ "Unable to set socket options "
1411+ "(socket=%d, errno=%d)!" ,
1412+ fd .val , to_errno (GET_OS_ERR ));
1413+ close_socket (& fd .val );
1414+ return fd ;
1415+ }
1416+ }
1417+ return fd ;
1418+ }
1419+
13931420/**
13941421 * @brief Initializes a sockaddr prepared to be used in bind()
13951422 *
@@ -1400,7 +1427,7 @@ static result create_server_socket() {
14001427 * @param port the port to bind.
14011428 */
14021429static void init_server_addr (struct sockaddr * * sock_addr , socklen_t * sock_len ,
1403- xcom_port port ) {
1430+ xcom_port port , int family ) {
14041431 struct addrinfo * address_info = NULL , hints , * address_info_loop ;
14051432 memset (& hints , 0 , sizeof (hints ));
14061433
@@ -1412,7 +1439,7 @@ static void init_server_addr(struct sockaddr **sock_addr, socklen_t *sock_len,
14121439
14131440 address_info_loop = address_info ;
14141441 while (address_info_loop ) {
1415- if (address_info_loop -> ai_family == AF_INET6 ) {
1442+ if (address_info_loop -> ai_family == family ) {
14161443 if (* sock_addr == NULL ) {
14171444 * sock_addr = (struct sockaddr * )malloc (address_info_loop -> ai_addrlen );
14181445 }
@@ -1433,18 +1460,40 @@ result announce_tcp(xcom_port port) {
14331460 result fd ;
14341461 struct sockaddr * sock_addr = NULL ;
14351462 socklen_t sock_addr_len ;
1463+ int server_socket_v6_ok = 0 ;
14361464
1465+ // Try and create a V6 server socket. It should succeed if the OS
1466+ // supports IPv6, and fail otherwise.
14371467 fd = create_server_socket ();
14381468 if (fd .val < 0 ) {
1439- return fd ;
1469+ // If the OS does not support IPv6, we fall back to IPv4.
1470+ fd = create_server_socket_v4 ();
1471+ if (fd .val < 0 ) {
1472+ return fd ;
1473+ }
1474+ } else {
1475+ server_socket_v6_ok = 1 ;
14401476 }
1441- init_server_addr (& sock_addr , & sock_addr_len , port );
1477+ init_server_addr (& sock_addr , & sock_addr_len , port ,
1478+ server_socket_v6_ok ? AF_INET6 : AF_INET );
14421479 if (sock_addr == NULL || (bind (fd .val , sock_addr , sock_addr_len ) < 0 )) {
1443- int err = to_errno (GET_OS_ERR );
1444- G_MESSAGE ("Unable to bind to %s:%d (socket=%d, errno=%d)!" , "INADDR_ANY" ,
1445- port , fd .val , err );
1446- goto err ;
1480+ // If we fail to bind to the desired address, we fall back to an
1481+ // IPv4 socket.
1482+ fd = create_server_socket_v4 ();
1483+ if (fd .val < 0 ) {
1484+ return fd ;
1485+ }
1486+
1487+ free (sock_addr );
1488+ init_server_addr (& sock_addr , & sock_addr_len , port , AF_INET );
1489+ if (bind (fd .val , sock_addr , sock_addr_len ) < 0 ) {
1490+ int err = to_errno (GET_OS_ERR );
1491+ G_MESSAGE ("Unable to bind to %s:%d (socket=%d, errno=%d)!" , "INADDR_ANY" ,
1492+ port , fd .val , err );
1493+ goto err ;
1494+ }
14471495 }
1496+
14481497 G_DEBUG ("Successfully bound to %s:%d (socket=%d)." , "INADDR_ANY" , port ,
14491498 fd .val );
14501499 if (listen (fd .val , 32 ) < 0 ) {
@@ -1490,38 +1539,83 @@ result announce_tcp(xcom_port port) {
14901539 * These are used by the local_server and the XCom queue. They will use a local
14911540 * TCP connection to signal that the queue has work to be consumed.
14921541 */
1493- static void init_local_server_addr (struct sockaddr_in6 * sock_addr ) {
1542+ static void init_local_server_addr_v6 (struct sockaddr_in6 * sock_addr ) {
14941543 memset (sock_addr , 0 , sizeof (* sock_addr ));
14951544 sock_addr -> sin6_family = AF_INET6 ;
14961545 sock_addr -> sin6_addr = in6addr_loopback ;
14971546 sock_addr -> sin6_port = 0 ;
14981547}
14991548
1549+ static void init_local_server_addr_v4 (struct sockaddr_in * sock_addr ) {
1550+ memset (sock_addr , 0 , sizeof (* sock_addr ));
1551+ sock_addr -> sin_family = AF_INET ;
1552+ sock_addr -> sin_addr .s_addr = htonl (INADDR_LOOPBACK );
1553+ sock_addr -> sin_port = 0 ;
1554+ }
1555+
15001556result announce_tcp_local_server () {
15011557 result fd ;
15021558 struct sockaddr_in6 sock_addr ;
15031559 struct sockaddr_in6 bound_addr ;
1504- socklen_t bound_addr_len = sizeof (bound_addr );
1560+ struct sockaddr_in sock_addr_v4 ;
1561+ struct sockaddr_in bound_addr_v4 ;
1562+ int bind_v6 = 0 ;
1563+
15051564 int error_code = 0 ;
1565+ xcom_port port = 0 ;
1566+ socklen_t bound_addr_len = 0 ;
15061567
1568+ // Try to create an IPv6 server socket. It should succeed if the
1569+ // OS supports IPv6, and fail otherwise.
15071570 fd = create_server_socket ();
15081571 if (fd .val < 0 ) {
1509- /* purecov: begin inspected */
1510- return fd ;
1511- /* purecov: end */
1572+ // If the OS does *not* support IPv6, we fall back to IPv4.
1573+ fd = create_server_socket_v4 ();
1574+ if (fd .val < 0 ) {
1575+ return fd ;
1576+ }
1577+ } else {
1578+ bind_v6 = 1 ;
15121579 }
1513- init_local_server_addr (& sock_addr );
1514- xcom_port port = 0 ;
1515- if (bind (fd .val , (struct sockaddr * )& sock_addr , sizeof (sock_addr )) < 0 ) {
1516- /* purecov: begin inspected */
1517- int err = to_errno (GET_OS_ERR );
1518- G_MESSAGE ("Unable to bind to %s:%d (socket=%d, errno=%d)!" , "0.0.0.0" , port ,
1519- fd .val , err );
1520- goto err ;
1521- /* purecov: end */
1580+
1581+ int bind_result = 0 ;
1582+ if (bind_v6 ) {
1583+ init_local_server_addr_v6 (& sock_addr );
1584+ bind_result =
1585+ bind (fd .val , (struct sockaddr * )& sock_addr , sizeof (sock_addr ));
1586+ }
1587+
1588+ if (bind_result < 0 || !bind_v6 ) {
1589+ if (bind_result < 0 ) {
1590+ fd = create_server_socket_v4 ();
1591+ }
1592+ // If we fail to bind to the desired address,
1593+ // we fall back to an IPv4 socket.
1594+ init_local_server_addr_v4 (& sock_addr_v4 );
1595+ bind_result =
1596+ bind (fd .val , (struct sockaddr * )& sock_addr_v4 , sizeof (sock_addr_v4 ));
1597+
1598+ if (bind_result < 0 ) {
1599+ /* purecov: begin inspected */
1600+ int err = to_errno (GET_OS_ERR );
1601+ G_MESSAGE ("Unable to bind to %s:%d (socket=%d, errno=%d)!" , "0.0.0.0" ,
1602+ port , fd .val , err );
1603+ goto err ;
1604+ /* purecov: end */
1605+ } else {
1606+ bind_v6 = 0 ;
1607+ }
1608+ }
1609+
1610+ if (bind_v6 ) {
1611+ bound_addr_len = sizeof (bound_addr );
1612+ error_code =
1613+ getsockname (fd .val , (struct sockaddr * )& bound_addr , & bound_addr_len );
1614+ } else {
1615+ bound_addr_len = sizeof (bound_addr_v4 );
1616+ error_code =
1617+ getsockname (fd .val , (struct sockaddr * )& bound_addr_v4 , & bound_addr_len );
15221618 }
1523- error_code =
1524- getsockname (fd .val , (struct sockaddr * )& bound_addr , & bound_addr_len );
15251619 if (error_code != 0 ) {
15261620 /* purecov: begin inspected */
15271621 G_MESSAGE (
@@ -1531,7 +1625,13 @@ result announce_tcp_local_server() {
15311625 goto err ;
15321626 /* purecov: end */
15331627 }
1534- port = ntohs (bound_addr .sin6_port );
1628+
1629+ if (bind_v6 ) {
1630+ port = ntohs (bound_addr .sin6_port );
1631+ } else {
1632+ port = ntohs (bound_addr_v4 .sin_port );
1633+ }
1634+
15351635 G_DEBUG ("Successfully bound to %s:%d (socket=%d)." , "0.0.0.0" , port , fd .val );
15361636 if (listen (fd .val , 32 ) < 0 ) {
15371637 /* purecov: begin inspected */
@@ -1563,7 +1663,6 @@ result announce_tcp_local_server() {
15631663 close_socket (& fd .val );
15641664 return fd ;
15651665}
1566-
15671666int accept_tcp (int fd , int * ret ) {
15681667 struct sockaddr_storage sock_addr ;
15691668 DECL_ENV
0 commit comments