SocketAPI OSX: Forbid further sends on connectionDidDie
authorChristian Kamm <mail@ckamm.de>
Thu, 17 Jan 2019 09:16:44 +0000 (10:16 +0100)
committerKevin Ottens <kevin.ottens@nextcloud.com>
Tue, 15 Dec 2020 09:58:36 +0000 (10:58 +0100)
Also release the remote end immediately.

src/gui/socketapisocket_mac.mm

index 554447cf1b39a55962530ddc6e8dac41037496ce..f018ac752b63c37b65fefe8fff82d87577660751 100644 (file)
@@ -42,9 +42,13 @@ public:
     SocketApiSocketPrivate(NSDistantObject <ChannelProtocol> *remoteEnd);
     ~SocketApiSocketPrivate();
 
+    // release remoteEnd
+    void disconnectRemote();
+
     NSDistantObject <ChannelProtocol> *remoteEnd;
     LocalEnd *localEnd;
     QByteArray inBuffer;
+    bool isRemoteDisconnected = false;
 };
 
 class SocketApiServerPrivate
@@ -80,8 +84,10 @@ public:
 - (void)connectionDidDie:(NSNotification*)notification
 {
 #pragma unused(notification)
-    if (_wrapper)
+    if (_wrapper) {
+        _wrapper->disconnectRemote();
         emit _wrapper->q_ptr->disconnected();
+    }
 }
 @end
 
@@ -133,8 +139,11 @@ qint64 SocketApiSocket::readData(char *data, qint64 maxlen)
 
 qint64 SocketApiSocket::writeData(const char *data, qint64 len)
 {
+    Q_D(SocketApiSocket);
+    if (d->isRemoteDisconnected)
+        return -1;
+
     @try {
-        Q_D(SocketApiSocket);
         // FIXME: The NSConnection will make this block unless the function is marked as "oneway"
         // in the protocol. This isn't async and reduces our performances but this currectly avoids
         // a Mach queue deadlock during requests bursts of the legacy OwnCloudFinder extension.
@@ -143,6 +152,7 @@ qint64 SocketApiSocket::writeData(const char *data, qint64 len)
         return len;
     } @catch(NSException* e) {
         // connectionDidDie can be notified too late, also interpret any sending exception as a disconnection.
+        d->disconnectRemote();
         emit disconnected();
         return -1;
     }
@@ -174,12 +184,22 @@ SocketApiSocketPrivate::SocketApiSocketPrivate(NSDistantObject <ChannelProtocol>
 
 SocketApiSocketPrivate::~SocketApiSocketPrivate()
 {
-    [remoteEnd release];
+    disconnectRemote();
+
     // The DO vended localEnd might still be referenced by the connection
     localEnd.wrapper = nil;
     [localEnd release];
 }
 
+void SocketApiSocketPrivate::disconnectRemote()
+{
+    if (isRemoteDisconnected)
+        return;
+    isRemoteDisconnected = true;
+
+    [remoteEnd release];
+}
+
 SocketApiServer::SocketApiServer()
     : d_ptr(new SocketApiServerPrivate)
 {