Line data Source code
1 : /* 2 : Unix SMB/CIFS implementation. 3 : Samba utility functions 4 : Copyright (C) Andrew Tridgell 1992-1998 5 : Copyright (C) Tim Potter 2000-2001 6 : 7 : This program is free software; you can redistribute it and/or modify 8 : it under the terms of the GNU General Public License as published by 9 : the Free Software Foundation; either version 3 of the License, or 10 : (at your option) any later version. 11 : 12 : This program is distributed in the hope that it will be useful, 13 : but WITHOUT ANY WARRANTY; without even the implied warranty of 14 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 : GNU General Public License for more details. 16 : 17 : You should have received a copy of the GNU General Public License 18 : along with this program. If not, see <http://www.gnu.org/licenses/>. 19 : */ 20 : 21 : #include "includes.h" 22 : #include "system/network.h" 23 : #include "socketpair_tcp.h" 24 : 25 : /******************************************************************* 26 : this is like socketpair but uses tcp. It is used by the Samba 27 : regression test code 28 : The function guarantees that nobody else can attach to the socket, 29 : or if they do that this function fails and the socket gets closed 30 : returns 0 on success, -1 on failure 31 : the resulting file descriptors are symmetrical 32 : ******************************************************************/ 33 11 : int socketpair_tcp(int fd[2]) 34 : { 35 11 : int listener; 36 11 : struct sockaddr_in sock; 37 11 : struct sockaddr_in sock2; 38 11 : socklen_t socklen = sizeof(sock); 39 11 : int connect_done = 0; 40 : 41 11 : fd[0] = fd[1] = listener = -1; 42 : 43 11 : memset(&sock, 0, sizeof(sock)); 44 : 45 11 : if ((listener = socket(PF_INET, SOCK_STREAM, 0)) == -1) goto failed; 46 : 47 11 : memset(&sock2, 0, sizeof(sock2)); 48 : #ifdef HAVE_SOCK_SIN_LEN 49 : sock2.sin_len = sizeof(sock2); 50 : #endif 51 11 : sock2.sin_family = PF_INET; 52 : 53 11 : if (bind(listener, (struct sockaddr *)&sock2, sizeof(sock2)) != 0) goto failed; 54 : 55 11 : if (listen(listener, 1) != 0) goto failed; 56 : 57 11 : if (getsockname(listener, (struct sockaddr *)&sock, &socklen) != 0) goto failed; 58 : 59 11 : if ((fd[1] = socket(PF_INET, SOCK_STREAM, 0)) == -1) goto failed; 60 : 61 11 : set_blocking(fd[1], 0); 62 : 63 11 : sock.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 64 : 65 11 : if (connect(fd[1], (struct sockaddr *)&sock, socklen) == -1) { 66 11 : if (errno != EINPROGRESS) goto failed; 67 : } else { 68 : connect_done = 1; 69 : } 70 : 71 11 : if ((fd[0] = accept(listener, (struct sockaddr *)&sock, &socklen)) == -1) goto failed; 72 : 73 11 : if (connect_done == 0) { 74 11 : if (connect(fd[1], (struct sockaddr *)&sock, socklen) != 0 75 0 : && errno != EISCONN) goto failed; 76 : } 77 11 : close(listener); 78 : 79 11 : set_blocking(fd[1], 1); 80 : 81 : /* all OK! */ 82 11 : return 0; 83 : 84 0 : failed: 85 0 : if (fd[0] != -1) close(fd[0]); 86 0 : if (fd[1] != -1) close(fd[1]); 87 0 : if (listener != -1) close(listener); 88 : return -1; 89 : }