Commit ea5e6d8f authored by Max Kellermann's avatar Max Kellermann

Merge branch 'v0.21.x'

parents c1272c72 f6941f9a
...@@ -8,6 +8,13 @@ ver 0.22 (not yet released) ...@@ -8,6 +8,13 @@ ver 0.22 (not yet released)
- ffmpeg: new plugin based on FFmpeg's libavfilter library - ffmpeg: new plugin based on FFmpeg's libavfilter library
- hdcd: new plugin based on FFmpeg's "af_hdcd" for HDCD playback - hdcd: new plugin based on FFmpeg's "af_hdcd" for HDCD playback
ver 0.21.8 (not yet released)
* output
- httpd: add missing mutex lock
- httpd: fix use-after-free bug
* fix Bonjour bug
* fix build failure with GCC 9
ver 0.21.7 (2019/04/03) ver 0.21.7 (2019/04/03)
* input * input
- qobuz/tidal: scan tags when loading a playlist - qobuz/tidal: scan tags when loading a playlist
......
...@@ -2,8 +2,8 @@ ...@@ -2,8 +2,8 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.musicpd" package="org.musicpd"
android:installLocation="auto" android:installLocation="auto"
android:versionCode="29" android:versionCode="30"
android:versionName="0.21.7"> android:versionName="0.21.8">
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="26"/> <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="26"/>
......
...@@ -568,7 +568,8 @@ ProxyDatabase::OnSocketReady(gcc_unused unsigned flags) noexcept ...@@ -568,7 +568,8 @@ ProxyDatabase::OnSocketReady(gcc_unused unsigned flags) noexcept
if (!is_idle) { if (!is_idle) {
// TODO: can this happen? // TODO: can this happen?
IdleMonitor::Schedule(); IdleMonitor::Schedule();
return false; SocketMonitor::Cancel();
return true;
} }
unsigned idle = (unsigned)mpd_recv_idle(connection, false); unsigned idle = (unsigned)mpd_recv_idle(connection, false);
...@@ -586,7 +587,8 @@ ProxyDatabase::OnSocketReady(gcc_unused unsigned flags) noexcept ...@@ -586,7 +587,8 @@ ProxyDatabase::OnSocketReady(gcc_unused unsigned flags) noexcept
idle_received |= idle; idle_received |= idle;
is_idle = false; is_idle = false;
IdleMonitor::Schedule(); IdleMonitor::Schedule();
return false; SocketMonitor::Cancel();
return true;
} }
void void
......
...@@ -110,15 +110,9 @@ BufferedSocket::OnSocketReady(unsigned flags) noexcept ...@@ -110,15 +110,9 @@ BufferedSocket::OnSocketReady(unsigned flags) noexcept
if (flags & READ) { if (flags & READ) {
assert(!input.IsFull()); assert(!input.IsFull());
if (!ReadToBuffer()) if (!ReadToBuffer() || !ResumeInput())
return false; return false;
if (!ResumeInput())
/* we must return "true" here or
SocketMonitor::Dispatch() will call
Cancel() on a freed object */
return true;
if (!input.IsFull()) if (!input.IsFull())
ScheduleRead(); ScheduleRead();
} }
......
...@@ -47,6 +47,11 @@ public: ...@@ -47,6 +47,11 @@ public:
using SocketMonitor::Close; using SocketMonitor::Close;
private: private:
/**
* @return the number of bytes read from the socket, 0 if the
* socket isn't ready for reading, -1 on error (the socket has
* been closed and probably destructed)
*/
ssize_t DirectRead(void *data, size_t length) noexcept; ssize_t DirectRead(void *data, size_t length) noexcept;
/** /**
......
...@@ -46,6 +46,11 @@ public: ...@@ -46,6 +46,11 @@ public:
} }
private: private:
/**
* @return the number of bytes written to the socket, 0 if the
* socket isn't ready for writing, -1 on error (the socket has
* been closed and probably destructed)
*/
ssize_t DirectWrite(const void *data, size_t length) noexcept; ssize_t DirectWrite(const void *data, size_t length) noexcept;
protected: protected:
......
...@@ -33,8 +33,8 @@ SocketMonitor::Dispatch(unsigned flags) noexcept ...@@ -33,8 +33,8 @@ SocketMonitor::Dispatch(unsigned flags) noexcept
{ {
flags &= GetScheduledFlags(); flags &= GetScheduledFlags();
if (flags != 0 && !OnSocketReady(flags) && IsDefined()) if (flags != 0)
Cancel(); OnSocketReady(flags);
} }
SocketMonitor::~SocketMonitor() noexcept SocketMonitor::~SocketMonitor() noexcept
......
...@@ -168,7 +168,7 @@ public: ...@@ -168,7 +168,7 @@ public:
} }
constexpr operator SocketAddress() const noexcept { constexpr operator SocketAddress() const noexcept {
return SocketAddress((const struct sockaddr *)&address, return SocketAddress((const struct sockaddr *)(const void *)&address,
sizeof(address)); sizeof(address));
} }
......
...@@ -135,7 +135,7 @@ public: ...@@ -135,7 +135,7 @@ public:
} }
constexpr operator SocketAddress() const noexcept { constexpr operator SocketAddress() const noexcept {
return SocketAddress((const struct sockaddr *)&address, return SocketAddress((const struct sockaddr *)(const void *)&address,
sizeof(address)); sizeof(address));
} }
......
...@@ -154,7 +154,7 @@ HttpdClient::SendResponse() noexcept ...@@ -154,7 +154,7 @@ HttpdClient::SendResponse() noexcept
FormatWarning(httpd_output_domain, FormatWarning(httpd_output_domain,
"failed to write to client: %s", "failed to write to client: %s",
(const char *)msg); (const char *)msg);
Close(); LockClose();
return false; return false;
} }
...@@ -428,6 +428,7 @@ void ...@@ -428,6 +428,7 @@ void
HttpdClient::OnSocketError(std::exception_ptr ep) noexcept HttpdClient::OnSocketError(std::exception_ptr ep) noexcept
{ {
LogError(ep); LogError(ep);
LockClose();
} }
void void
......
...@@ -142,6 +142,8 @@ public: ...@@ -142,6 +142,8 @@ public:
/** /**
* Frees the client and removes it from the server's client list. * Frees the client and removes it from the server's client list.
*
* Caller must lock the mutex.
*/ */
void Close() noexcept; void Close() noexcept;
......
...@@ -208,10 +208,15 @@ public: ...@@ -208,10 +208,15 @@ public:
return HasClients(); return HasClients();
} }
/**
* Caller must lock the mutex.
*/
void AddClient(UniqueSocketDescriptor fd) noexcept; void AddClient(UniqueSocketDescriptor fd) noexcept;
/** /**
* Removes a client from the httpd_output.clients linked list. * Removes a client from the httpd_output.clients linked list.
*
* Caller must lock the mutex.
*/ */
void RemoveClient(HttpdClient &client) noexcept; void RemoveClient(HttpdClient &client) noexcept;
...@@ -239,10 +244,14 @@ public: ...@@ -239,10 +244,14 @@ public:
/** /**
* Broadcasts data from the encoder to all clients. * Broadcasts data from the encoder to all clients.
*
* Mutext must not be locked.
*/ */
void BroadcastFromEncoder(); void BroadcastFromEncoder();
/** /**
* Mutext must not be locked.
*
* Throws #std::runtime_error on error. * Throws #std::runtime_error on error.
*/ */
void EncodeAndPlay(const void *chunk, size_t size); void EncodeAndPlay(const void *chunk, size_t size);
...@@ -251,6 +260,9 @@ public: ...@@ -251,6 +260,9 @@ public:
size_t Play(const void *chunk, size_t size) override; size_t Play(const void *chunk, size_t size) override;
/**
* Mutext must not be locked.
*/
void CancelAllClients() noexcept; void CancelAllClients() noexcept;
void Cancel() noexcept override; void Cancel() noexcept override;
......
...@@ -50,7 +50,7 @@ protected: ...@@ -50,7 +50,7 @@ protected:
/* virtual methods from class SocketMonitor */ /* virtual methods from class SocketMonitor */
bool OnSocketReady(gcc_unused unsigned flags) noexcept override { bool OnSocketReady(gcc_unused unsigned flags) noexcept override {
DNSServiceProcessResult(service_ref); DNSServiceProcessResult(service_ref);
return false; return true;
} }
}; };
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment