153a5a1b3Sopenharmony_ci/*** 253a5a1b3Sopenharmony_ci This file is part of PulseAudio. 353a5a1b3Sopenharmony_ci 453a5a1b3Sopenharmony_ci Copyright 2006-2007 Pierre Ossman <ossman@cendio.se> for Cendio AB 553a5a1b3Sopenharmony_ci 653a5a1b3Sopenharmony_ci PulseAudio is free software; you can redistribute it and/or modify 753a5a1b3Sopenharmony_ci it under the terms of the GNU Lesser General Public License as published 853a5a1b3Sopenharmony_ci by the Free Software Foundation; either version 2.1 of the License, 953a5a1b3Sopenharmony_ci or (at your option) any later version. 1053a5a1b3Sopenharmony_ci 1153a5a1b3Sopenharmony_ci PulseAudio is distributed in the hope that it will be useful, but 1253a5a1b3Sopenharmony_ci WITHOUT ANY WARRANTY; without even the implied warranty of 1353a5a1b3Sopenharmony_ci MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1453a5a1b3Sopenharmony_ci General Public License for more details. 1553a5a1b3Sopenharmony_ci 1653a5a1b3Sopenharmony_ci You should have received a copy of the GNU Lesser General Public License 1753a5a1b3Sopenharmony_ci along with PulseAudio; if not, see <http://www.gnu.org/licenses/>. 1853a5a1b3Sopenharmony_ci***/ 1953a5a1b3Sopenharmony_ci 2053a5a1b3Sopenharmony_ci#ifdef HAVE_CONFIG_H 2153a5a1b3Sopenharmony_ci#include <config.h> 2253a5a1b3Sopenharmony_ci#endif 2353a5a1b3Sopenharmony_ci 2453a5a1b3Sopenharmony_ci#include <errno.h> 2553a5a1b3Sopenharmony_ci#include <unistd.h> 2653a5a1b3Sopenharmony_ci#include <fcntl.h> 2753a5a1b3Sopenharmony_ci 2853a5a1b3Sopenharmony_ci#include <sys/types.h> 2953a5a1b3Sopenharmony_ci 3053a5a1b3Sopenharmony_ci#include <pulsecore/socket.h> 3153a5a1b3Sopenharmony_ci#include <pulsecore/core-util.h> 3253a5a1b3Sopenharmony_ci 3353a5a1b3Sopenharmony_ci#include "pipe.h" 3453a5a1b3Sopenharmony_ci 3553a5a1b3Sopenharmony_ci#ifndef HAVE_PIPE 3653a5a1b3Sopenharmony_ci 3753a5a1b3Sopenharmony_cistatic int set_block(int fd, int blocking) { 3853a5a1b3Sopenharmony_ci#ifdef O_NONBLOCK 3953a5a1b3Sopenharmony_ci 4053a5a1b3Sopenharmony_ci int v; 4153a5a1b3Sopenharmony_ci 4253a5a1b3Sopenharmony_ci pa_assert(fd >= 0); 4353a5a1b3Sopenharmony_ci 4453a5a1b3Sopenharmony_ci if ((v = fcntl(fd, F_GETFL)) < 0) 4553a5a1b3Sopenharmony_ci return -1; 4653a5a1b3Sopenharmony_ci 4753a5a1b3Sopenharmony_ci if (blocking) 4853a5a1b3Sopenharmony_ci v &= ~O_NONBLOCK; 4953a5a1b3Sopenharmony_ci else 5053a5a1b3Sopenharmony_ci v |= O_NONBLOCK; 5153a5a1b3Sopenharmony_ci 5253a5a1b3Sopenharmony_ci if (fcntl(fd, F_SETFL, v) < 0) 5353a5a1b3Sopenharmony_ci return -1; 5453a5a1b3Sopenharmony_ci 5553a5a1b3Sopenharmony_ci return 0; 5653a5a1b3Sopenharmony_ci 5753a5a1b3Sopenharmony_ci#elif defined(OS_IS_WIN32) 5853a5a1b3Sopenharmony_ci 5953a5a1b3Sopenharmony_ci u_long arg; 6053a5a1b3Sopenharmony_ci 6153a5a1b3Sopenharmony_ci arg = !blocking; 6253a5a1b3Sopenharmony_ci 6353a5a1b3Sopenharmony_ci if (ioctlsocket(fd, FIONBIO, &arg) < 0) 6453a5a1b3Sopenharmony_ci return -1; 6553a5a1b3Sopenharmony_ci 6653a5a1b3Sopenharmony_ci return 0; 6753a5a1b3Sopenharmony_ci 6853a5a1b3Sopenharmony_ci#else 6953a5a1b3Sopenharmony_ci 7053a5a1b3Sopenharmony_ci return -1; 7153a5a1b3Sopenharmony_ci 7253a5a1b3Sopenharmony_ci#endif 7353a5a1b3Sopenharmony_ci} 7453a5a1b3Sopenharmony_ci 7553a5a1b3Sopenharmony_ciint pipe(int filedes[2]) { 7653a5a1b3Sopenharmony_ci int listener; 7753a5a1b3Sopenharmony_ci struct sockaddr_in addr, peer; 7853a5a1b3Sopenharmony_ci socklen_t len; 7953a5a1b3Sopenharmony_ci 8053a5a1b3Sopenharmony_ci listener = -1; 8153a5a1b3Sopenharmony_ci filedes[0] = -1; 8253a5a1b3Sopenharmony_ci filedes[1] = -1; 8353a5a1b3Sopenharmony_ci 8453a5a1b3Sopenharmony_ci listener = socket(PF_INET, SOCK_STREAM, 0); 8553a5a1b3Sopenharmony_ci if (listener < 0) 8653a5a1b3Sopenharmony_ci goto error; 8753a5a1b3Sopenharmony_ci 8853a5a1b3Sopenharmony_ci filedes[0] = socket(PF_INET, SOCK_STREAM, 0); 8953a5a1b3Sopenharmony_ci if (filedes[0] < 0) 9053a5a1b3Sopenharmony_ci goto error; 9153a5a1b3Sopenharmony_ci 9253a5a1b3Sopenharmony_ci filedes[1] = socket(PF_INET, SOCK_STREAM, 0); 9353a5a1b3Sopenharmony_ci if (filedes[1] < 0) 9453a5a1b3Sopenharmony_ci goto error; 9553a5a1b3Sopenharmony_ci 9653a5a1b3Sopenharmony_ci /* Make non-blocking so that connect() won't block */ 9753a5a1b3Sopenharmony_ci if (set_block(filedes[0], 0) < 0) 9853a5a1b3Sopenharmony_ci goto error; 9953a5a1b3Sopenharmony_ci 10053a5a1b3Sopenharmony_ci addr.sin_family = AF_INET; 10153a5a1b3Sopenharmony_ci addr.sin_port = 0; 10253a5a1b3Sopenharmony_ci addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 10353a5a1b3Sopenharmony_ci 10453a5a1b3Sopenharmony_ci if (bind(listener, (struct sockaddr*)&addr, sizeof(addr)) < 0) 10553a5a1b3Sopenharmony_ci goto error; 10653a5a1b3Sopenharmony_ci 10753a5a1b3Sopenharmony_ci if (listen(listener, 1) < 0) 10853a5a1b3Sopenharmony_ci goto error; 10953a5a1b3Sopenharmony_ci 11053a5a1b3Sopenharmony_ci len = sizeof(addr); 11153a5a1b3Sopenharmony_ci if (getsockname(listener, (struct sockaddr*)&addr, &len) < 0) 11253a5a1b3Sopenharmony_ci goto error; 11353a5a1b3Sopenharmony_ci 11453a5a1b3Sopenharmony_ci if (connect(filedes[0], (struct sockaddr*)&addr, sizeof(addr)) < 0) { 11553a5a1b3Sopenharmony_ci#ifdef OS_IS_WIN32 11653a5a1b3Sopenharmony_ci if (WSAGetLastError() != EWOULDBLOCK) 11753a5a1b3Sopenharmony_ci#else 11853a5a1b3Sopenharmony_ci if (errno != EINPROGRESS) 11953a5a1b3Sopenharmony_ci#endif 12053a5a1b3Sopenharmony_ci goto error; 12153a5a1b3Sopenharmony_ci } 12253a5a1b3Sopenharmony_ci 12353a5a1b3Sopenharmony_ci len = sizeof(peer); 12453a5a1b3Sopenharmony_ci filedes[1] = accept(listener, (struct sockaddr*)&peer, &len); 12553a5a1b3Sopenharmony_ci if (filedes[1] < 0) 12653a5a1b3Sopenharmony_ci goto error; 12753a5a1b3Sopenharmony_ci 12853a5a1b3Sopenharmony_ci /* Restore blocking */ 12953a5a1b3Sopenharmony_ci if (set_block(filedes[0], 1) < 0) 13053a5a1b3Sopenharmony_ci goto error; 13153a5a1b3Sopenharmony_ci 13253a5a1b3Sopenharmony_ci len = sizeof(addr); 13353a5a1b3Sopenharmony_ci if (getsockname(filedes[0], (struct sockaddr*)&addr, &len) < 0) 13453a5a1b3Sopenharmony_ci goto error; 13553a5a1b3Sopenharmony_ci 13653a5a1b3Sopenharmony_ci /* Check that someone else didn't steal the connection */ 13753a5a1b3Sopenharmony_ci if ((addr.sin_port != peer.sin_port) || (addr.sin_addr.s_addr != peer.sin_addr.s_addr)) 13853a5a1b3Sopenharmony_ci goto error; 13953a5a1b3Sopenharmony_ci 14053a5a1b3Sopenharmony_ci pa_close(listener); 14153a5a1b3Sopenharmony_ci 14253a5a1b3Sopenharmony_ci return 0; 14353a5a1b3Sopenharmony_ci 14453a5a1b3Sopenharmony_cierror: 14553a5a1b3Sopenharmony_ci if (listener >= 0) 14653a5a1b3Sopenharmony_ci pa_close(listener); 14753a5a1b3Sopenharmony_ci if (filedes[0] >= 0) 14853a5a1b3Sopenharmony_ci pa_close(filedes[0]); 14953a5a1b3Sopenharmony_ci if (filedes[1] >= 0) 15053a5a1b3Sopenharmony_ci pa_close(filedes[1]); 15153a5a1b3Sopenharmony_ci 15253a5a1b3Sopenharmony_ci return -1; 15353a5a1b3Sopenharmony_ci} 15453a5a1b3Sopenharmony_ci 15553a5a1b3Sopenharmony_ci#endif /* HAVE_PIPE */ 156