| /*************************************************************************** |
| * _ _ ____ _ |
| * Project ___| | | | _ \| | |
| * / __| | | | |_) | | |
| * | (__| |_| | _ <| |___ |
| * \___|\___/|_| \_\_____| |
| * |
| * Copyright (C) 2019 - 2021, Daniel Stenberg, <[email protected]>, et al. |
| * |
| * This software is licensed as described in the file COPYING, which |
| * you should have received as part of this distribution. The terms |
| * are also available at https://curl.se/docs/copyright.html. |
| * |
| * You may opt to use, copy, modify, merge, publish, distribute and/or sell |
| * copies of the Software, and permit persons to whom the Software is |
| * furnished to do so, under the terms of the COPYING file. |
| * |
| * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY |
| * KIND, either express or implied. |
| * |
| ***************************************************************************/ |
| |
| #include "curl_setup.h" |
| #include "socketpair.h" |
| |
| #if !defined(HAVE_SOCKETPAIR) && !defined(CURL_DISABLE_SOCKETPAIR) |
| #ifdef WIN32 |
| /* |
| * This is a socketpair() implementation for Windows. |
| */ |
| #include <string.h> |
| #include <winsock2.h> |
| #include <ws2tcpip.h> |
| #include <windows.h> |
| #include <io.h> |
| #else |
| #ifdef HAVE_NETDB_H |
| #include <netdb.h> |
| #endif |
| #ifdef HAVE_NETINET_IN_H |
| #include <netinet/in.h> /* IPPROTO_TCP */ |
| #endif |
| #ifdef HAVE_ARPA_INET_H |
| #include <arpa/inet.h> |
| #endif |
| #ifndef INADDR_LOOPBACK |
| #define INADDR_LOOPBACK 0x7f000001 |
| #endif /* !INADDR_LOOPBACK */ |
| #endif /* !WIN32 */ |
| |
| #include "nonblock.h" /* for curlx_nonblock */ |
| #include "timeval.h" /* needed before select.h */ |
| #include "select.h" /* for Curl_poll */ |
| |
| /* The last 3 #include files should be in this order */ |
| #include "curl_printf.h" |
| #include "curl_memory.h" |
| #include "memdebug.h" |
| |
| int Curl_socketpair(int domain, int type, int protocol, |
| curl_socket_t socks[2]) |
| { |
| union { |
| struct sockaddr_in inaddr; |
| struct sockaddr addr; |
| } a, a2; |
| curl_socket_t listener; |
| curl_socklen_t addrlen = sizeof(a.inaddr); |
| int reuse = 1; |
| struct pollfd pfd[1]; |
| (void)domain; |
| (void)type; |
| (void)protocol; |
| |
| listener = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); |
| if(listener == CURL_SOCKET_BAD) |
| return -1; |
| |
| memset(&a, 0, sizeof(a)); |
| a.inaddr.sin_family = AF_INET; |
| a.inaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); |
| a.inaddr.sin_port = 0; |
| |
| socks[0] = socks[1] = CURL_SOCKET_BAD; |
| |
| if(setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, |
| (char *)&reuse, (curl_socklen_t)sizeof(reuse)) == -1) |
| goto error; |
| if(bind(listener, &a.addr, sizeof(a.inaddr)) == -1) |
| goto error; |
| if(getsockname(listener, &a.addr, &addrlen) == -1 || |
| addrlen < (int)sizeof(a.inaddr)) |
| goto error; |
| if(listen(listener, 1) == -1) |
| goto error; |
| socks[0] = socket(AF_INET, SOCK_STREAM, 0); |
| if(socks[0] == CURL_SOCKET_BAD) |
| goto error; |
| if(connect(socks[0], &a.addr, sizeof(a.inaddr)) == -1) |
| goto error; |
| |
| /* use non-blocking accept to make sure we don't block forever */ |
| if(curlx_nonblock(listener, TRUE) < 0) |
| goto error; |
| pfd[0].fd = listener; |
| pfd[0].events = POLLIN; |
| pfd[0].revents = 0; |
| (void)Curl_poll(pfd, 1, 10*1000); /* 10 seconds */ |
| socks[1] = accept(listener, NULL, NULL); |
| if(socks[1] == CURL_SOCKET_BAD) |
| goto error; |
| |
| /* verify that nothing else connected */ |
| addrlen = sizeof(a.inaddr); |
| if(getsockname(socks[0], &a.addr, &addrlen) == -1 || |
| addrlen < (int)sizeof(a.inaddr)) |
| goto error; |
| addrlen = sizeof(a2.inaddr); |
| if(getpeername(socks[1], &a2.addr, &addrlen) == -1 || |
| addrlen < (int)sizeof(a2.inaddr)) |
| goto error; |
| if(a.inaddr.sin_family != a2.inaddr.sin_family || |
| a.inaddr.sin_addr.s_addr != a2.inaddr.sin_addr.s_addr || |
| a.inaddr.sin_port != a2.inaddr.sin_port) |
| goto error; |
| |
| sclose(listener); |
| return 0; |
| |
| error: |
| sclose(listener); |
| sclose(socks[0]); |
| sclose(socks[1]); |
| return -1; |
| } |
| |
| #endif /* ! HAVE_SOCKETPAIR */ |