xref: /third_party/pulseaudio/src/pulsecore/pipe.c (revision 53a5a1b3)
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