From b70d38dc10868a7ddfac2df7001be36fc37fc21c Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Wed, 7 Aug 2013 10:31:31 +0200 Subject: Makefile.am: move sources to libsystem.a --- Makefile.am | 60 +++--- src/ClientNew.cxx | 4 +- src/Daemon.cxx | 2 +- src/Daemon.hxx | 2 +- src/DecoderThread.cxx | 2 +- src/FatalError.cxx | 91 ---------- src/FatalError.hxx | 58 ------ src/InotifySource.cxx | 4 +- src/Log.cxx | 4 +- src/Main.cxx | 2 +- src/MusicBuffer.cxx | 2 +- src/OutputAll.cxx | 2 +- src/OutputThread.cxx | 2 +- src/PlayerThread.cxx | 2 +- src/SignalHandlers.cxx | 2 +- src/SocketError.hxx | 156 ---------------- src/SocketUtil.cxx | 95 ---------- src/SocketUtil.hxx | 58 ------ src/Timer.cxx | 2 +- src/UpdateGlue.cxx | 2 +- src/clock.c | 98 ---------- src/clock.h | 49 ----- src/event/BufferedSocket.cxx | 2 +- src/event/EventFD.cxx | 2 +- src/event/EventPipe.cxx | 2 +- src/event/FullyBufferedSocket.cxx | 2 +- src/event/MultiSocketMonitor.cxx | 2 +- src/event/ServerSocket.cxx | 8 +- src/event/SocketMonitor.cxx | 2 +- src/fd_util.c | 353 ------------------------------------ src/fd_util.h | 168 ----------------- src/fs/FileSystem.hxx | 2 +- src/input/FileInputPlugin.cxx | 2 +- src/mixer/OssMixerPlugin.cxx | 2 +- src/output/FifoOutputPlugin.cxx | 2 +- src/output/HttpdClient.cxx | 2 +- src/output/HttpdOutputPlugin.cxx | 4 +- src/output/OssOutputPlugin.cxx | 2 +- src/output/RecorderOutputPlugin.cxx | 2 +- src/output/SolarisOutputPlugin.cxx | 2 +- src/resolver.c | 140 -------------- src/resolver.h | 74 -------- src/system/FatalError.cxx | 91 ++++++++++ src/system/FatalError.hxx | 58 ++++++ src/system/SocketError.hxx | 156 ++++++++++++++++ src/system/SocketUtil.cxx | 95 ++++++++++ src/system/SocketUtil.hxx | 58 ++++++ src/system/clock.c | 98 ++++++++++ src/system/clock.h | 49 +++++ src/system/fd_util.c | 353 ++++++++++++++++++++++++++++++++++++ src/system/fd_util.h | 168 +++++++++++++++++ src/system/resolver.c | 140 ++++++++++++++ src/system/resolver.h | 74 ++++++++ test/run_resolver.c | 2 +- 54 files changed, 1409 insertions(+), 1407 deletions(-) delete mode 100644 src/FatalError.cxx delete mode 100644 src/FatalError.hxx delete mode 100644 src/SocketError.hxx delete mode 100644 src/SocketUtil.cxx delete mode 100644 src/SocketUtil.hxx delete mode 100644 src/clock.c delete mode 100644 src/clock.h delete mode 100644 src/fd_util.c delete mode 100644 src/fd_util.h delete mode 100644 src/resolver.c delete mode 100644 src/resolver.h create mode 100644 src/system/FatalError.cxx create mode 100644 src/system/FatalError.hxx create mode 100644 src/system/SocketError.hxx create mode 100644 src/system/SocketUtil.cxx create mode 100644 src/system/SocketUtil.hxx create mode 100644 src/system/clock.c create mode 100644 src/system/clock.h create mode 100644 src/system/fd_util.c create mode 100644 src/system/fd_util.h create mode 100644 src/system/resolver.c create mode 100644 src/system/resolver.h diff --git a/Makefile.am b/Makefile.am index b21761092..8b5f7cc9a 100644 --- a/Makefile.am +++ b/Makefile.am @@ -9,6 +9,7 @@ bin_PROGRAMS = src/mpd noinst_LIBRARIES = \ libutil.a \ + libsystem.a \ libevent.a \ libpcm.a \ libconf.a \ @@ -43,6 +44,7 @@ src_mpd_LDADD = \ $(MIXER_LIBS) \ libconf.a \ libevent.a \ + libsystem.a \ libutil.a \ libfs.a \ $(SYSTEMD_DAEMON_LIBS) \ @@ -54,7 +56,6 @@ mpd_headers = \ src/filter_internal.h \ src/command.h \ src/conf.h \ - src/fd_util.h \ src/gerror.h \ src/glib_compat.h \ src/gcc.h \ @@ -91,8 +92,6 @@ src_mpd_SOURCES = \ src/thread/PosixCond.hxx \ src/thread/WindowsCond.hxx \ src/thread/GLibCond.hxx \ - src/FatalError.cxx src/FatalError.hxx \ - src/clock.c src/clock.h \ src/notify.cxx src/notify.hxx \ src/AudioConfig.cxx src/AudioConfig.hxx \ src/CheckAudioFormat.cxx src/CheckAudioFormat.hxx \ @@ -135,7 +134,6 @@ src_mpd_SOURCES = \ src/DatabaseVisitor.hxx \ src/DatabaseSelection.cxx src/DatabaseSelection.hxx \ src/ExcludeList.cxx src/ExcludeList.hxx \ - src/fd_util.c \ src/FilterConfig.cxx src/FilterConfig.hxx \ src/FilterPlugin.cxx src/FilterPlugin.hxx \ src/FilterRegistry.cxx src/FilterRegistry.hxx \ @@ -166,7 +164,6 @@ src_mpd_SOURCES = \ src/Listen.cxx src/Listen.hxx \ src/Log.cxx src/Log.hxx \ src/ls.cxx \ - src/SocketError.hxx \ src/io_error.h \ src/IOThread.cxx src/IOThread.hxx \ src/Main.cxx src/Main.hxx \ @@ -210,8 +207,6 @@ src_mpd_SOURCES = \ src/SongPrint.cxx src/SongPrint.hxx \ src/SongSave.cxx src/SongSave.hxx \ src/SongSort.cxx src/SongSort.hxx \ - src/resolver.c src/resolver.h \ - src/SocketUtil.cxx src/SocketUtil.hxx \ src/StateFile.cxx src/StateFile.hxx \ src/Stats.cxx \ src/TagType.h \ @@ -285,6 +280,16 @@ libutil_a_SOURCES = \ src/util/byte_reverse.c src/util/byte_reverse.h \ src/util/bit_reverse.c src/util/bit_reverse.h +# System library + +libsystem_a_SOURCES = \ + src/system/FatalError.cxx src/system/FatalError.hxx \ + src/system/fd_util.c src/system/fd_util.h \ + src/system/SocketUtil.cxx src/system/SocketUtil.hxx \ + src/system/SocketError.hxx \ + src/system/resolver.c src/system/resolver.h \ + src/system/clock.c src/system/clock.h + # Event loop library libevent_a_SOURCES = \ @@ -1057,9 +1062,9 @@ test_read_conf_LDADD = \ test_read_conf_SOURCES = test/read_conf.cxx test_run_resolver_LDADD = \ + libsystem.a \ $(GLIB_LIBS) -test_run_resolver_SOURCES = test/run_resolver.c \ - src/resolver.c +test_run_resolver_SOURCES = test/run_resolver.c test_DumpDatabase_LDADD = \ $(DB_LIBS) \ @@ -1084,13 +1089,13 @@ test_run_input_LDADD = \ libconf.a \ libutil.a \ libevent.a \ + libsystem.a \ libfs.a \ $(GLIB_LIBS) test_run_input_SOURCES = test/run_input.cxx \ test/stdbin.h \ src/IOThread.cxx \ - src/Tag.cxx src/TagNames.c src/TagPool.cxx src/TagSave.cxx \ - src/fd_util.c + src/Tag.cxx src/TagNames.c src/TagPool.cxx src/TagSave.cxx if ENABLE_ARCHIVE @@ -1100,13 +1105,13 @@ test_visit_archive_LDADD = \ libconf.a \ libutil.a \ libevent.a \ + libsystem.a \ libfs.a \ $(GLIB_LIBS) test_visit_archive_SOURCES = test/visit_archive.cxx \ src/IOThread.cxx \ src/InputStream.cxx \ - src/Tag.cxx src/TagNames.c src/TagPool.cxx \ - src/fd_util.c + src/Tag.cxx src/TagNames.c src/TagPool.cxx if ENABLE_DESPOTIFY test_visit_archive_SOURCES += src/DespotifyUtils.cxx @@ -1120,14 +1125,14 @@ test_dump_text_file_LDADD = \ libconf.a \ libevent.a \ libfs.a \ + libsystem.a \ libutil.a \ $(GLIB_LIBS) test_dump_text_file_SOURCES = test/dump_text_file.cxx \ test/stdbin.h \ src/IOThread.cxx \ src/Tag.cxx src/TagNames.c src/TagPool.cxx \ - src/TextInputStream.cxx \ - src/fd_util.c + src/TextInputStream.cxx test_dump_playlist_LDADD = \ $(PLAYLIST_LIBS) \ @@ -1138,6 +1143,7 @@ test_dump_playlist_LDADD = \ $(TAG_LIBS) \ libconf.a \ libevent.a \ + libsystem.a \ libfs.a \ libutil.a \ libpcm.a \ @@ -1149,8 +1155,7 @@ test_dump_playlist_SOURCES = test/dump_playlist.cxx \ src/TagHandler.cxx src/TagFile.cxx \ src/CheckAudioFormat.cxx \ src/TextInputStream.cxx \ - src/cue/CueParser.cxx src/cue/CueParser.hxx \ - src/fd_util.c + src/cue/CueParser.cxx src/cue/CueParser.hxx if HAVE_FLAC test_dump_playlist_SOURCES += \ @@ -1166,6 +1171,7 @@ test_run_decoder_LDADD = \ $(TAG_LIBS) \ libconf.a \ libevent.a \ + libsystem.a \ libfs.a \ libutil.a \ $(GLIB_LIBS) @@ -1174,7 +1180,6 @@ test_run_decoder_SOURCES = test/run_decoder.cxx \ src/IOThread.cxx \ src/Tag.cxx src/TagNames.c src/TagPool.cxx src/TagHandler.cxx \ src/ReplayGainInfo.cxx \ - src/fd_util.c \ src/AudioFormat.cxx src/CheckAudioFormat.cxx \ $(ARCHIVE_SRC) \ $(INPUT_SRC) \ @@ -1189,6 +1194,7 @@ test_read_tags_LDADD = \ $(TAG_LIBS) \ libconf.a \ libevent.a \ + libsystem.a \ libfs.a \ libutil.a \ $(GLIB_LIBS) @@ -1196,7 +1202,6 @@ test_read_tags_SOURCES = test/read_tags.cxx \ src/IOThread.cxx \ src/Tag.cxx src/TagNames.c src/TagPool.cxx src/TagHandler.cxx \ src/ReplayGainInfo.cxx \ - src/fd_util.c \ src/CheckAudioFormat.cxx \ $(DECODER_SRC) @@ -1307,6 +1312,7 @@ test_run_output_LDADD = $(MPD_LIBS) \ libconf.a \ libevent.a \ libfs.a \ + libsystem.a \ libutil.a \ $(GLIB_LIBS) test_run_output_SOURCES = test/run_output.cxx \ @@ -1316,11 +1322,9 @@ test_run_output_SOURCES = test/run_output.cxx \ src/CheckAudioFormat.cxx \ src/AudioFormat.cxx \ src/AudioParser.cxx \ - src/Timer.cxx src/clock.c \ + src/Timer.cxx \ src/Tag.cxx src/TagNames.c src/TagPool.cxx \ src/Page.cxx \ - src/SocketUtil.cxx \ - src/resolver.c \ src/OutputInit.cxx src/OutputFinish.cxx src/OutputList.cxx \ src/OutputPlugin.cxx \ src/MixerControl.cxx \ @@ -1328,8 +1332,7 @@ test_run_output_SOURCES = test/run_output.cxx \ src/FilterPlugin.cxx \ src/FilterConfig.cxx \ src/AudioCompress/compress.c \ - src/ReplayGainInfo.cxx \ - src/fd_util.c + src/ReplayGainInfo.cxx test_read_mixer_LDADD = \ libpcm.a \ @@ -1338,13 +1341,13 @@ test_read_mixer_LDADD = \ libconf.a \ libutil.a \ libevent.a \ + libsystem.a \ libfs.a \ $(GLIB_LIBS) test_read_mixer_SOURCES = test/read_mixer.cxx \ src/MixerControl.cxx \ src/FilterPlugin.cxx \ - src/filter/VolumeFilterPlugin.cxx \ - src/fd_util.c + src/filter/VolumeFilterPlugin.cxx if ENABLE_BZIP2_TEST TESTS += test/test_archive_bzip2.sh @@ -1361,11 +1364,10 @@ endif if ENABLE_INOTIFY noinst_PROGRAMS += test/run_inotify test_run_inotify_SOURCES = test/run_inotify.cxx \ - src/FatalError.cxx \ - src/fd_util.c \ src/InotifySource.cxx test_run_inotify_LDADD = \ libevent.a \ + libsystem.a \ libutil.a \ $(GLIB_LIBS) endif @@ -1393,9 +1395,9 @@ test_test_pcm_LDADD = \ test_test_queue_priority_SOURCES = \ src/Queue.cxx \ - src/fd_util.c \ test/test_queue_priority.cxx test_test_queue_priority_LDADD = \ + libsystem.a \ libutil.a \ $(GLIB_LIBS) diff --git a/src/ClientNew.cxx b/src/ClientNew.cxx index 22127c491..c277423ab 100644 --- a/src/ClientNew.cxx +++ b/src/ClientNew.cxx @@ -22,9 +22,9 @@ #include "ClientList.hxx" #include "Partition.hxx" #include "Instance.hxx" -#include "fd_util.h" +#include "system/fd_util.h" extern "C" { -#include "resolver.h" +#include "system/resolver.h" } #include "Permission.hxx" diff --git a/src/Daemon.cxx b/src/Daemon.cxx index 84e32d43a..e0990d146 100644 --- a/src/Daemon.cxx +++ b/src/Daemon.cxx @@ -19,7 +19,7 @@ #include "config.h" #include "Daemon.hxx" -#include "FatalError.hxx" +#include "system/FatalError.hxx" #include diff --git a/src/Daemon.hxx b/src/Daemon.hxx index cd4cc965e..6c27ebc3e 100644 --- a/src/Daemon.hxx +++ b/src/Daemon.hxx @@ -46,7 +46,7 @@ daemonize_finish(void) void daemonize_kill(void); #else -#include "FatalError.hxx" +#include "system/FatalError.hxx" static inline void daemonize_kill(void) { diff --git a/src/DecoderThread.cxx b/src/DecoderThread.cxx index 61c1fdd8a..8c196cdae 100644 --- a/src/DecoderThread.cxx +++ b/src/DecoderThread.cxx @@ -24,7 +24,7 @@ #include "DecoderError.hxx" #include "DecoderPlugin.hxx" #include "Song.hxx" -#include "FatalError.hxx" +#include "system/FatalError.hxx" #include "Mapper.hxx" #include "fs/Path.hxx" #include "DecoderAPI.hxx" diff --git a/src/FatalError.cxx b/src/FatalError.cxx deleted file mode 100644 index 30ddc50ea..000000000 --- a/src/FatalError.cxx +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (C) 2003-2013 The Music Player Daemon Project - * 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 "FatalError.hxx" - -#include - -#include -#include -#include - -#ifdef WIN32 -#include -#else -#include -#endif - -#undef G_LOG_DOMAIN -#define G_LOG_DOMAIN "FatalError" - -void -FatalError(const char *msg) -{ - g_critical("%s", msg); - exit(EXIT_FAILURE); -} - -void -FormatFatalError(const char *fmt, ...) -{ - va_list ap; - va_start(ap, fmt); - g_logv(G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, fmt, ap); - va_end(ap); - - exit(EXIT_FAILURE); -} - -void -FatalError(GError *error) -{ - FatalError(error->message); -} - -void -FatalError(const char *msg, GError *error) -{ - FormatFatalError("%s: %s", msg, error->message); -} - -void -FatalSystemError(const char *msg) -{ - const char *system_error; -#ifdef WIN32 - system_error = g_win32_error_message(GetLastError()); -#else - system_error = g_strerror(errno); -#endif - - g_critical("%s: %s", msg, system_error); - exit(EXIT_FAILURE); -} - -void -FormatFatalSystemError(const char *fmt, ...) -{ - char buffer[1024]; - va_list ap; - va_start(ap, fmt); - vsnprintf(buffer, sizeof(buffer), fmt, ap); - va_end(ap); - - FatalSystemError(buffer); -} diff --git a/src/FatalError.hxx b/src/FatalError.hxx deleted file mode 100644 index 3918e5fc1..000000000 --- a/src/FatalError.hxx +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (C) 2003-2013 The Music Player Daemon Project - * 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. - */ - -#ifndef MPD_FATAL_ERROR_HXX -#define MPD_FATAL_ERROR_HXX - -#include "gerror.h" -#include "gcc.h" - -/** - * Log the specified message and abort the process. - */ -gcc_noreturn -void -FatalError(const char *msg); - -gcc_noreturn -void -FormatFatalError(const char *fmt, ...); - -gcc_noreturn -void -FatalError(GError *error); - -gcc_noreturn -void -FatalError(const char *msg, GError *error); - -/** - * Call this after a system call has failed that is not supposed to - * fail. Prints the given message, the system error message (from - * errno or GetLastError()) and abort the process. - */ -gcc_noreturn -void -FatalSystemError(const char *msg); - -gcc_noreturn -void -FormatFatalSystemError(const char *fmt, ...); - -#endif diff --git a/src/InotifySource.cxx b/src/InotifySource.cxx index ff161b6c6..9a2d4d46d 100644 --- a/src/InotifySource.cxx +++ b/src/InotifySource.cxx @@ -20,8 +20,8 @@ #include "config.h" #include "InotifySource.hxx" #include "util/fifo_buffer.h" -#include "fd_util.h" -#include "FatalError.hxx" +#include "system/fd_util.h" +#include "system/FatalError.hxx" #include diff --git a/src/Log.cxx b/src/Log.cxx index 37bff9c78..52b8be3ba 100644 --- a/src/Log.cxx +++ b/src/Log.cxx @@ -20,8 +20,8 @@ #include "config.h" #include "Log.hxx" #include "conf.h" -#include "fd_util.h" -#include "FatalError.hxx" +#include "system/fd_util.h" +#include "system/FatalError.hxx" #include "mpd_error.h" #include diff --git a/src/Main.cxx b/src/Main.cxx index 4efe59325..cbf501267 100644 --- a/src/Main.cxx +++ b/src/Main.cxx @@ -55,7 +55,7 @@ #include "AudioConfig.hxx" #include "pcm/PcmResample.hxx" #include "Daemon.hxx" -#include "FatalError.hxx" +#include "system/FatalError.hxx" extern "C" { #include "stats.h" diff --git a/src/MusicBuffer.cxx b/src/MusicBuffer.cxx index 049fb81d9..eb42a0311 100644 --- a/src/MusicBuffer.cxx +++ b/src/MusicBuffer.cxx @@ -22,7 +22,7 @@ #include "MusicChunk.hxx" #include "thread/Mutex.hxx" #include "util/SliceBuffer.hxx" -#include "FatalError.hxx" +#include "system/FatalError.hxx" #include diff --git a/src/OutputAll.cxx b/src/OutputAll.cxx index c58f54597..575eb0c70 100644 --- a/src/OutputAll.cxx +++ b/src/OutputAll.cxx @@ -26,7 +26,7 @@ #include "MusicBuffer.hxx" #include "MusicPipe.hxx" #include "MusicChunk.hxx" -#include "FatalError.hxx" +#include "system/FatalError.hxx" #include "conf.h" #include "notify.hxx" diff --git a/src/OutputThread.cxx b/src/OutputThread.cxx index 081b89f35..68c5c2c7b 100644 --- a/src/OutputThread.cxx +++ b/src/OutputThread.cxx @@ -29,7 +29,7 @@ #include "PlayerControl.hxx" #include "MusicPipe.hxx" #include "MusicChunk.hxx" -#include "FatalError.hxx" +#include "system/FatalError.hxx" #include "gcc.h" #include diff --git a/src/PlayerThread.cxx b/src/PlayerThread.cxx index 948ad9b90..87b173245 100644 --- a/src/PlayerThread.cxx +++ b/src/PlayerThread.cxx @@ -26,7 +26,7 @@ #include "MusicChunk.hxx" #include "Song.hxx" #include "Main.hxx" -#include "FatalError.hxx" +#include "system/FatalError.hxx" #include "CrossFade.hxx" #include "PlayerControl.hxx" #include "OutputAll.hxx" diff --git a/src/SignalHandlers.cxx b/src/SignalHandlers.cxx index 36408dc78..ef6be448b 100644 --- a/src/SignalHandlers.cxx +++ b/src/SignalHandlers.cxx @@ -26,7 +26,7 @@ #include "Main.hxx" #include "event/Loop.hxx" #include "GlobalEvents.hxx" -#include "FatalError.hxx" +#include "system/FatalError.hxx" #include diff --git a/src/SocketError.hxx b/src/SocketError.hxx deleted file mode 100644 index 53a0c1d8f..000000000 --- a/src/SocketError.hxx +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Copyright (C) 2003-2013 The Music Player Daemon Project - * 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. - */ - -#ifndef MPD_SOCKET_ERROR_HXX -#define MPD_SOCKET_ERROR_HXX - -#include "gcc.h" - -#include - -#ifdef WIN32 -#include -typedef DWORD socket_error_t; -#else -#include -typedef int socket_error_t; -#endif - -/** - * A GQuark for GError for socket I/O errors. The code is an errno - * value (or WSAGetLastError() on Windows). - */ -gcc_const -static inline GQuark -SocketErrorQuark(void) -{ - return g_quark_from_static_string("socket"); -} - -gcc_pure -static inline socket_error_t -GetSocketError() -{ -#ifdef WIN32 - return WSAGetLastError(); -#else - return errno; -#endif -} - -gcc_const -static inline bool -IsSocketErrorAgain(socket_error_t code) -{ -#ifdef WIN32 - return code == WSAEINPROGRESS; -#else - return code == EAGAIN; -#endif -} - -gcc_const -static inline bool -IsSocketErrorInterruped(socket_error_t code) -{ -#ifdef WIN32 - return code == WSAEINTR; -#else - return code == EINTR; -#endif -} - -gcc_const -static inline bool -IsSocketErrorClosed(socket_error_t code) -{ -#ifdef WIN32 - return code == WSAECONNRESET; -#else - return code == EPIPE || code == ECONNRESET; -#endif -} - -/** - * Helper class that formats a socket error message into a - * human-readable string. On Windows, a buffer is necessary for this, - * and this class hosts the buffer. - */ -class SocketErrorMessage { -#ifdef WIN32 - char msg[256]; -#else - const char *const msg; -#endif - -public: -#ifdef WIN32 - explicit SocketErrorMessage(socket_error_t code=GetSocketError()) { - DWORD nbytes = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS | - FORMAT_MESSAGE_MAX_WIDTH_MASK, - NULL, code, 0, - (LPSTR)msg, sizeof(msg), NULL); - if (nbytes == 0) - strcpy(msg, "Unknown error"); - } -#else - explicit SocketErrorMessage(socket_error_t code=GetSocketError()) - :msg(g_strerror(code)) {} -#endif - - operator const char *() const { - return msg; - } -}; - -static inline void -SetSocketError(GError **error_r, socket_error_t code) -{ -#ifdef WIN32 - if (error_r == NULL) - return; -#endif - - const SocketErrorMessage msg(code); - g_set_error_literal(error_r, SocketErrorQuark(), code, msg); -} - -static inline void -SetSocketError(GError **error_r) -{ - SetSocketError(error_r, GetSocketError()); -} - -gcc_malloc -static inline GError * -NewSocketError(socket_error_t code) -{ - const SocketErrorMessage msg(code); - return g_error_new_literal(SocketErrorQuark(), code, msg); -} - -gcc_malloc -static inline GError * -NewSocketError() -{ - return NewSocketError(GetSocketError()); -} - -#endif diff --git a/src/SocketUtil.cxx b/src/SocketUtil.cxx deleted file mode 100644 index dd7eb7dd2..000000000 --- a/src/SocketUtil.cxx +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright (C) 2003-2013 The Music Player Daemon Project - * 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" -#include "SocketUtil.hxx" -#include "SocketError.hxx" -#include "fd_util.h" - -#include - -#include - -#ifndef G_OS_WIN32 -#include -#else /* G_OS_WIN32 */ -#include -#include -#endif /* G_OS_WIN32 */ - -#ifdef HAVE_IPV6 -#include -#endif - -int -socket_bind_listen(int domain, int type, int protocol, - const struct sockaddr *address, size_t address_length, - int backlog, - GError **error_r) -{ - int fd, ret; - const int reuse = 1; - - fd = socket_cloexec_nonblock(domain, type, protocol); - if (fd < 0) { - SetSocketError(error_r); - g_prefix_error(error_r, "Failed to create socket: "); - return -1; - } - - ret = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, - (const char *) &reuse, sizeof(reuse)); - if (ret < 0) { - SetSocketError(error_r); - g_prefix_error(error_r, "setsockopt() failed: "); - close_socket(fd); - return -1; - } - - ret = bind(fd, address, address_length); - if (ret < 0) { - SetSocketError(error_r); - close_socket(fd); - return -1; - } - - ret = listen(fd, backlog); - if (ret < 0) { - SetSocketError(error_r); - g_prefix_error(error_r, "listen() failed: "); - close_socket(fd); - return -1; - } - -#ifdef HAVE_STRUCT_UCRED - setsockopt(fd, SOL_SOCKET, SO_PASSCRED, - (const char *) &reuse, sizeof(reuse)); -#endif - - return fd; -} - -int -socket_keepalive(int fd) -{ - const int reuse = 1; - - return setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, - (const char *)&reuse, sizeof(reuse)); -} diff --git a/src/SocketUtil.hxx b/src/SocketUtil.hxx deleted file mode 100644 index 3d0be78c4..000000000 --- a/src/SocketUtil.hxx +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (C) 2003-2013 The Music Player Daemon Project - * 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. - */ - -/* - * This library provides easy helper functions for working with - * sockets. - * - */ - -#ifndef MPD_SOCKET_UTIL_HXX -#define MPD_SOCKET_UTIL_HXX - -#include "gerror.h" - -#include - -struct sockaddr; - -/** - * Creates a socket listening on the specified address. This is a - * shortcut for socket(), bind() and listen(). - * - * @param domain the socket domain, e.g. PF_INET6 - * @param type the socket type, e.g. SOCK_STREAM - * @param protocol the protocol, usually 0 to let the kernel choose - * @param address the address to listen on - * @param address_length the size of #address - * @param backlog the backlog parameter for the listen() system call - * @param error location to store the error occurring, or NULL to - * ignore errors - * @return the socket file descriptor or -1 on error - */ -int -socket_bind_listen(int domain, int type, int protocol, - const struct sockaddr *address, size_t address_length, - int backlog, - GError **error); - -int -socket_keepalive(int fd); - -#endif diff --git a/src/Timer.cxx b/src/Timer.cxx index 18ccffbcb..75fba03aa 100644 --- a/src/Timer.cxx +++ b/src/Timer.cxx @@ -20,7 +20,7 @@ #include "config.h" #include "Timer.hxx" #include "AudioFormat.hxx" -#include "clock.h" +#include "system/clock.h" #include diff --git a/src/UpdateGlue.cxx b/src/UpdateGlue.cxx index 08ba9783f..da8f92739 100644 --- a/src/UpdateGlue.cxx +++ b/src/UpdateGlue.cxx @@ -33,7 +33,7 @@ extern "C" { #include "Main.hxx" #include "Instance.hxx" -#include "FatalError.hxx" +#include "system/FatalError.hxx" #include diff --git a/src/clock.c b/src/clock.c deleted file mode 100644 index d987aed48..000000000 --- a/src/clock.c +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright (C) 2003-2012 The Music Player Daemon Project - * 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 "clock.h" - -#ifdef WIN32 -#include -#elif defined(__APPLE__) -#include -#else -#include -#ifndef CLOCK_MONOTONIC -#include -#endif -#endif - -unsigned -monotonic_clock_ms(void) -{ -#ifdef WIN32 - return GetTickCount(); -#elif defined(__APPLE__) /* OS X does not define CLOCK_MONOTONIC */ - static mach_timebase_info_data_t base; - if (base.denom == 0) - (void)mach_timebase_info(&base); - - return (unsigned)((mach_absolute_time() * base.numer) - / (1000000 * base.denom)); -#elif defined(CLOCK_MONOTONIC) - struct timespec ts; - clock_gettime(CLOCK_MONOTONIC, &ts); - return ts.tv_sec * 1000 + ts.tv_nsec / 1000000; -#else - /* we have no monotonic clock, fall back to gettimeofday() */ - struct timeval tv; - gettimeofday(&tv, 0); - return tv.tv_sec * 1000 + tv.tv_usec / 1000; -#endif -} - -uint64_t -monotonic_clock_us(void) -{ -#ifdef WIN32 - LARGE_INTEGER l_value, l_frequency; - - if (!QueryPerformanceCounter(&l_value) || - !QueryPerformanceFrequency(&l_frequency)) - return 0; - - uint64_t value = l_value.QuadPart; - uint64_t frequency = l_frequency.QuadPart; - - if (frequency > 1000000) { - value *= 10000; - value /= frequency / 100; - } else if (frequency < 1000000) { - value *= 10000; - value /= frequency; - value *= 100; - } - - return value; -#elif defined(__APPLE__) /* OS X does not define CLOCK_MONOTONIC */ - static mach_timebase_info_data_t base; - if (base.denom == 0) - (void)mach_timebase_info(&base); - - return ((uint64_t)mach_absolute_time() * (uint64_t)base.numer) - / (1000 * (uint64_t)base.denom); -#elif defined(CLOCK_MONOTONIC) - struct timespec ts; - clock_gettime(CLOCK_MONOTONIC, &ts); - return (uint64_t)ts.tv_sec * 1000000 + (uint64_t)(ts.tv_nsec / 1000); -#else - /* we have no monotonic clock, fall back to gettimeofday() */ - struct timeval tv; - gettimeofday(&tv, 0); - return (uint64_t)tv.tv_sec * 1000 + (uint64_t)tv.tv_usec; -#endif -} - diff --git a/src/clock.h b/src/clock.h deleted file mode 100644 index c98b9a652..000000000 --- a/src/clock.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (C) 2003-2012 The Music Player Daemon Project - * 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. - */ - -#ifndef MPD_CLOCK_H -#define MPD_CLOCK_H - -#include "gcc.h" - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * Returns the value of a monotonic clock in milliseconds. - */ -gcc_pure -unsigned -monotonic_clock_ms(void); - -/** - * Returns the value of a monotonic clock in microseconds. - */ -gcc_pure -uint64_t -monotonic_clock_us(void); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/event/BufferedSocket.cxx b/src/event/BufferedSocket.cxx index 05e703441..ac3d2cf0e 100644 --- a/src/event/BufferedSocket.cxx +++ b/src/event/BufferedSocket.cxx @@ -19,7 +19,7 @@ #include "config.h" #include "BufferedSocket.hxx" -#include "SocketError.hxx" +#include "system/SocketError.hxx" #include "util/fifo_buffer.h" #include diff --git a/src/event/EventFD.cxx b/src/event/EventFD.cxx index f103c44b8..dba80d9be 100644 --- a/src/event/EventFD.cxx +++ b/src/event/EventFD.cxx @@ -20,7 +20,7 @@ #include "config.h" #ifdef USE_EVENTFD #include "EventFD.hxx" -#include "fd_util.h" +#include "system/fd_util.h" #include "gcc.h" #include diff --git a/src/event/EventPipe.cxx b/src/event/EventPipe.cxx index 0a37abe03..3b52118e4 100644 --- a/src/event/EventPipe.cxx +++ b/src/event/EventPipe.cxx @@ -19,7 +19,7 @@ #include "config.h" #include "EventPipe.hxx" -#include "fd_util.h" +#include "system/fd_util.h" #include "gcc.h" #include diff --git a/src/event/FullyBufferedSocket.cxx b/src/event/FullyBufferedSocket.cxx index a92cb68aa..f8b149500 100644 --- a/src/event/FullyBufferedSocket.cxx +++ b/src/event/FullyBufferedSocket.cxx @@ -19,7 +19,7 @@ #include "config.h" #include "FullyBufferedSocket.hxx" -#include "SocketError.hxx" +#include "system/SocketError.hxx" #include "util/fifo_buffer.h" #include diff --git a/src/event/MultiSocketMonitor.cxx b/src/event/MultiSocketMonitor.cxx index 6f20b907c..d8a9ffd6a 100644 --- a/src/event/MultiSocketMonitor.cxx +++ b/src/event/MultiSocketMonitor.cxx @@ -20,7 +20,7 @@ #include "config.h" #include "MultiSocketMonitor.hxx" #include "Loop.hxx" -#include "fd_util.h" +#include "system/fd_util.h" #include "gcc.h" #include diff --git a/src/event/ServerSocket.cxx b/src/event/ServerSocket.cxx index 119bfe1d7..a137e2d9a 100644 --- a/src/event/ServerSocket.cxx +++ b/src/event/ServerSocket.cxx @@ -24,11 +24,11 @@ #endif #include "ServerSocket.hxx" -#include "SocketUtil.hxx" -#include "SocketError.hxx" +#include "system/SocketUtil.hxx" +#include "system/SocketError.hxx" #include "event/SocketMonitor.hxx" -#include "resolver.h" -#include "fd_util.h" +#include "system/resolver.h" +#include "system/fd_util.h" #include #include diff --git a/src/event/SocketMonitor.cxx b/src/event/SocketMonitor.cxx index 6efa69647..92aac9a92 100644 --- a/src/event/SocketMonitor.cxx +++ b/src/event/SocketMonitor.cxx @@ -20,7 +20,7 @@ #include "config.h" #include "SocketMonitor.hxx" #include "Loop.hxx" -#include "fd_util.h" +#include "system/fd_util.h" #include "gcc.h" #include diff --git a/src/fd_util.c b/src/fd_util.c deleted file mode 100644 index 17976a5ee..000000000 --- a/src/fd_util.c +++ /dev/null @@ -1,353 +0,0 @@ -/* - * Copyright (C) 2003-2011 The Music Player Daemon Project - * http://www.musicpd.org - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" /* must be first for large file support */ -#include "fd_util.h" - -#if !defined(_GNU_SOURCE) && (defined(HAVE_PIPE2) || defined(HAVE_ACCEPT4)) -#define _GNU_SOURCE -#endif - -#include -#include -#include -#include - -#ifdef WIN32 -#include -#include -#else -#include -#endif - -#ifdef HAVE_INOTIFY_INIT -#include -#endif - -#ifdef USE_EVENTFD -#include -#endif - -#ifndef WIN32 - -static int -fd_mask_flags(int fd, int and_mask, int xor_mask) -{ - int ret; - - assert(fd >= 0); - - ret = fcntl(fd, F_GETFD, 0); - if (ret < 0) - return ret; - - return fcntl(fd, F_SETFD, (ret & and_mask) ^ xor_mask); -} - -#endif /* !WIN32 */ - -static int -fd_set_cloexec(int fd, bool enable) -{ -#ifndef WIN32 - return fd_mask_flags(fd, ~FD_CLOEXEC, enable ? FD_CLOEXEC : 0); -#else - (void)fd; - (void)enable; - - return 0; -#endif -} - -/** - * Enables non-blocking mode for the specified file descriptor. On - * WIN32, this function only works for sockets. - */ -static int -fd_set_nonblock(int fd) -{ -#ifdef WIN32 - u_long val = 1; - return ioctlsocket(fd, FIONBIO, &val); -#else - int flags; - - assert(fd >= 0); - - flags = fcntl(fd, F_GETFL); - if (flags < 0) - return flags; - - return fcntl(fd, F_SETFL, flags | O_NONBLOCK); -#endif -} - -int -dup_cloexec(int oldfd) -{ - int newfd = dup(oldfd); - if (newfd >= 0) - fd_set_nonblock(newfd); - - return newfd; -} - -int -open_cloexec(const char *path_fs, int flags, int mode) -{ - int fd; - -#ifdef O_CLOEXEC - flags |= O_CLOEXEC; -#endif - -#ifdef O_NOCTTY - flags |= O_NOCTTY; -#endif - - fd = open(path_fs, flags, mode); - if (fd >= 0) - fd_set_cloexec(fd, true); - - return fd; -} - -int -pipe_cloexec(int fd[2]) -{ -#ifdef WIN32 - return _pipe(fd, 512, _O_BINARY); -#else - int ret; - -#ifdef HAVE_PIPE2 - ret = pipe2(fd, O_CLOEXEC); - if (ret >= 0 || errno != ENOSYS) - return ret; -#endif - - ret = pipe(fd); - if (ret >= 0) { - fd_set_cloexec(fd[0], true); - fd_set_cloexec(fd[1], true); - } - - return ret; -#endif -} - -int -pipe_cloexec_nonblock(int fd[2]) -{ -#ifdef WIN32 - return _pipe(fd, 512, _O_BINARY); -#else - int ret; - -#ifdef HAVE_PIPE2 - ret = pipe2(fd, O_CLOEXEC|O_NONBLOCK); - if (ret >= 0 || errno != ENOSYS) - return ret; -#endif - - ret = pipe(fd); - if (ret >= 0) { - fd_set_cloexec(fd[0], true); - fd_set_cloexec(fd[1], true); - - fd_set_nonblock(fd[0]); - fd_set_nonblock(fd[1]); - } - - return ret; -#endif -} - -#ifndef WIN32 - -int -socketpair_cloexec(int domain, int type, int protocol, int sv[2]) -{ - int ret; - -#ifdef SOCK_CLOEXEC - ret = socketpair(domain, type | SOCK_CLOEXEC, protocol, sv); - if (ret >= 0 || errno != EINVAL) - return ret; -#endif - - ret = socketpair(domain, type, protocol, sv); - if (ret >= 0) { - fd_set_cloexec(sv[0], true); - fd_set_cloexec(sv[1], true); - } - - return ret; -} - -int -socketpair_cloexec_nonblock(int domain, int type, int protocol, int sv[2]) -{ - int ret; - -#if defined(SOCK_CLOEXEC) && defined(SOCK_NONBLOCK) - ret = socketpair(domain, type | SOCK_CLOEXEC | SOCK_NONBLOCK, protocol, - sv); - if (ret >= 0 || errno != EINVAL) - return ret; -#endif - - ret = socketpair(domain, type, protocol, sv); - if (ret >= 0) { - fd_set_cloexec(sv[0], true); - fd_set_nonblock(sv[0]); - fd_set_cloexec(sv[1], true); - fd_set_nonblock(sv[1]); - } - - return ret; -} - -#endif - -int -socket_cloexec_nonblock(int domain, int type, int protocol) -{ - int fd; - -#if defined(SOCK_CLOEXEC) && defined(SOCK_NONBLOCK) - fd = socket(domain, type | SOCK_CLOEXEC | SOCK_NONBLOCK, protocol); - if (fd >= 0 || errno != EINVAL) - return fd; -#endif - - fd = socket(domain, type, protocol); - if (fd >= 0) { - fd_set_cloexec(fd, true); - fd_set_nonblock(fd); - } - - return fd; -} - -int -accept_cloexec_nonblock(int fd, struct sockaddr *address, - size_t *address_length_r) -{ - int ret; - socklen_t address_length = *address_length_r; - -#ifdef HAVE_ACCEPT4 - ret = accept4(fd, address, &address_length, - SOCK_CLOEXEC|SOCK_NONBLOCK); - if (ret >= 0 || errno != ENOSYS) { - if (ret >= 0) - *address_length_r = address_length; - - return ret; - } -#endif - - ret = accept(fd, address, &address_length); - if (ret >= 0) { - fd_set_cloexec(ret, true); - fd_set_nonblock(ret); - *address_length_r = address_length; - } - - return ret; -} - -#ifndef WIN32 - -ssize_t -recvmsg_cloexec(int sockfd, struct msghdr *msg, int flags) -{ -#ifdef MSG_CMSG_CLOEXEC - flags |= MSG_CMSG_CLOEXEC; -#endif - - ssize_t result = recvmsg(sockfd, msg, flags); - if (result >= 0) { - struct cmsghdr *cmsg = CMSG_FIRSTHDR(msg); - while (cmsg != NULL) { - if (cmsg->cmsg_type == SCM_RIGHTS) { - const int *fd_p = (const int *)CMSG_DATA(cmsg); - fd_set_cloexec(*fd_p, true); - } - - cmsg = CMSG_NXTHDR(msg, cmsg); - } - } - - return result; -} - -#endif - -#ifdef HAVE_INOTIFY_INIT - -int -inotify_init_cloexec(void) -{ - int fd; - -#ifdef HAVE_INOTIFY_INIT1 - fd = inotify_init1(IN_CLOEXEC); - if (fd >= 0 || errno != ENOSYS) - return fd; -#endif - - fd = inotify_init(); - if (fd >= 0) - fd_set_cloexec(fd, true); - - return fd; -} - -#endif - -#ifdef USE_EVENTFD - -int -eventfd_cloexec_nonblock(unsigned initval, int flags) -{ - return eventfd(initval, flags | EFD_CLOEXEC | EFD_NONBLOCK); -} - -#endif - -int -close_socket(int fd) -{ -#ifdef WIN32 - return closesocket(fd); -#else - return close(fd); -#endif -} diff --git a/src/fd_util.h b/src/fd_util.h deleted file mode 100644 index 9003b1616..000000000 --- a/src/fd_util.h +++ /dev/null @@ -1,168 +0,0 @@ -/* - * Copyright (C) 2003-2011 The Music Player Daemon Project - * http://www.musicpd.org - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * This library provides easy helper functions for working with file - * descriptors. It has wrappers for taking advantage of Linux 2.6 - * specific features like O_CLOEXEC. - * - */ - -#ifndef FD_UTIL_H -#define FD_UTIL_H - -#include "check.h" - -#include -#include - -#ifndef WIN32 -#if !defined(_GNU_SOURCE) && (defined(HAVE_PIPE2) || defined(HAVE_ACCEPT4)) -#define _GNU_SOURCE -#endif - -#include -#endif - -struct sockaddr; - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * Wrapper for dup(), which sets the CLOEXEC flag on the new - * descriptor. - */ -int -dup_cloexec(int oldfd); - -/** - * Wrapper for open(), which sets the CLOEXEC flag (atomically if - * supported by the OS). - */ -int -open_cloexec(const char *path_fs, int flags, int mode); - -/** - * Wrapper for pipe(), which sets the CLOEXEC flag (atomically if - * supported by the OS). - */ -int -pipe_cloexec(int fd[2]); - -/** - * Wrapper for pipe(), which sets the CLOEXEC flag (atomically if - * supported by the OS). - * - * On systems that supports it (everybody except for Windows), it also - * sets the NONBLOCK flag. - */ -int -pipe_cloexec_nonblock(int fd[2]); - -#ifndef WIN32 - -/** - * Wrapper for socketpair(), which sets the CLOEXEC flag (atomically - * if supported by the OS). - */ -int -socketpair_cloexec(int domain, int type, int protocol, int sv[2]); - -/** - * Wrapper for socketpair(), which sets the flags CLOEXEC and NONBLOCK - * (atomically if supported by the OS). - */ -int -socketpair_cloexec_nonblock(int domain, int type, int protocol, int sv[2]); - -#endif - -/** - * Wrapper for socket(), which sets the CLOEXEC and the NONBLOCK flag - * (atomically if supported by the OS). - */ -int -socket_cloexec_nonblock(int domain, int type, int protocol); - -/** - * Wrapper for accept(), which sets the CLOEXEC and the NONBLOCK flags - * (atomically if supported by the OS). - */ -int -accept_cloexec_nonblock(int fd, struct sockaddr *address, - size_t *address_length_r); - - -#ifndef WIN32 - -struct msghdr; - -/** - * Wrapper for recvmsg(), which sets the CLOEXEC flag (atomically if - * supported by the OS). - */ -ssize_t -recvmsg_cloexec(int sockfd, struct msghdr *msg, int flags); - -#endif - -#ifdef HAVE_INOTIFY_INIT - -/** - * Wrapper for inotify_init(), which sets the CLOEXEC flag (atomically - * if supported by the OS). - */ -int -inotify_init_cloexec(void); - -#endif - -#ifdef USE_EVENTFD - -/** - * Wrapper for eventfd() which sets the flags CLOEXEC and NONBLOCK - * flag (atomically if supported by the OS). - */ -int -eventfd_cloexec_nonblock(unsigned initval, int flags); - -#endif - -/** - * Portable wrapper for close(); use closesocket() on WIN32/WinSock. - */ -int -close_socket(int fd); - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif diff --git a/src/fs/FileSystem.hxx b/src/fs/FileSystem.hxx index 2e1701c87..4df415e0a 100644 --- a/src/fs/FileSystem.hxx +++ b/src/fs/FileSystem.hxx @@ -21,7 +21,7 @@ #define MPD_FS_FILESYSTEM_HXX #include "check.h" -#include "fd_util.h" +#include "system/fd_util.h" #include "Path.hxx" diff --git a/src/input/FileInputPlugin.cxx b/src/input/FileInputPlugin.cxx index 2eecf32b6..6fd743179 100644 --- a/src/input/FileInputPlugin.cxx +++ b/src/input/FileInputPlugin.cxx @@ -22,7 +22,7 @@ #include "InputInternal.hxx" #include "InputStream.hxx" #include "InputPlugin.hxx" -#include "fd_util.h" +#include "system/fd_util.h" #include "open.h" #include "io_error.h" diff --git a/src/mixer/OssMixerPlugin.cxx b/src/mixer/OssMixerPlugin.cxx index d8af6dff0..231f38432 100644 --- a/src/mixer/OssMixerPlugin.cxx +++ b/src/mixer/OssMixerPlugin.cxx @@ -20,7 +20,7 @@ #include "config.h" #include "MixerInternal.hxx" #include "OutputAPI.hxx" -#include "fd_util.h" +#include "system/fd_util.h" #include diff --git a/src/output/FifoOutputPlugin.cxx b/src/output/FifoOutputPlugin.cxx index a3c76aa4d..4d1b56e69 100644 --- a/src/output/FifoOutputPlugin.cxx +++ b/src/output/FifoOutputPlugin.cxx @@ -21,7 +21,7 @@ #include "FifoOutputPlugin.hxx" #include "OutputAPI.hxx" #include "Timer.hxx" -#include "fd_util.h" +#include "system/fd_util.h" #include "open.h" #include diff --git a/src/output/HttpdClient.cxx b/src/output/HttpdClient.cxx index 0a00ee2f9..c097e48f1 100644 --- a/src/output/HttpdClient.cxx +++ b/src/output/HttpdClient.cxx @@ -23,7 +23,7 @@ #include "util/fifo_buffer.h" #include "Page.hxx" #include "IcyMetaDataServer.hxx" -#include "SocketError.hxx" +#include "system/SocketError.hxx" #include #include diff --git a/src/output/HttpdOutputPlugin.cxx b/src/output/HttpdOutputPlugin.cxx index 4169aabfa..fbf25ca00 100644 --- a/src/output/HttpdOutputPlugin.cxx +++ b/src/output/HttpdOutputPlugin.cxx @@ -24,10 +24,10 @@ #include "OutputAPI.hxx" #include "EncoderPlugin.hxx" #include "EncoderList.hxx" -#include "resolver.h" +#include "system/resolver.h" #include "Page.hxx" #include "IcyMetaDataServer.hxx" -#include "fd_util.h" +#include "system/fd_util.h" #include "Main.hxx" #include diff --git a/src/output/OssOutputPlugin.cxx b/src/output/OssOutputPlugin.cxx index 6362a374f..b31db6c43 100644 --- a/src/output/OssOutputPlugin.cxx +++ b/src/output/OssOutputPlugin.cxx @@ -21,7 +21,7 @@ #include "OssOutputPlugin.hxx" #include "OutputAPI.hxx" #include "MixerList.hxx" -#include "fd_util.h" +#include "system/fd_util.h" #include diff --git a/src/output/RecorderOutputPlugin.cxx b/src/output/RecorderOutputPlugin.cxx index afae17e84..9374e4c20 100644 --- a/src/output/RecorderOutputPlugin.cxx +++ b/src/output/RecorderOutputPlugin.cxx @@ -22,7 +22,7 @@ #include "OutputAPI.hxx" #include "EncoderPlugin.hxx" #include "EncoderList.hxx" -#include "fd_util.h" +#include "system/fd_util.h" #include "open.h" #include diff --git a/src/output/SolarisOutputPlugin.cxx b/src/output/SolarisOutputPlugin.cxx index 074eae728..aa2f853e6 100644 --- a/src/output/SolarisOutputPlugin.cxx +++ b/src/output/SolarisOutputPlugin.cxx @@ -20,7 +20,7 @@ #include "config.h" #include "SolarisOutputPlugin.hxx" #include "OutputAPI.hxx" -#include "fd_util.h" +#include "system/fd_util.h" #include diff --git a/src/resolver.c b/src/resolver.c deleted file mode 100644 index 243b7cd02..000000000 --- a/src/resolver.c +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Copyright (C) 2003-2011 The Music Player Daemon Project - * 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" -#include "resolver.h" - -#ifndef G_OS_WIN32 -#include -#include -#else /* G_OS_WIN32 */ -#include -#include -#endif /* G_OS_WIN32 */ - -#include - -char * -sockaddr_to_string(const struct sockaddr *sa, size_t length, GError **error) -{ -#if defined(HAVE_IPV6) && defined(IN6_IS_ADDR_V4MAPPED) - const struct sockaddr_in6 *a6 = (const struct sockaddr_in6 *)sa; - struct sockaddr_in a4; -#endif - int ret; - char host[NI_MAXHOST], serv[NI_MAXSERV]; - -#if defined(HAVE_IPV6) && defined(IN6_IS_ADDR_V4MAPPED) - if (sa->sa_family == AF_INET6 && - IN6_IS_ADDR_V4MAPPED(&a6->sin6_addr)) { - /* convert "::ffff:127.0.0.1" to "127.0.0.1" */ - - memset(&a4, 0, sizeof(a4)); - a4.sin_family = AF_INET; - memcpy(&a4.sin_addr, ((const char *)&a6->sin6_addr) + 12, - sizeof(a4.sin_addr)); - a4.sin_port = a6->sin6_port; - - sa = (const struct sockaddr *)&a4; - length = sizeof(a4); - } -#endif - - ret = getnameinfo(sa, length, host, sizeof(host), serv, sizeof(serv), - NI_NUMERICHOST|NI_NUMERICSERV); - if (ret != 0) { - g_set_error(error, g_quark_from_static_string("netdb"), ret, - "%s", gai_strerror(ret)); - return NULL; - } - -#ifdef HAVE_UN - if (sa->sa_family == AF_UNIX) - /* "serv" contains corrupt information with unix - sockets */ - return g_strdup(host); -#endif - -#ifdef HAVE_IPV6 - if (strchr(host, ':') != NULL) - return g_strconcat("[", host, "]:", serv, NULL); -#endif - - return g_strconcat(host, ":", serv, NULL); -} - -struct addrinfo * -resolve_host_port(const char *host_port, unsigned default_port, - int flags, int socktype, - GError **error_r) -{ - char *p = g_strdup(host_port); - const char *host = p, *port = NULL; - - if (host_port[0] == '[') { - /* IPv6 needs enclosing square braces, to - differentiate between IP colons and the port - separator */ - - char *q = strchr(p + 1, ']'); - if (q != NULL && q[1] == ':' && q[2] != 0) { - *q = 0; - ++host; - port = q + 2; - } - } - - if (port == NULL) { - /* port is after the colon, but only if it's the only - colon (don't split IPv6 addresses) */ - - char *q = strchr(p, ':'); - if (q != NULL && q[1] != 0 && strchr(q + 1, ':') == NULL) { - *q = 0; - port = q + 1; - } - } - - char buffer[32]; - if (port == NULL && default_port != 0) { - g_snprintf(buffer, sizeof(buffer), "%u", default_port); - port = buffer; - } - - if ((flags & AI_PASSIVE) != 0 && strcmp(host, "*") == 0) - host = NULL; - - const struct addrinfo hints = { - .ai_flags = flags, - .ai_family = AF_UNSPEC, - .ai_socktype = socktype, - }; - - struct addrinfo *ai; - int ret = getaddrinfo(host, port, &hints, &ai); - g_free(p); - if (ret != 0) { - g_set_error(error_r, resolver_quark(), ret, - "Failed to look up '%s': %s", - host_port, gai_strerror(ret)); - return NULL; - } - - return ai; -} diff --git a/src/resolver.h b/src/resolver.h deleted file mode 100644 index af14f5f23..000000000 --- a/src/resolver.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (C) 2003-2011 The Music Player Daemon Project - * 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. - */ - -#ifndef MPD_RESOLVER_H -#define MPD_RESOLVER_H - -#include "gcc.h" - -#include - -struct sockaddr; -struct addrinfo; - -gcc_const -static inline GQuark -resolver_quark(void) -{ - return g_quark_from_static_string("resolver"); -} - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * Converts the specified socket address into a string in the form - * "IP:PORT". The return value must be freed with g_free() when you - * don't need it anymore. - * - * @param sa the sockaddr struct - * @param length the length of #sa in bytes - * @param error location to store the error occurring, or NULL to - * ignore errors - */ -gcc_malloc -char * -sockaddr_to_string(const struct sockaddr *sa, size_t length, GError **error); - -/** - * Resolve a specification in the form "host", "host:port", - * "[host]:port". This is a convenience wrapper for getaddrinfo(). - * - * @param default_port a default port number that will be used if none - * is given in the string (if applicable); pass 0 to go without a - * default - * @return an #addrinfo linked list that must be freed with - * freeaddrinfo(), or NULL on error - */ -struct addrinfo * -resolve_host_port(const char *host_port, unsigned default_port, - int flags, int socktype, - GError **error_r); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/system/FatalError.cxx b/src/system/FatalError.cxx new file mode 100644 index 000000000..30ddc50ea --- /dev/null +++ b/src/system/FatalError.cxx @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2003-2013 The Music Player Daemon Project + * 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 "FatalError.hxx" + +#include + +#include +#include +#include + +#ifdef WIN32 +#include +#else +#include +#endif + +#undef G_LOG_DOMAIN +#define G_LOG_DOMAIN "FatalError" + +void +FatalError(const char *msg) +{ + g_critical("%s", msg); + exit(EXIT_FAILURE); +} + +void +FormatFatalError(const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + g_logv(G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, fmt, ap); + va_end(ap); + + exit(EXIT_FAILURE); +} + +void +FatalError(GError *error) +{ + FatalError(error->message); +} + +void +FatalError(const char *msg, GError *error) +{ + FormatFatalError("%s: %s", msg, error->message); +} + +void +FatalSystemError(const char *msg) +{ + const char *system_error; +#ifdef WIN32 + system_error = g_win32_error_message(GetLastError()); +#else + system_error = g_strerror(errno); +#endif + + g_critical("%s: %s", msg, system_error); + exit(EXIT_FAILURE); +} + +void +FormatFatalSystemError(const char *fmt, ...) +{ + char buffer[1024]; + va_list ap; + va_start(ap, fmt); + vsnprintf(buffer, sizeof(buffer), fmt, ap); + va_end(ap); + + FatalSystemError(buffer); +} diff --git a/src/system/FatalError.hxx b/src/system/FatalError.hxx new file mode 100644 index 000000000..3918e5fc1 --- /dev/null +++ b/src/system/FatalError.hxx @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2003-2013 The Music Player Daemon Project + * 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. + */ + +#ifndef MPD_FATAL_ERROR_HXX +#define MPD_FATAL_ERROR_HXX + +#include "gerror.h" +#include "gcc.h" + +/** + * Log the specified message and abort the process. + */ +gcc_noreturn +void +FatalError(const char *msg); + +gcc_noreturn +void +FormatFatalError(const char *fmt, ...); + +gcc_noreturn +void +FatalError(GError *error); + +gcc_noreturn +void +FatalError(const char *msg, GError *error); + +/** + * Call this after a system call has failed that is not supposed to + * fail. Prints the given message, the system error message (from + * errno or GetLastError()) and abort the process. + */ +gcc_noreturn +void +FatalSystemError(const char *msg); + +gcc_noreturn +void +FormatFatalSystemError(const char *fmt, ...); + +#endif diff --git a/src/system/SocketError.hxx b/src/system/SocketError.hxx new file mode 100644 index 000000000..53a0c1d8f --- /dev/null +++ b/src/system/SocketError.hxx @@ -0,0 +1,156 @@ +/* + * Copyright (C) 2003-2013 The Music Player Daemon Project + * 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. + */ + +#ifndef MPD_SOCKET_ERROR_HXX +#define MPD_SOCKET_ERROR_HXX + +#include "gcc.h" + +#include + +#ifdef WIN32 +#include +typedef DWORD socket_error_t; +#else +#include +typedef int socket_error_t; +#endif + +/** + * A GQuark for GError for socket I/O errors. The code is an errno + * value (or WSAGetLastError() on Windows). + */ +gcc_const +static inline GQuark +SocketErrorQuark(void) +{ + return g_quark_from_static_string("socket"); +} + +gcc_pure +static inline socket_error_t +GetSocketError() +{ +#ifdef WIN32 + return WSAGetLastError(); +#else + return errno; +#endif +} + +gcc_const +static inline bool +IsSocketErrorAgain(socket_error_t code) +{ +#ifdef WIN32 + return code == WSAEINPROGRESS; +#else + return code == EAGAIN; +#endif +} + +gcc_const +static inline bool +IsSocketErrorInterruped(socket_error_t code) +{ +#ifdef WIN32 + return code == WSAEINTR; +#else + return code == EINTR; +#endif +} + +gcc_const +static inline bool +IsSocketErrorClosed(socket_error_t code) +{ +#ifdef WIN32 + return code == WSAECONNRESET; +#else + return code == EPIPE || code == ECONNRESET; +#endif +} + +/** + * Helper class that formats a socket error message into a + * human-readable string. On Windows, a buffer is necessary for this, + * and this class hosts the buffer. + */ +class SocketErrorMessage { +#ifdef WIN32 + char msg[256]; +#else + const char *const msg; +#endif + +public: +#ifdef WIN32 + explicit SocketErrorMessage(socket_error_t code=GetSocketError()) { + DWORD nbytes = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS | + FORMAT_MESSAGE_MAX_WIDTH_MASK, + NULL, code, 0, + (LPSTR)msg, sizeof(msg), NULL); + if (nbytes == 0) + strcpy(msg, "Unknown error"); + } +#else + explicit SocketErrorMessage(socket_error_t code=GetSocketError()) + :msg(g_strerror(code)) {} +#endif + + operator const char *() const { + return msg; + } +}; + +static inline void +SetSocketError(GError **error_r, socket_error_t code) +{ +#ifdef WIN32 + if (error_r == NULL) + return; +#endif + + const SocketErrorMessage msg(code); + g_set_error_literal(error_r, SocketErrorQuark(), code, msg); +} + +static inline void +SetSocketError(GError **error_r) +{ + SetSocketError(error_r, GetSocketError()); +} + +gcc_malloc +static inline GError * +NewSocketError(socket_error_t code) +{ + const SocketErrorMessage msg(code); + return g_error_new_literal(SocketErrorQuark(), code, msg); +} + +gcc_malloc +static inline GError * +NewSocketError() +{ + return NewSocketError(GetSocketError()); +} + +#endif diff --git a/src/system/SocketUtil.cxx b/src/system/SocketUtil.cxx new file mode 100644 index 000000000..dd7eb7dd2 --- /dev/null +++ b/src/system/SocketUtil.cxx @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2003-2013 The Music Player Daemon Project + * 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" +#include "SocketUtil.hxx" +#include "SocketError.hxx" +#include "fd_util.h" + +#include + +#include + +#ifndef G_OS_WIN32 +#include +#else /* G_OS_WIN32 */ +#include +#include +#endif /* G_OS_WIN32 */ + +#ifdef HAVE_IPV6 +#include +#endif + +int +socket_bind_listen(int domain, int type, int protocol, + const struct sockaddr *address, size_t address_length, + int backlog, + GError **error_r) +{ + int fd, ret; + const int reuse = 1; + + fd = socket_cloexec_nonblock(domain, type, protocol); + if (fd < 0) { + SetSocketError(error_r); + g_prefix_error(error_r, "Failed to create socket: "); + return -1; + } + + ret = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, + (const char *) &reuse, sizeof(reuse)); + if (ret < 0) { + SetSocketError(error_r); + g_prefix_error(error_r, "setsockopt() failed: "); + close_socket(fd); + return -1; + } + + ret = bind(fd, address, address_length); + if (ret < 0) { + SetSocketError(error_r); + close_socket(fd); + return -1; + } + + ret = listen(fd, backlog); + if (ret < 0) { + SetSocketError(error_r); + g_prefix_error(error_r, "listen() failed: "); + close_socket(fd); + return -1; + } + +#ifdef HAVE_STRUCT_UCRED + setsockopt(fd, SOL_SOCKET, SO_PASSCRED, + (const char *) &reuse, sizeof(reuse)); +#endif + + return fd; +} + +int +socket_keepalive(int fd) +{ + const int reuse = 1; + + return setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, + (const char *)&reuse, sizeof(reuse)); +} diff --git a/src/system/SocketUtil.hxx b/src/system/SocketUtil.hxx new file mode 100644 index 000000000..3d0be78c4 --- /dev/null +++ b/src/system/SocketUtil.hxx @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2003-2013 The Music Player Daemon Project + * 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. + */ + +/* + * This library provides easy helper functions for working with + * sockets. + * + */ + +#ifndef MPD_SOCKET_UTIL_HXX +#define MPD_SOCKET_UTIL_HXX + +#include "gerror.h" + +#include + +struct sockaddr; + +/** + * Creates a socket listening on the specified address. This is a + * shortcut for socket(), bind() and listen(). + * + * @param domain the socket domain, e.g. PF_INET6 + * @param type the socket type, e.g. SOCK_STREAM + * @param protocol the protocol, usually 0 to let the kernel choose + * @param address the address to listen on + * @param address_length the size of #address + * @param backlog the backlog parameter for the listen() system call + * @param error location to store the error occurring, or NULL to + * ignore errors + * @return the socket file descriptor or -1 on error + */ +int +socket_bind_listen(int domain, int type, int protocol, + const struct sockaddr *address, size_t address_length, + int backlog, + GError **error); + +int +socket_keepalive(int fd); + +#endif diff --git a/src/system/clock.c b/src/system/clock.c new file mode 100644 index 000000000..d987aed48 --- /dev/null +++ b/src/system/clock.c @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2003-2012 The Music Player Daemon Project + * 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 "clock.h" + +#ifdef WIN32 +#include +#elif defined(__APPLE__) +#include +#else +#include +#ifndef CLOCK_MONOTONIC +#include +#endif +#endif + +unsigned +monotonic_clock_ms(void) +{ +#ifdef WIN32 + return GetTickCount(); +#elif defined(__APPLE__) /* OS X does not define CLOCK_MONOTONIC */ + static mach_timebase_info_data_t base; + if (base.denom == 0) + (void)mach_timebase_info(&base); + + return (unsigned)((mach_absolute_time() * base.numer) + / (1000000 * base.denom)); +#elif defined(CLOCK_MONOTONIC) + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + return ts.tv_sec * 1000 + ts.tv_nsec / 1000000; +#else + /* we have no monotonic clock, fall back to gettimeofday() */ + struct timeval tv; + gettimeofday(&tv, 0); + return tv.tv_sec * 1000 + tv.tv_usec / 1000; +#endif +} + +uint64_t +monotonic_clock_us(void) +{ +#ifdef WIN32 + LARGE_INTEGER l_value, l_frequency; + + if (!QueryPerformanceCounter(&l_value) || + !QueryPerformanceFrequency(&l_frequency)) + return 0; + + uint64_t value = l_value.QuadPart; + uint64_t frequency = l_frequency.QuadPart; + + if (frequency > 1000000) { + value *= 10000; + value /= frequency / 100; + } else if (frequency < 1000000) { + value *= 10000; + value /= frequency; + value *= 100; + } + + return value; +#elif defined(__APPLE__) /* OS X does not define CLOCK_MONOTONIC */ + static mach_timebase_info_data_t base; + if (base.denom == 0) + (void)mach_timebase_info(&base); + + return ((uint64_t)mach_absolute_time() * (uint64_t)base.numer) + / (1000 * (uint64_t)base.denom); +#elif defined(CLOCK_MONOTONIC) + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + return (uint64_t)ts.tv_sec * 1000000 + (uint64_t)(ts.tv_nsec / 1000); +#else + /* we have no monotonic clock, fall back to gettimeofday() */ + struct timeval tv; + gettimeofday(&tv, 0); + return (uint64_t)tv.tv_sec * 1000 + (uint64_t)tv.tv_usec; +#endif +} + diff --git a/src/system/clock.h b/src/system/clock.h new file mode 100644 index 000000000..c98b9a652 --- /dev/null +++ b/src/system/clock.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2003-2012 The Music Player Daemon Project + * 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. + */ + +#ifndef MPD_CLOCK_H +#define MPD_CLOCK_H + +#include "gcc.h" + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Returns the value of a monotonic clock in milliseconds. + */ +gcc_pure +unsigned +monotonic_clock_ms(void); + +/** + * Returns the value of a monotonic clock in microseconds. + */ +gcc_pure +uint64_t +monotonic_clock_us(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/system/fd_util.c b/src/system/fd_util.c new file mode 100644 index 000000000..17976a5ee --- /dev/null +++ b/src/system/fd_util.c @@ -0,0 +1,353 @@ +/* + * Copyright (C) 2003-2011 The Music Player Daemon Project + * http://www.musicpd.org + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" /* must be first for large file support */ +#include "fd_util.h" + +#if !defined(_GNU_SOURCE) && (defined(HAVE_PIPE2) || defined(HAVE_ACCEPT4)) +#define _GNU_SOURCE +#endif + +#include +#include +#include +#include + +#ifdef WIN32 +#include +#include +#else +#include +#endif + +#ifdef HAVE_INOTIFY_INIT +#include +#endif + +#ifdef USE_EVENTFD +#include +#endif + +#ifndef WIN32 + +static int +fd_mask_flags(int fd, int and_mask, int xor_mask) +{ + int ret; + + assert(fd >= 0); + + ret = fcntl(fd, F_GETFD, 0); + if (ret < 0) + return ret; + + return fcntl(fd, F_SETFD, (ret & and_mask) ^ xor_mask); +} + +#endif /* !WIN32 */ + +static int +fd_set_cloexec(int fd, bool enable) +{ +#ifndef WIN32 + return fd_mask_flags(fd, ~FD_CLOEXEC, enable ? FD_CLOEXEC : 0); +#else + (void)fd; + (void)enable; + + return 0; +#endif +} + +/** + * Enables non-blocking mode for the specified file descriptor. On + * WIN32, this function only works for sockets. + */ +static int +fd_set_nonblock(int fd) +{ +#ifdef WIN32 + u_long val = 1; + return ioctlsocket(fd, FIONBIO, &val); +#else + int flags; + + assert(fd >= 0); + + flags = fcntl(fd, F_GETFL); + if (flags < 0) + return flags; + + return fcntl(fd, F_SETFL, flags | O_NONBLOCK); +#endif +} + +int +dup_cloexec(int oldfd) +{ + int newfd = dup(oldfd); + if (newfd >= 0) + fd_set_nonblock(newfd); + + return newfd; +} + +int +open_cloexec(const char *path_fs, int flags, int mode) +{ + int fd; + +#ifdef O_CLOEXEC + flags |= O_CLOEXEC; +#endif + +#ifdef O_NOCTTY + flags |= O_NOCTTY; +#endif + + fd = open(path_fs, flags, mode); + if (fd >= 0) + fd_set_cloexec(fd, true); + + return fd; +} + +int +pipe_cloexec(int fd[2]) +{ +#ifdef WIN32 + return _pipe(fd, 512, _O_BINARY); +#else + int ret; + +#ifdef HAVE_PIPE2 + ret = pipe2(fd, O_CLOEXEC); + if (ret >= 0 || errno != ENOSYS) + return ret; +#endif + + ret = pipe(fd); + if (ret >= 0) { + fd_set_cloexec(fd[0], true); + fd_set_cloexec(fd[1], true); + } + + return ret; +#endif +} + +int +pipe_cloexec_nonblock(int fd[2]) +{ +#ifdef WIN32 + return _pipe(fd, 512, _O_BINARY); +#else + int ret; + +#ifdef HAVE_PIPE2 + ret = pipe2(fd, O_CLOEXEC|O_NONBLOCK); + if (ret >= 0 || errno != ENOSYS) + return ret; +#endif + + ret = pipe(fd); + if (ret >= 0) { + fd_set_cloexec(fd[0], true); + fd_set_cloexec(fd[1], true); + + fd_set_nonblock(fd[0]); + fd_set_nonblock(fd[1]); + } + + return ret; +#endif +} + +#ifndef WIN32 + +int +socketpair_cloexec(int domain, int type, int protocol, int sv[2]) +{ + int ret; + +#ifdef SOCK_CLOEXEC + ret = socketpair(domain, type | SOCK_CLOEXEC, protocol, sv); + if (ret >= 0 || errno != EINVAL) + return ret; +#endif + + ret = socketpair(domain, type, protocol, sv); + if (ret >= 0) { + fd_set_cloexec(sv[0], true); + fd_set_cloexec(sv[1], true); + } + + return ret; +} + +int +socketpair_cloexec_nonblock(int domain, int type, int protocol, int sv[2]) +{ + int ret; + +#if defined(SOCK_CLOEXEC) && defined(SOCK_NONBLOCK) + ret = socketpair(domain, type | SOCK_CLOEXEC | SOCK_NONBLOCK, protocol, + sv); + if (ret >= 0 || errno != EINVAL) + return ret; +#endif + + ret = socketpair(domain, type, protocol, sv); + if (ret >= 0) { + fd_set_cloexec(sv[0], true); + fd_set_nonblock(sv[0]); + fd_set_cloexec(sv[1], true); + fd_set_nonblock(sv[1]); + } + + return ret; +} + +#endif + +int +socket_cloexec_nonblock(int domain, int type, int protocol) +{ + int fd; + +#if defined(SOCK_CLOEXEC) && defined(SOCK_NONBLOCK) + fd = socket(domain, type | SOCK_CLOEXEC | SOCK_NONBLOCK, protocol); + if (fd >= 0 || errno != EINVAL) + return fd; +#endif + + fd = socket(domain, type, protocol); + if (fd >= 0) { + fd_set_cloexec(fd, true); + fd_set_nonblock(fd); + } + + return fd; +} + +int +accept_cloexec_nonblock(int fd, struct sockaddr *address, + size_t *address_length_r) +{ + int ret; + socklen_t address_length = *address_length_r; + +#ifdef HAVE_ACCEPT4 + ret = accept4(fd, address, &address_length, + SOCK_CLOEXEC|SOCK_NONBLOCK); + if (ret >= 0 || errno != ENOSYS) { + if (ret >= 0) + *address_length_r = address_length; + + return ret; + } +#endif + + ret = accept(fd, address, &address_length); + if (ret >= 0) { + fd_set_cloexec(ret, true); + fd_set_nonblock(ret); + *address_length_r = address_length; + } + + return ret; +} + +#ifndef WIN32 + +ssize_t +recvmsg_cloexec(int sockfd, struct msghdr *msg, int flags) +{ +#ifdef MSG_CMSG_CLOEXEC + flags |= MSG_CMSG_CLOEXEC; +#endif + + ssize_t result = recvmsg(sockfd, msg, flags); + if (result >= 0) { + struct cmsghdr *cmsg = CMSG_FIRSTHDR(msg); + while (cmsg != NULL) { + if (cmsg->cmsg_type == SCM_RIGHTS) { + const int *fd_p = (const int *)CMSG_DATA(cmsg); + fd_set_cloexec(*fd_p, true); + } + + cmsg = CMSG_NXTHDR(msg, cmsg); + } + } + + return result; +} + +#endif + +#ifdef HAVE_INOTIFY_INIT + +int +inotify_init_cloexec(void) +{ + int fd; + +#ifdef HAVE_INOTIFY_INIT1 + fd = inotify_init1(IN_CLOEXEC); + if (fd >= 0 || errno != ENOSYS) + return fd; +#endif + + fd = inotify_init(); + if (fd >= 0) + fd_set_cloexec(fd, true); + + return fd; +} + +#endif + +#ifdef USE_EVENTFD + +int +eventfd_cloexec_nonblock(unsigned initval, int flags) +{ + return eventfd(initval, flags | EFD_CLOEXEC | EFD_NONBLOCK); +} + +#endif + +int +close_socket(int fd) +{ +#ifdef WIN32 + return closesocket(fd); +#else + return close(fd); +#endif +} diff --git a/src/system/fd_util.h b/src/system/fd_util.h new file mode 100644 index 000000000..9003b1616 --- /dev/null +++ b/src/system/fd_util.h @@ -0,0 +1,168 @@ +/* + * Copyright (C) 2003-2011 The Music Player Daemon Project + * http://www.musicpd.org + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * This library provides easy helper functions for working with file + * descriptors. It has wrappers for taking advantage of Linux 2.6 + * specific features like O_CLOEXEC. + * + */ + +#ifndef FD_UTIL_H +#define FD_UTIL_H + +#include "check.h" + +#include +#include + +#ifndef WIN32 +#if !defined(_GNU_SOURCE) && (defined(HAVE_PIPE2) || defined(HAVE_ACCEPT4)) +#define _GNU_SOURCE +#endif + +#include +#endif + +struct sockaddr; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Wrapper for dup(), which sets the CLOEXEC flag on the new + * descriptor. + */ +int +dup_cloexec(int oldfd); + +/** + * Wrapper for open(), which sets the CLOEXEC flag (atomically if + * supported by the OS). + */ +int +open_cloexec(const char *path_fs, int flags, int mode); + +/** + * Wrapper for pipe(), which sets the CLOEXEC flag (atomically if + * supported by the OS). + */ +int +pipe_cloexec(int fd[2]); + +/** + * Wrapper for pipe(), which sets the CLOEXEC flag (atomically if + * supported by the OS). + * + * On systems that supports it (everybody except for Windows), it also + * sets the NONBLOCK flag. + */ +int +pipe_cloexec_nonblock(int fd[2]); + +#ifndef WIN32 + +/** + * Wrapper for socketpair(), which sets the CLOEXEC flag (atomically + * if supported by the OS). + */ +int +socketpair_cloexec(int domain, int type, int protocol, int sv[2]); + +/** + * Wrapper for socketpair(), which sets the flags CLOEXEC and NONBLOCK + * (atomically if supported by the OS). + */ +int +socketpair_cloexec_nonblock(int domain, int type, int protocol, int sv[2]); + +#endif + +/** + * Wrapper for socket(), which sets the CLOEXEC and the NONBLOCK flag + * (atomically if supported by the OS). + */ +int +socket_cloexec_nonblock(int domain, int type, int protocol); + +/** + * Wrapper for accept(), which sets the CLOEXEC and the NONBLOCK flags + * (atomically if supported by the OS). + */ +int +accept_cloexec_nonblock(int fd, struct sockaddr *address, + size_t *address_length_r); + + +#ifndef WIN32 + +struct msghdr; + +/** + * Wrapper for recvmsg(), which sets the CLOEXEC flag (atomically if + * supported by the OS). + */ +ssize_t +recvmsg_cloexec(int sockfd, struct msghdr *msg, int flags); + +#endif + +#ifdef HAVE_INOTIFY_INIT + +/** + * Wrapper for inotify_init(), which sets the CLOEXEC flag (atomically + * if supported by the OS). + */ +int +inotify_init_cloexec(void); + +#endif + +#ifdef USE_EVENTFD + +/** + * Wrapper for eventfd() which sets the flags CLOEXEC and NONBLOCK + * flag (atomically if supported by the OS). + */ +int +eventfd_cloexec_nonblock(unsigned initval, int flags); + +#endif + +/** + * Portable wrapper for close(); use closesocket() on WIN32/WinSock. + */ +int +close_socket(int fd); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif diff --git a/src/system/resolver.c b/src/system/resolver.c new file mode 100644 index 000000000..243b7cd02 --- /dev/null +++ b/src/system/resolver.c @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2003-2011 The Music Player Daemon Project + * 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" +#include "resolver.h" + +#ifndef G_OS_WIN32 +#include +#include +#else /* G_OS_WIN32 */ +#include +#include +#endif /* G_OS_WIN32 */ + +#include + +char * +sockaddr_to_string(const struct sockaddr *sa, size_t length, GError **error) +{ +#if defined(HAVE_IPV6) && defined(IN6_IS_ADDR_V4MAPPED) + const struct sockaddr_in6 *a6 = (const struct sockaddr_in6 *)sa; + struct sockaddr_in a4; +#endif + int ret; + char host[NI_MAXHOST], serv[NI_MAXSERV]; + +#if defined(HAVE_IPV6) && defined(IN6_IS_ADDR_V4MAPPED) + if (sa->sa_family == AF_INET6 && + IN6_IS_ADDR_V4MAPPED(&a6->sin6_addr)) { + /* convert "::ffff:127.0.0.1" to "127.0.0.1" */ + + memset(&a4, 0, sizeof(a4)); + a4.sin_family = AF_INET; + memcpy(&a4.sin_addr, ((const char *)&a6->sin6_addr) + 12, + sizeof(a4.sin_addr)); + a4.sin_port = a6->sin6_port; + + sa = (const struct sockaddr *)&a4; + length = sizeof(a4); + } +#endif + + ret = getnameinfo(sa, length, host, sizeof(host), serv, sizeof(serv), + NI_NUMERICHOST|NI_NUMERICSERV); + if (ret != 0) { + g_set_error(error, g_quark_from_static_string("netdb"), ret, + "%s", gai_strerror(ret)); + return NULL; + } + +#ifdef HAVE_UN + if (sa->sa_family == AF_UNIX) + /* "serv" contains corrupt information with unix + sockets */ + return g_strdup(host); +#endif + +#ifdef HAVE_IPV6 + if (strchr(host, ':') != NULL) + return g_strconcat("[", host, "]:", serv, NULL); +#endif + + return g_strconcat(host, ":", serv, NULL); +} + +struct addrinfo * +resolve_host_port(const char *host_port, unsigned default_port, + int flags, int socktype, + GError **error_r) +{ + char *p = g_strdup(host_port); + const char *host = p, *port = NULL; + + if (host_port[0] == '[') { + /* IPv6 needs enclosing square braces, to + differentiate between IP colons and the port + separator */ + + char *q = strchr(p + 1, ']'); + if (q != NULL && q[1] == ':' && q[2] != 0) { + *q = 0; + ++host; + port = q + 2; + } + } + + if (port == NULL) { + /* port is after the colon, but only if it's the only + colon (don't split IPv6 addresses) */ + + char *q = strchr(p, ':'); + if (q != NULL && q[1] != 0 && strchr(q + 1, ':') == NULL) { + *q = 0; + port = q + 1; + } + } + + char buffer[32]; + if (port == NULL && default_port != 0) { + g_snprintf(buffer, sizeof(buffer), "%u", default_port); + port = buffer; + } + + if ((flags & AI_PASSIVE) != 0 && strcmp(host, "*") == 0) + host = NULL; + + const struct addrinfo hints = { + .ai_flags = flags, + .ai_family = AF_UNSPEC, + .ai_socktype = socktype, + }; + + struct addrinfo *ai; + int ret = getaddrinfo(host, port, &hints, &ai); + g_free(p); + if (ret != 0) { + g_set_error(error_r, resolver_quark(), ret, + "Failed to look up '%s': %s", + host_port, gai_strerror(ret)); + return NULL; + } + + return ai; +} diff --git a/src/system/resolver.h b/src/system/resolver.h new file mode 100644 index 000000000..af14f5f23 --- /dev/null +++ b/src/system/resolver.h @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2003-2011 The Music Player Daemon Project + * 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. + */ + +#ifndef MPD_RESOLVER_H +#define MPD_RESOLVER_H + +#include "gcc.h" + +#include + +struct sockaddr; +struct addrinfo; + +gcc_const +static inline GQuark +resolver_quark(void) +{ + return g_quark_from_static_string("resolver"); +} + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Converts the specified socket address into a string in the form + * "IP:PORT". The return value must be freed with g_free() when you + * don't need it anymore. + * + * @param sa the sockaddr struct + * @param length the length of #sa in bytes + * @param error location to store the error occurring, or NULL to + * ignore errors + */ +gcc_malloc +char * +sockaddr_to_string(const struct sockaddr *sa, size_t length, GError **error); + +/** + * Resolve a specification in the form "host", "host:port", + * "[host]:port". This is a convenience wrapper for getaddrinfo(). + * + * @param default_port a default port number that will be used if none + * is given in the string (if applicable); pass 0 to go without a + * default + * @return an #addrinfo linked list that must be freed with + * freeaddrinfo(), or NULL on error + */ +struct addrinfo * +resolve_host_port(const char *host_port, unsigned default_port, + int flags, int socktype, + GError **error_r); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/test/run_resolver.c b/test/run_resolver.c index ee0bc0172..87067ad23 100644 --- a/test/run_resolver.c +++ b/test/run_resolver.c @@ -18,7 +18,7 @@ */ #include "config.h" -#include "resolver.h" +#include "system/resolver.h" #ifdef WIN32 #include -- cgit v1.2.3