EventPipe.cxx 3.06 KB
Newer Older
1
/*
Max Kellermann's avatar
Max Kellermann committed
2
 * Copyright 2003-2017 The Music Player Daemon Project
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
 * http://www.musicpd.org
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#include "config.h"
21
#include "EventPipe.hxx"
22
#include "FileDescriptor.hxx"
23
#include "system/Error.hxx"
24
#include "util/ScopeExit.hxx"
25
#include "Compiler.h"
26

27
#include <assert.h>
28 29
#include <unistd.h>

30
#ifdef _WIN32
31
#include "net/IPv4Address.hxx"
32 33
#include "net/StaticSocketAddress.hxx"
#include "net/UniqueSocketDescriptor.hxx"
34
#include "net/SocketError.hxx"
35 36
#endif

37
#ifdef _WIN32
38
static void PoorSocketPair(int fd[2]);
39 40
#endif

41
EventPipe::EventPipe()
42
{
43
#ifdef _WIN32
44
	PoorSocketPair(fds);
45
#else
46 47
	FileDescriptor r, w;
	if (!FileDescriptor::CreatePipeNonBlock(r, w))
48
		throw MakeErrno("pipe() has failed");
49 50

	fds[0] = r.Steal();
51
	fds[1] = w.Steal();
52
#endif
53 54
}

55
EventPipe::~EventPipe()
56
{
57
#ifdef _WIN32
58 59 60
	closesocket(fds[0]);
	closesocket(fds[1]);
#else
61
	close(fds[0]);
62 63
	close(fds[1]);
#endif
64 65 66
}

bool
67
EventPipe::Read()
68 69
{
	assert(fds[0] >= 0);
70
	assert(fds[1] >= 0);
71

72
	char buffer[256];
73
#ifdef _WIN32
74 75
	return recv(fds[0], buffer, sizeof(buffer), 0) > 0;
#else
76
	return read(fds[0], buffer, sizeof(buffer)) > 0;
77
#endif
78 79 80
}

void
81
EventPipe::Write()
82 83
{
	assert(fds[0] >= 0);
84 85
	assert(fds[1] >= 0);

86
#ifdef _WIN32
87 88
	send(fds[1], "", 1, 0);
#else
89
	gcc_unused ssize_t nbytes = write(fds[1], "", 1);
90 91 92
#endif
}

93
#ifdef _WIN32
94 95

/* Our poor man's socketpair() implementation
96
 * Due to limited protocol/address family support
97
 * it's better to keep this as a private implementation detail of EventPipe
98 99
 * rather than wide-available API.
 */
100 101
static void
PoorSocketPair(int fd[2])
102 103 104
{
	assert (fd != nullptr);

105 106
	UniqueSocketDescriptor listen_socket;
	if (!listen_socket.CreateNonBlock(AF_INET, SOCK_STREAM, IPPROTO_TCP))
107
		throw MakeSocketError("Failed to create socket");
108

109
	if (!listen_socket.Bind(IPv4Address(IPv4Address::Loopback(), 0)))
110
		throw MakeSocketError("Failed to create socket");
111

112
	if (!listen_socket.Listen(1))
113
		throw MakeSocketError("Failed to listen on socket");
114

115
	UniqueSocketDescriptor socket0;
116
	if (!socket0.Create(AF_INET, SOCK_STREAM, IPPROTO_TCP))
117
		throw MakeSocketError("Failed to create socket");
118

119
	if (!socket0.Connect(listen_socket.GetLocalAddress()))
120
		throw MakeSocketError("Failed to connect socket");
121

122 123
	socket0.SetNonBlocking();

124 125
	auto socket1 = listen_socket.AcceptNonBlock();
	if (!socket1.IsDefined())
126
		throw MakeSocketError("Failed to accept connection");
127 128 129

	fd[0] = socket0.Steal();
	fd[1] = socket1.Steal();
130
}
131 132

#endif