1/*** 2 This file is part of PulseAudio. 3 4 Copyright 2006-2007 Pierre Ossman <ossman@cendio.se> for Cendio AB 5 6 PulseAudio is free software; you can redistribute it and/or modify 7 it under the terms of the GNU Lesser General Public License as published 8 by the Free Software Foundation; either version 2.1 of the License, 9 or (at your option) any later version. 10 11 PulseAudio is distributed in the hope that it will be useful, but 12 WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 General Public License for more details. 15 16 You should have received a copy of the GNU Lesser General Public License 17 along with PulseAudio; if not, see <http://www.gnu.org/licenses/>. 18***/ 19 20#ifdef HAVE_CONFIG_H 21#include <config.h> 22#endif 23 24#include <errno.h> 25#include <unistd.h> 26#include <fcntl.h> 27 28#include <sys/types.h> 29 30#include <pulsecore/socket.h> 31#include <pulsecore/core-util.h> 32 33#include "pipe.h" 34 35#ifndef HAVE_PIPE 36 37static int set_block(int fd, int blocking) { 38#ifdef O_NONBLOCK 39 40 int v; 41 42 pa_assert(fd >= 0); 43 44 if ((v = fcntl(fd, F_GETFL)) < 0) 45 return -1; 46 47 if (blocking) 48 v &= ~O_NONBLOCK; 49 else 50 v |= O_NONBLOCK; 51 52 if (fcntl(fd, F_SETFL, v) < 0) 53 return -1; 54 55 return 0; 56 57#elif defined(OS_IS_WIN32) 58 59 u_long arg; 60 61 arg = !blocking; 62 63 if (ioctlsocket(fd, FIONBIO, &arg) < 0) 64 return -1; 65 66 return 0; 67 68#else 69 70 return -1; 71 72#endif 73} 74 75int pipe(int filedes[2]) { 76 int listener; 77 struct sockaddr_in addr, peer; 78 socklen_t len; 79 80 listener = -1; 81 filedes[0] = -1; 82 filedes[1] = -1; 83 84 listener = socket(PF_INET, SOCK_STREAM, 0); 85 if (listener < 0) 86 goto error; 87 88 filedes[0] = socket(PF_INET, SOCK_STREAM, 0); 89 if (filedes[0] < 0) 90 goto error; 91 92 filedes[1] = socket(PF_INET, SOCK_STREAM, 0); 93 if (filedes[1] < 0) 94 goto error; 95 96 /* Make non-blocking so that connect() won't block */ 97 if (set_block(filedes[0], 0) < 0) 98 goto error; 99 100 addr.sin_family = AF_INET; 101 addr.sin_port = 0; 102 addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 103 104 if (bind(listener, (struct sockaddr*)&addr, sizeof(addr)) < 0) 105 goto error; 106 107 if (listen(listener, 1) < 0) 108 goto error; 109 110 len = sizeof(addr); 111 if (getsockname(listener, (struct sockaddr*)&addr, &len) < 0) 112 goto error; 113 114 if (connect(filedes[0], (struct sockaddr*)&addr, sizeof(addr)) < 0) { 115#ifdef OS_IS_WIN32 116 if (WSAGetLastError() != EWOULDBLOCK) 117#else 118 if (errno != EINPROGRESS) 119#endif 120 goto error; 121 } 122 123 len = sizeof(peer); 124 filedes[1] = accept(listener, (struct sockaddr*)&peer, &len); 125 if (filedes[1] < 0) 126 goto error; 127 128 /* Restore blocking */ 129 if (set_block(filedes[0], 1) < 0) 130 goto error; 131 132 len = sizeof(addr); 133 if (getsockname(filedes[0], (struct sockaddr*)&addr, &len) < 0) 134 goto error; 135 136 /* Check that someone else didn't steal the connection */ 137 if ((addr.sin_port != peer.sin_port) || (addr.sin_addr.s_addr != peer.sin_addr.s_addr)) 138 goto error; 139 140 pa_close(listener); 141 142 return 0; 143 144error: 145 if (listener >= 0) 146 pa_close(listener); 147 if (filedes[0] >= 0) 148 pa_close(filedes[0]); 149 if (filedes[1] >= 0) 150 pa_close(filedes[1]); 151 152 return -1; 153} 154 155#endif /* HAVE_PIPE */ 156