From 143c735f967f84325c56cb042cb5157e77739aa7 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Mon, 24 Nov 2014 22:08:28 +0100 Subject: configure.ac: prepare for 0.18.19 --- NEWS | 2 ++ configure.ac | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/NEWS b/NEWS index 21b44eec3..8a39a6504 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,5 @@ +ver 0.18.19 (not yet released) + ver 0.18.18 (2014/11/18) * decoder - ffmpeg: support opus diff --git a/configure.ac b/configure.ac index ca3d9b24f..2e0061954 100644 --- a/configure.ac +++ b/configure.ac @@ -1,10 +1,10 @@ AC_PREREQ(2.60) -AC_INIT(mpd, 0.18.18, mpd-devel@musicpd.org) +AC_INIT(mpd, 0.18.19, mpd-devel@musicpd.org) VERSION_MAJOR=0 VERSION_MINOR=18 -VERSION_REVISION=18 +VERSION_REVISION=19 VERSION_EXTRA=0 AC_CONFIG_SRCDIR([src/Main.cxx]) -- cgit v1.2.3 From a254f5a3a8396865cf05e27e0ab03345ee66783a Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Mon, 24 Nov 2014 22:08:11 +0100 Subject: archive/zzip: fix inverted error handler Set the Error when zzip_seek()==-1 and not on success. Fixes a crash after seeking. --- NEWS | 2 ++ src/archive/ZzipArchivePlugin.cxx | 9 +++++---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/NEWS b/NEWS index 8a39a6504..4699f6666 100644 --- a/NEWS +++ b/NEWS @@ -1,4 +1,6 @@ ver 0.18.19 (not yet released) +* archive + - zzip: fix crash after seeking ver 0.18.18 (2014/11/18) * decoder diff --git a/src/archive/ZzipArchivePlugin.cxx b/src/archive/ZzipArchivePlugin.cxx index 973fe91dc..d3e4cc837 100644 --- a/src/archive/ZzipArchivePlugin.cxx +++ b/src/archive/ZzipArchivePlugin.cxx @@ -186,12 +186,13 @@ zzip_input_seek(InputStream *is, InputPlugin::offset_type offset, { ZzipInputStream *zis = (ZzipInputStream *)is; zzip_off_t ofs = zzip_seek(zis->file, offset, whence); - if (ofs != -1) { + if (ofs < 0) { error.Set(zzip_domain, "zzip_seek() has failed"); - is->offset = ofs; - return true; + return false; } - return false; + + is->offset = ofs; + return true; } /* exported structures */ -- cgit v1.2.3 From b19e5720cc47a66cc59e55a81dc08de4e521bc39 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Tue, 25 Nov 2014 07:51:33 +0100 Subject: test/run_input: make variables more local --- test/run_input.cxx | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/test/run_input.cxx b/test/run_input.cxx index de5bd9632..6864a5d64 100644 --- a/test/run_input.cxx +++ b/test/run_input.cxx @@ -54,11 +54,6 @@ tag_save(FILE *file, const Tag &tag) static int dump_input_stream(InputStream *is) { - Error error; - char buffer[4096]; - size_t num_read; - ssize_t num_written; - is->Lock(); /* print meta data */ @@ -76,7 +71,9 @@ dump_input_stream(InputStream *is) delete tag; } - num_read = is->Read(buffer, sizeof(buffer), error); + Error error; + char buffer[4096]; + size_t num_read = is->Read(buffer, sizeof(buffer), error); if (num_read == 0) { if (error.IsDefined()) LogError(error); @@ -84,11 +81,12 @@ dump_input_stream(InputStream *is) break; } - num_written = write(1, buffer, num_read); + ssize_t num_written = write(1, buffer, num_read); if (num_written <= 0) break; } + Error error; if (!is->Check(error)) { LogError(error); is->Unlock(); @@ -102,10 +100,6 @@ dump_input_stream(InputStream *is) int main(int argc, char **argv) { - Error error; - InputStream *is; - int ret; - if (argc != 2) { fprintf(stderr, "Usage: run_input URI\n"); return EXIT_FAILURE; @@ -129,6 +123,7 @@ int main(int argc, char **argv) archive_plugin_init_all(); #endif + Error error; if (!input_stream_global_init(error)) { LogError(error); return 2; @@ -139,7 +134,8 @@ int main(int argc, char **argv) Mutex mutex; Cond cond; - is = InputStream::OpenReady(argv[1], mutex, cond, error); + InputStream *is = InputStream::OpenReady(argv[1], mutex, cond, error); + int ret; if (is != NULL) { ret = dump_input_stream(is); delete is; -- cgit v1.2.3 From a8ebfd7a92a48676d753e3ca3ee3175f6ff4d62e Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Tue, 25 Nov 2014 10:43:39 +0100 Subject: event/DeferredMonitor: include cleanup --- src/event/DeferredMonitor.hxx | 3 --- src/input/plugins/AlsaInputPlugin.cxx | 2 ++ 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/event/DeferredMonitor.hxx b/src/event/DeferredMonitor.hxx index 3d3ab22b7..c4aa605fc 100644 --- a/src/event/DeferredMonitor.hxx +++ b/src/event/DeferredMonitor.hxx @@ -21,9 +21,6 @@ #define MPD_SOCKET_DEFERRED_MONITOR_HXX #include "check.h" -#include "Compiler.h" - -#include class EventLoop; diff --git a/src/input/plugins/AlsaInputPlugin.cxx b/src/input/plugins/AlsaInputPlugin.cxx index 82b96f7df..f03f745c6 100644 --- a/src/input/plugins/AlsaInputPlugin.cxx +++ b/src/input/plugins/AlsaInputPlugin.cxx @@ -43,6 +43,8 @@ #include +#include + #include #include -- cgit v1.2.3 From fa4d202e71e2ff59583e088d9512424e32d3d761 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Mon, 24 Nov 2014 22:18:31 +0100 Subject: decoder/mp4v2: remove because of incompatible license libmp4v2 is licensed under MPL 1.1, which is incompatible with GPLv2. Unfortunately, this means that we must remove the plugin. More information can be found in the Debian bug report: http://bugs.debian.org/767504 --- INSTALL | 3 - Makefile.am | 8 - NEWS | 1 + configure.ac | 24 --- src/decoder/DecoderList.cxx | 4 - src/decoder/plugins/Mp4v2DecoderPlugin.cxx | 330 ----------------------------- src/decoder/plugins/Mp4v2DecoderPlugin.hxx | 25 --- 7 files changed, 1 insertion(+), 394 deletions(-) delete mode 100644 src/decoder/plugins/Mp4v2DecoderPlugin.cxx delete mode 100644 src/decoder/plugins/Mp4v2DecoderPlugin.hxx diff --git a/INSTALL b/INSTALL index 2a4a4c3c4..29a23d361 100644 --- a/INSTALL +++ b/INSTALL @@ -119,9 +119,6 @@ For AdLib playback. despotify - https://github.com/SimonKagstrom/despotify For Spotify playback. -MP4v2 - https://code.google.com/p/mp4v2/ -For MP4 playback. You will need FAAD2. - Optional Miscellaneous Dependencies ----------------------------------- diff --git a/Makefile.am b/Makefile.am index 72b6a0ca4..874e37d10 100644 --- a/Makefile.am +++ b/Makefile.am @@ -828,7 +828,6 @@ libdecoder_a_CPPFLAGS = $(AM_CPPFLAGS) \ $(WAVPACK_CFLAGS) \ $(MAD_CFLAGS) \ $(MPG123_CFLAGS) \ - $(MP4V2_CFLAGS) \ $(OPUS_CFLAGS) \ $(FFMPEG_CFLAGS) \ $(MPCDEC_CFLAGS) \ @@ -848,7 +847,6 @@ DECODER_LIBS = \ $(WAVPACK_LIBS) \ $(MAD_LIBS) \ $(MPG123_LIBS) \ - $(MP4V2_LIBS) \ $(OPUS_LIBS) \ $(FFMPEG_LIBS2) \ $(MPCDEC_LIBS) \ @@ -963,12 +961,6 @@ noinst_LIBRARIES += libmodplug_decoder_plugin.a DECODER_LIBS += libmodplug_decoder_plugin.a $(MODPLUG_LIBS) endif -if HAVE_MP4V2 -libdecoder_a_SOURCES += \ - src/decoder/plugins/Mp4v2DecoderPlugin.cxx \ - src/decoder/plugins/Mp4v2DecoderPlugin.hxx -endif - if ENABLE_SIDPLAY libdecoder_a_SOURCES += \ src/decoder/plugins/SidplayDecoderPlugin.cxx \ diff --git a/NEWS b/NEWS index fb5fd19b5..7d04d528c 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,7 @@ ver 0.19.5 (not yet released) * decoder - dsdiff, dsf, opus: fix deadlock while seeking + - mp4v2: remove because of incompatible license ver 0.19.4 (2014/11/18) * protocol diff --git a/configure.ac b/configure.ac index 5a44fa5c8..f8d100331 100644 --- a/configure.ac +++ b/configure.ac @@ -496,11 +496,6 @@ AC_ARG_ENABLE(modplug, [enable modplug decoder plugin]),, enable_modplug=auto) -AC_ARG_ENABLE(mp4v2, - AS_HELP_STRING([--enable-mp4v2], - [enable libmp4v2 decoder plugin]),, - enable_mp4v2=auto) - AC_ARG_ENABLE(mpc, AS_HELP_STRING([--enable-mpc], [disable musepack (MPC) support (default: auto)]),, @@ -1264,24 +1259,6 @@ if test x$enable_modplug = xyes; then fi AM_CONDITIONAL(HAVE_MODPLUG, test x$enable_modplug = xyes) -dnl -------------------------------- libmp4v2 --------------------------------- -if test x$enable_aac = xyes; then - MPD_AUTO_LIB(mp4v2, MP4V2, mp4v2, MP4Create, [-lmp4v2], [], - [mp4v2], [libmp4v2 not found]) - - if test x$enable_mp4v2 = xyes; then - AC_DEFINE(HAVE_MP4V2, 1, [Define to use libmp4v2 for MP4 decoding]) - fi -else - if test x$enable_mp4v2 = xyes; then - AC_MSG_ERROR([MP4V2 requires AAC!]) - fi - - enable_mp4v2=no -fi - -AM_CONDITIONAL(HAVE_MP4V2, test x$enable_mp4v2 = xyes) - dnl -------------------------------- libopus ---------------------------------- MPD_AUTO_PKG(opus, OPUS, [opus ogg], [opus decoder plugin], [libopus not found]) @@ -1868,7 +1845,6 @@ printf '\n\t' results(sndfile, [libsndfile]) results(mikmod, [MikMod]) results(modplug, [MODPLUG]) -results(mp4v2, [MP4V2]) results(mad, [MAD]) results(mpg123, [MPG123]) results(mpc, [Musepack]) diff --git a/src/decoder/DecoderList.cxx b/src/decoder/DecoderList.cxx index 0a31d9eac..cd6881ce2 100644 --- a/src/decoder/DecoderList.cxx +++ b/src/decoder/DecoderList.cxx @@ -37,7 +37,6 @@ #include "plugins/MadDecoderPlugin.hxx" #include "plugins/SndfileDecoderPlugin.hxx" #include "plugins/Mpg123DecoderPlugin.hxx" -#include "plugins/Mp4v2DecoderPlugin.hxx" #include "plugins/WildmidiDecoderPlugin.hxx" #include "plugins/MikmodDecoderPlugin.hxx" #include "plugins/ModplugDecoderPlugin.hxx" @@ -55,9 +54,6 @@ const struct DecoderPlugin *const decoder_plugins[] = { #ifdef HAVE_MPG123 &mpg123_decoder_plugin, #endif -#ifdef HAVE_MP4V2 - &mp4v2_decoder_plugin, -#endif #ifdef ENABLE_VORBIS_DECODER &vorbis_decoder_plugin, #endif diff --git a/src/decoder/plugins/Mp4v2DecoderPlugin.cxx b/src/decoder/plugins/Mp4v2DecoderPlugin.cxx deleted file mode 100644 index 34bccd243..000000000 --- a/src/decoder/plugins/Mp4v2DecoderPlugin.cxx +++ /dev/null @@ -1,330 +0,0 @@ -/* - * Copyright (C) 2003-2014 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" /* must be first for large file support */ -#include "Mp4v2DecoderPlugin.hxx" -#include "../DecoderAPI.hxx" -#include "CheckAudioFormat.hxx" -#include "tag/TagHandler.hxx" -#include "fs/Path.hxx" -#include "util/Error.hxx" -#include "util/Domain.hxx" -#include "Log.hxx" - -#include -#include - -#include -#include - -static constexpr Domain mp4v2_decoder_domain("mp4v2"); - -static MP4TrackId -mp4_get_aac_track(MP4FileHandle handle, NeAACDecHandle decoder, - AudioFormat &audio_format, Error &error) -{ - unsigned long sample_rate; - - const MP4TrackId tracks = MP4GetNumberOfTracks(handle); - - for (MP4TrackId id = 1; id <= tracks; id++) { - const char* track_type = MP4GetTrackType(handle, id); - - if (track_type == 0) - continue; - - const auto obj_type = MP4GetTrackEsdsObjectTypeId(handle, id); - - if (obj_type == MP4_INVALID_AUDIO_TYPE) - continue; - if (obj_type == MP4_MPEG4_AUDIO_TYPE) { - const auto mpeg_type = MP4GetTrackAudioMpeg4Type(handle, id); - if (!MP4_IS_MPEG4_AAC_AUDIO_TYPE(mpeg_type)) - continue; - } else if (!MP4_IS_AAC_AUDIO_TYPE(obj_type)) - continue; - - if (decoder == nullptr) - /* found audio track, no decoder */ - return id; - - unsigned char *buff = nullptr; - unsigned buff_size = 0; - - if (!MP4GetTrackESConfiguration(handle, id, &buff, &buff_size)) - continue; - - uint8_t channels; - int32_t nbytes = NeAACDecInit(decoder, buff, buff_size, - &sample_rate, &channels); - - free(buff); - - if (nbytes < 0) - /* invalid stream */ - continue; - - if (!audio_format_init_checked(audio_format, sample_rate, - SampleFormat::S16, - channels, - error)) - continue; - - return id; - } - - error.Set(mp4v2_decoder_domain, "no valid aac track found"); - - return MP4_INVALID_TRACK_ID; -} - -static NeAACDecHandle -mp4_faad_new(MP4FileHandle handle, AudioFormat &audio_format, Error &error) -{ - const NeAACDecHandle decoder = NeAACDecOpen(); - const NeAACDecConfigurationPtr config = - NeAACDecGetCurrentConfiguration(decoder); - config->outputFormat = FAAD_FMT_16BIT; - config->downMatrix = 1; - config->dontUpSampleImplicitSBR = 0; - NeAACDecSetConfiguration(decoder, config); - - const auto track = mp4_get_aac_track(handle, decoder, audio_format, error); - - if (track == MP4_INVALID_TRACK_ID) { - NeAACDecClose(decoder); - return nullptr; - } - - return decoder; -} - -static void -mp4_file_decode(Decoder &mpd_decoder, Path path_fs) -{ - const MP4FileHandle handle = MP4Read(path_fs.c_str()); - - if (handle == MP4_INVALID_FILE_HANDLE) { - FormatError(mp4v2_decoder_domain, - "unable to open file"); - return; - } - - AudioFormat audio_format; - Error error; - const NeAACDecHandle decoder = mp4_faad_new(handle, audio_format, error); - - if (decoder == nullptr) { - LogError(error); - MP4Close(handle); - return; - } - - const MP4TrackId track = mp4_get_aac_track(handle, nullptr, audio_format, error); - - /* initialize the MPD core */ - - const MP4Timestamp scale = MP4GetTrackTimeScale(handle, track); - const SongTime duration = SongTime::FromScale(MP4GetTrackDuration(handle, track), - scale); - const MP4SampleId num_samples = MP4GetTrackNumberOfSamples(handle, track); - - decoder_initialized(mpd_decoder, audio_format, true, duration); - - /* the decoder loop */ - - DecoderCommand cmd = DecoderCommand::NONE; - - for (MP4SampleId sample = 1; - sample < num_samples && cmd != DecoderCommand::STOP; - sample++) { - unsigned char *data = nullptr; - unsigned int data_length = 0; - - if (cmd == DecoderCommand::SEEK) { - const MP4Timestamp offset = - decoder_seek_time(mpd_decoder).ToScale(scale); - - sample = MP4GetSampleIdFromTime(handle, track, offset, - false); - decoder_command_finished(mpd_decoder); - } - - /* read */ - if (MP4ReadSample(handle, track, sample, &data, &data_length) == 0) { - FormatError(mp4v2_decoder_domain, "unable to read sample"); - break; - } - - /* decode it */ - NeAACDecFrameInfo frame_info; - const void *const decoded = NeAACDecDecode(decoder, &frame_info, data, data_length); - - if (frame_info.error > 0) { - FormatWarning(mp4v2_decoder_domain, - "error decoding AAC stream: %s", - NeAACDecGetErrorMessage(frame_info.error)); - break; - } - - if (frame_info.channels != audio_format.channels) { - FormatDefault(mp4v2_decoder_domain, - "channel count changed from %u to %u", - audio_format.channels, frame_info.channels); - break; - } - - if (frame_info.samplerate != audio_format.sample_rate) { - FormatDefault(mp4v2_decoder_domain, - "sample rate changed from %u to %lu", - audio_format.sample_rate, - (unsigned long)frame_info.samplerate); - break; - } - - /* update bit rate and position */ - unsigned bit_rate = 0; - - if (frame_info.samples > 0) { - bit_rate = frame_info.bytesconsumed * 8.0 * - frame_info.channels * audio_format.sample_rate / - frame_info.samples / 1000 + 0.5; - } - - /* send PCM samples to MPD */ - - cmd = decoder_data(mpd_decoder, nullptr, decoded, - (size_t)frame_info.samples * 2, - bit_rate); - - free(data); - } - - /* cleanup */ - NeAACDecClose(decoder); - MP4Close(handle); -} - -static inline void -mp4_safe_invoke_tag(const struct tag_handler *handler, void *handler_ctx, - TagType tag, const char *value) -{ - if (value != nullptr) - tag_handler_invoke_tag(handler, handler_ctx, tag, value); -} - -static bool -mp4_scan_file(Path path_fs, - const struct tag_handler *handler, void *handler_ctx) -{ - const MP4FileHandle handle = MP4Read(path_fs.c_str()); - - if (handle == MP4_INVALID_FILE_HANDLE) - return false; - - AudioFormat tmp_audio_format; - Error error; - const MP4TrackId id = mp4_get_aac_track(handle, nullptr, tmp_audio_format, error); - - if (id == MP4_INVALID_TRACK_ID) { - LogError(error); - MP4Close(handle); - return false; - } - - const MP4Timestamp scale = MP4GetTrackTimeScale(handle, id); - const SongTime dur = - SongTime::FromScale(MP4GetTrackDuration(handle, id), - scale); - tag_handler_invoke_duration(handler, handler_ctx, dur); - - const MP4Tags* tags = MP4TagsAlloc(); - MP4TagsFetch(tags, handle); - - static constexpr struct { - const char *MP4Tags::*p; - TagType tag_type; - } mp4v2_tags[] = { - { &MP4Tags::name, TAG_NAME }, - { &MP4Tags::artist, TAG_ARTIST }, - { &MP4Tags::albumArtist, TAG_ALBUM_ARTIST }, - { &MP4Tags::album, TAG_ALBUM }, - { &MP4Tags::composer, TAG_COMPOSER }, - { &MP4Tags::comments, TAG_COMMENT }, - { &MP4Tags::genre, TAG_GENRE }, - { &MP4Tags::releaseDate, TAG_DATE }, - { &MP4Tags::sortArtist, TAG_ARTIST_SORT }, - { &MP4Tags::sortAlbumArtist, TAG_ALBUM_ARTIST_SORT }, - }; - - for (const auto &i : mp4v2_tags) - mp4_safe_invoke_tag(handler, handler_ctx, - i.tag_type, tags->*i.p); - - char buff[8]; /* tmp buffer for index to string. */ - if (tags->track != nullptr) { - sprintf(buff, "%d", tags->track->index); - tag_handler_invoke_tag(handler, handler_ctx, TAG_TRACK, buff); - } - - if (tags->disk != nullptr) { - sprintf(buff, "%d", tags->disk->index); - tag_handler_invoke_tag(handler, handler_ctx, TAG_DISC, buff); - } - - MP4TagsFree(tags); - MP4Close(handle); - - return true; -} - -static const char *const mp4_suffixes[] = { - "mp4", - "m4a", - /* "m4p", encrypted */ - /* "m4b", audio book */ - /* "m4r", ring tones */ - /* "m4v", video */ - nullptr -}; - -static const char *const mp4_mime_types[] = { - "application/mp4", - "application/m4a", - "audio/mp4", - "audio/m4a", - /* "audio/m4p", */ - /* "audio/m4b", */ - /* "audio/m4r", */ - /* "audio/m4v", */ - nullptr -}; - -const struct DecoderPlugin mp4v2_decoder_plugin = { - "mp4v2", - nullptr, - nullptr, - nullptr, - mp4_file_decode, - mp4_scan_file, - nullptr, - nullptr, - mp4_suffixes, - mp4_mime_types -}; diff --git a/src/decoder/plugins/Mp4v2DecoderPlugin.hxx b/src/decoder/plugins/Mp4v2DecoderPlugin.hxx deleted file mode 100644 index 57585dec4..000000000 --- a/src/decoder/plugins/Mp4v2DecoderPlugin.hxx +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (C) 2003-2014 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_DECODER_MP4V2_HXX -#define MPD_DECODER_MP4V2_HXX - -extern const struct DecoderPlugin mp4v2_decoder_plugin; - -#endif -- cgit v1.2.3 From 029555d1921e651f1ed6929561a52eb598def3fb Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Tue, 25 Nov 2014 13:10:16 +0100 Subject: lib/nfs/FileReader: include Compiler.h for "final" fallback --- src/lib/nfs/FileReader.hxx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lib/nfs/FileReader.hxx b/src/lib/nfs/FileReader.hxx index 7f43e0ecf..424ff766d 100644 --- a/src/lib/nfs/FileReader.hxx +++ b/src/lib/nfs/FileReader.hxx @@ -24,6 +24,7 @@ #include "Lease.hxx" #include "Callback.hxx" #include "event/DeferredMonitor.hxx" +#include "Compiler.h" #include -- cgit v1.2.3 From f5f43db2da6bf0e5f39c8fb281ccca6e3dd8e65a Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Tue, 25 Nov 2014 13:09:19 +0100 Subject: lib/nfs/Connection: cancel DeferredMonitor on disconnect Fixes potential second mount attempt after the old connection to the NFS server was shut down. --- src/lib/nfs/Connection.cxx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/lib/nfs/Connection.cxx b/src/lib/nfs/Connection.cxx index c2c7ceb2b..c4612f613 100644 --- a/src/lib/nfs/Connection.cxx +++ b/src/lib/nfs/Connection.cxx @@ -327,6 +327,10 @@ NfsConnection::DestroyContext() assert(GetEventLoop().IsInside()); assert(context != nullptr); + /* cancel pending DeferredMonitor that was scheduled to notify + new leases */ + DeferredMonitor::Cancel(); + if (SocketMonitor::IsDefined()) SocketMonitor::Cancel(); -- cgit v1.2.3 From b293b160079fd19cfc675fa86c2b99695aac171f Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Tue, 25 Nov 2014 13:27:06 +0100 Subject: lib/nfs/Connection: broadcast error before closing connection During the NfsLease::OnNfsConnectionFailed() call, the old (defunct) nfs_context may be used to close file handles. Such code does not yet exist, but will be added soon to fix other bugs. --- src/lib/nfs/Connection.cxx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/lib/nfs/Connection.cxx b/src/lib/nfs/Connection.cxx index c4612f613..06d2a4d2a 100644 --- a/src/lib/nfs/Connection.cxx +++ b/src/lib/nfs/Connection.cxx @@ -409,10 +409,10 @@ NfsConnection::OnSocketReady(unsigned flags) error.Format(nfs_domain, "NFS connection has failed: %s", nfs_get_error(context)); + BroadcastError(std::move(error)); + DestroyContext(); closed = true; - - BroadcastError(std::move(error)); } else if (SocketMonitor::IsDefined() && nfs_get_fd(context) < 0) { /* this happens when rpc_reconnect_requeue() is called after the connection broke, but autoreconnet was @@ -425,10 +425,10 @@ NfsConnection::OnSocketReady(unsigned flags) error.Format(nfs_domain, "NFS socket disappeared: %s", msg); + BroadcastError(std::move(error)); + DestroyContext(); closed = true; - - BroadcastError(std::move(error)); } assert(in_event); -- cgit v1.2.3 From 3cef348f30ad8a018b1c46f257d3e719be3f96b0 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Tue, 25 Nov 2014 10:42:52 +0100 Subject: lib/nfs/Manager: defer NfsConnection destruction Avoids a crash that occurs when NfsConnection::OnSocketReady() dereferences itself before returning. --- NEWS | 2 ++ src/lib/nfs/Manager.cxx | 30 +++++++++++++++++++++++++----- src/lib/nfs/Manager.hxx | 33 +++++++++++++++++++++++++++++---- 3 files changed, 56 insertions(+), 9 deletions(-) diff --git a/NEWS b/NEWS index 7d04d528c..5d089033a 100644 --- a/NEWS +++ b/NEWS @@ -1,4 +1,6 @@ ver 0.19.5 (not yet released) +* input + - nfs: fix crash on connection failure * decoder - dsdiff, dsf, opus: fix deadlock while seeking - mp4v2: remove because of incompatible license diff --git a/src/lib/nfs/Manager.cxx b/src/lib/nfs/Manager.cxx index c5aecf48d..6d50cce18 100644 --- a/src/lib/nfs/Manager.cxx +++ b/src/lib/nfs/Manager.cxx @@ -29,8 +29,10 @@ NfsManager::ManagedConnection::OnNfsConnectionError(Error &&error) { FormatError(error, "NFS error on %s:%s", GetServer(), GetExportName()); - manager.connections.erase(manager.connections.iterator_to(*this)); - delete this; + /* defer deletion so the caller + (i.e. NfsConnection::OnSocketReady()) can still use this + object */ + manager.ScheduleDelete(*this); } inline bool @@ -59,7 +61,9 @@ NfsManager::Compare::operator()(const ManagedConnection &a, NfsManager::~NfsManager() { - assert(loop.IsInside()); + assert(GetEventLoop().IsInside()); + + CollectGarbage(); connections.clear_and_dispose([](ManagedConnection *c){ delete c; @@ -71,13 +75,13 @@ NfsManager::GetConnection(const char *server, const char *export_name) { assert(server != nullptr); assert(export_name != nullptr); - assert(loop.IsInside()); + assert(GetEventLoop().IsInside()); Map::insert_commit_data hint; auto result = connections.insert_check(LookupKey{server, export_name}, Compare(), hint); if (result.second) { - auto c = new ManagedConnection(*this, loop, + auto c = new ManagedConnection(*this, GetEventLoop(), server, export_name); connections.insert_commit(*c, hint); return *c; @@ -85,3 +89,19 @@ NfsManager::GetConnection(const char *server, const char *export_name) return *result.first; } } + +void +NfsManager::CollectGarbage() +{ + assert(GetEventLoop().IsInside()); + + garbage.clear_and_dispose([](ManagedConnection *c){ + delete c; + }); +} + +void +NfsManager::OnIdle() +{ + CollectGarbage(); +} diff --git a/src/lib/nfs/Manager.hxx b/src/lib/nfs/Manager.hxx index 612b01f9c..130c81aca 100644 --- a/src/lib/nfs/Manager.hxx +++ b/src/lib/nfs/Manager.hxx @@ -23,14 +23,16 @@ #include "check.h" #include "Connection.hxx" #include "Compiler.h" +#include "event/IdleMonitor.hxx" #include +#include /** * A manager for NFS connections. Handles multiple connections to * multiple NFS servers. */ -class NfsManager { +class NfsManager final : IdleMonitor { struct LookupKey { const char *server; const char *export_name; @@ -38,6 +40,7 @@ class NfsManager { class ManagedConnection final : public NfsConnection, + public boost::intrusive::slist_base_hook>, public boost::intrusive::set_base_hook> { NfsManager &manager; @@ -63,8 +66,6 @@ class NfsManager { const LookupKey b) const; }; - EventLoop &loop; - /** * Maps server and export_name to #ManagedConnection. */ @@ -74,9 +75,18 @@ class NfsManager { Map connections; + typedef boost::intrusive::slist List; + + /** + * A list of "garbage" connection objects. Their destruction + * is postponed because they were thrown into the garbage list + * when callers on the stack were still using them. + */ + List garbage; + public: NfsManager(EventLoop &_loop) - :loop(_loop) {} + :IdleMonitor(_loop) {} /** * Must be run from EventLoop's thread. @@ -86,6 +96,21 @@ public: gcc_pure NfsConnection &GetConnection(const char *server, const char *export_name); + +private: + void ScheduleDelete(ManagedConnection &c) { + connections.erase(connections.iterator_to(c)); + garbage.push_front(c); + IdleMonitor::Schedule(); + } + + /** + * Delete all connections on the #garbage list. + */ + void CollectGarbage(); + + /* virtual methods from IdleMonitor */ + void OnIdle() override; }; #endif -- cgit v1.2.3 From 40dd968f1302da9fa65c53ba0ae0e6a12c7cda9b Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Tue, 25 Nov 2014 13:03:09 +0100 Subject: lib/nfs/FileReader: update "state" in OnNfsError() Clean up the "state" to indicate that there is no longer any asynchronous operation. Fixes another NFS-related crash due to cleanup of a non-existing asynchronous operation. --- src/lib/nfs/FileReader.cxx | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/lib/nfs/FileReader.cxx b/src/lib/nfs/FileReader.cxx index 4837e1f0e..7f5506d50 100644 --- a/src/lib/nfs/FileReader.cxx +++ b/src/lib/nfs/FileReader.cxx @@ -246,6 +246,30 @@ NfsFileReader::OnNfsCallback(unsigned status, void *data) void NfsFileReader::OnNfsError(Error &&error) { + switch (state) { + case State::INITIAL: + case State::DEFER: + case State::MOUNT: + case State::IDLE: + assert(false); + gcc_unreachable(); + + case State::OPEN: + connection->RemoveLease(*this); + state = State::INITIAL; + break; + + case State::STAT: + connection->RemoveLease(*this); + connection->Close(fh); + state = State::INITIAL; + break; + + case State::READ: + state = State::IDLE; + break; + } + OnNfsFileError(std::move(error)); } -- cgit v1.2.3 From 38f19981b2bcaa6f08f1d1e81be66d217e8da9b8 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Tue, 25 Nov 2014 13:50:36 +0100 Subject: lib/nfs/FileReader: reset state in OnNfsConnectionFailed() Avoid calling NfsConnection::RemoveLease(), because the lease has been removed already. --- src/lib/nfs/FileReader.cxx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/lib/nfs/FileReader.cxx b/src/lib/nfs/FileReader.cxx index 7f5506d50..79256492b 100644 --- a/src/lib/nfs/FileReader.cxx +++ b/src/lib/nfs/FileReader.cxx @@ -164,6 +164,8 @@ NfsFileReader::OnNfsConnectionFailed(const Error &error) { assert(state == State::MOUNT); + state = State::INITIAL; + Error copy; copy.Set(error); OnNfsFileError(std::move(copy)); -- cgit v1.2.3 From 016063c810281bd05c792dfe8643cc68b4c3cab2 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Tue, 25 Nov 2014 14:00:32 +0100 Subject: lib/nfs/FileReader: move code to CancelOrClose() --- src/lib/nfs/FileReader.cxx | 10 ++++++++++ src/lib/nfs/FileReader.hxx | 6 ++++++ 2 files changed, 16 insertions(+) diff --git a/src/lib/nfs/FileReader.cxx b/src/lib/nfs/FileReader.cxx index 79256492b..455165bbd 100644 --- a/src/lib/nfs/FileReader.cxx +++ b/src/lib/nfs/FileReader.cxx @@ -56,8 +56,18 @@ NfsFileReader::Close() return; } + /* this cancels State::MOUNT */ connection->RemoveLease(*this); + CancelOrClose(); +} + +void +NfsFileReader::CancelOrClose() +{ + assert(state != State::INITIAL && + state != State::DEFER); + if (state == State::IDLE) /* no async operation in progress: can close immediately */ diff --git a/src/lib/nfs/FileReader.hxx b/src/lib/nfs/FileReader.hxx index 424ff766d..1495a2832 100644 --- a/src/lib/nfs/FileReader.hxx +++ b/src/lib/nfs/FileReader.hxx @@ -76,6 +76,12 @@ protected: virtual void OnNfsFileError(Error &&error) = 0; private: + /** + * Cancel the current operation, if any. The NfsLease must be + * unregistered already. + */ + void CancelOrClose(); + void OpenCallback(nfsfh *_fh); void StatCallback(const struct stat *st); -- cgit v1.2.3 From e72eef421b75516e0447e4a06419d1a7aba4d853 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Tue, 25 Nov 2014 12:29:55 +0100 Subject: lib/nfs/FileReader: clean up on disconnect Avoids crash because Close() invokes a call on a destructed NfsConnection. --- src/lib/nfs/FileReader.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/nfs/FileReader.cxx b/src/lib/nfs/FileReader.cxx index 455165bbd..1b80f2c86 100644 --- a/src/lib/nfs/FileReader.cxx +++ b/src/lib/nfs/FileReader.cxx @@ -186,7 +186,7 @@ NfsFileReader::OnNfsConnectionDisconnected(const Error &error) { assert(state > State::MOUNT); - state = State::INITIAL; + CancelOrClose(); Error copy; copy.Set(error); -- cgit v1.2.3 From 04f627c2af2695c848dd8b9ce25e9603db17fdd8 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Wed, 26 Nov 2014 19:58:48 +0100 Subject: release v0.18.19 --- NEWS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NEWS b/NEWS index 4699f6666..2782ca89d 100644 --- a/NEWS +++ b/NEWS @@ -1,4 +1,4 @@ -ver 0.18.19 (not yet released) +ver 0.18.19 (2014/11/26) * archive - zzip: fix crash after seeking -- cgit v1.2.3 From 0bc511715b409bf400de4d9053ff4978d2e8d7cb Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Wed, 26 Nov 2014 20:10:00 +0100 Subject: Makefile.am: distribute Android sources --- Makefile.am | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Makefile.am b/Makefile.am index 874e37d10..e8f459454 100644 --- a/Makefile.am +++ b/Makefile.am @@ -2179,4 +2179,11 @@ EXTRA_DIST = $(doc_DATA) autogen.sh \ $(wildcard scripts/*.sh) \ $(man_MANS) $(DOCBOOK_FILES) doc/mpdconf.example doc/doxygen.conf \ systemd/mpd.socket \ + android/AndroidManifest.xml \ + android/build.py \ + android/custom_rules.xml \ + android/res/values/strings.xml \ + android/src/Bridge.java \ + android/src/Loader.java \ + android/src/Main.java \ src/win32/mpd_win32_rc.rc.in src/win32/mpd.ico -- cgit v1.2.3 From 67cba251c8826409c82fb2ab75072dc4fca2b4dc Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Wed, 26 Nov 2014 20:05:45 +0100 Subject: release v0.19.5 --- NEWS | 2 +- android/AndroidManifest.xml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/NEWS b/NEWS index 31013de46..315dfdb85 100644 --- a/NEWS +++ b/NEWS @@ -1,4 +1,4 @@ -ver 0.19.5 (not yet released) +ver 0.19.5 (2014/11/26) * input - nfs: fix crash on connection failure * archive diff --git a/android/AndroidManifest.xml b/android/AndroidManifest.xml index 02401c699..8625bd76e 100644 --- a/android/AndroidManifest.xml +++ b/android/AndroidManifest.xml @@ -2,8 +2,8 @@ + android:versionCode="9" + android:versionName="0.19.5"> -- cgit v1.2.3