From 16acce08b9039aaecdb8f3bf372eea3b04fbc0d9 Mon Sep 17 00:00:00 2001 From: Erik Verbruggen Date: Wed, 10 Nov 2021 18:05:55 +0100 Subject: macOS: Use local socket to communicate with finder extension https://github.com/owncloud/client/issues/6343 --- src/gui/guiutility_mac.mm | 10 +- src/gui/socketapi/CMakeLists.txt | 4 - src/gui/socketapi/socketapi.cpp | 37 ++--- src/gui/socketapi/socketapi.h | 2 +- src/gui/socketapi/socketapisocket_mac.h | 69 -------- src/gui/socketapi/socketapisocket_mac.mm | 273 ------------------------------- 6 files changed, 23 insertions(+), 372 deletions(-) delete mode 100644 src/gui/socketapi/socketapisocket_mac.h delete mode 100644 src/gui/socketapi/socketapisocket_mac.mm (limited to 'src/gui') diff --git a/src/gui/guiutility_mac.mm b/src/gui/guiutility_mac.mm index 65e05ab6a..0aa7e114e 100644 --- a/src/gui/guiutility_mac.mm +++ b/src/gui/guiutility_mac.mm @@ -19,6 +19,7 @@ #include #import +#import namespace OCC { @@ -54,9 +55,12 @@ void Utility::startShellIntegration() QString Utility::socketApiSocketPath() { // This must match the code signing Team setting of the extension - // Example for developer builds (with ad-hoc signing identity): "" "com.owncloud.desktopclient" ".socketApi" - // Example for official signed packages: "9B5WD74GWJ." "com.owncloud.desktopclient" ".socketApi" - return QLatin1String(SOCKETAPI_TEAM_IDENTIFIER_PREFIX "." APPLICATION_REV_DOMAIN ".socketApi"); + // Example for all builds: "9B5WD74GWJ" "." "com.owncloud.desktopclient" + NSString *appGroupId = @SOCKETAPI_TEAM_IDENTIFIER_PREFIX "." APPLICATION_REV_DOMAIN; + + NSURL *container = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:appGroupId]; + NSURL *socketPath = [container URLByAppendingPathComponent:@"GUI.socket" isDirectory:false]; + return QString::fromNSString(socketPath.path); } } // namespace OCC diff --git a/src/gui/socketapi/CMakeLists.txt b/src/gui/socketapi/CMakeLists.txt index 78ce96cfd..0f28db92e 100644 --- a/src/gui/socketapi/CMakeLists.txt +++ b/src/gui/socketapi/CMakeLists.txt @@ -2,7 +2,3 @@ target_sources(owncloudCore PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/socketapi.cpp ${CMAKE_CURRENT_SOURCE_DIR}/socketuploadjob.cpp ) - -if( APPLE ) - target_sources(owncloudCore PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/socketapisocket_mac.mm) -endif() diff --git a/src/gui/socketapi/socketapi.cpp b/src/gui/socketapi/socketapi.cpp index c1dad9184..e83166932 100644 --- a/src/gui/socketapi/socketapi.cpp +++ b/src/gui/socketapi/socketapi.cpp @@ -37,37 +37,30 @@ #include "syncfileitem.h" #include "theme.h" -#include +#include +#include #include -#include -#include -#include -#include -#include -#include +#include +#include #include -#include -#include -#include -#include +#include #include - - -#include #include #include #include -#include -#include - -#include - +#include +#include +#include +#include #include +#include #include +#include +#include +#include +#include -#ifdef Q_OS_MAC -#include -#endif +#include // This is the version that is returned when the client asks for the VERSION. diff --git a/src/gui/socketapi/socketapi.h b/src/gui/socketapi/socketapi.h index 84229b1dd..1fc8e4546 100644 --- a/src/gui/socketapi/socketapi.h +++ b/src/gui/socketapi/socketapi.h @@ -22,7 +22,7 @@ #include "config.h" -#if defined(Q_OS_MAC) +#if defined(Q_OS_MAC) && 0 #include "socketapisocket_mac.h" #else #include diff --git a/src/gui/socketapi/socketapisocket_mac.h b/src/gui/socketapi/socketapisocket_mac.h deleted file mode 100644 index cbacdf028..000000000 --- a/src/gui/socketapi/socketapisocket_mac.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (C) by Jocelyn Turcotte - * - * 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. - */ - -#ifndef SOCKETAPISOCKET_OSX_H -#define SOCKETAPISOCKET_OSX_H - -#include -#include - -class SocketApiServerPrivate; -class SocketApiSocketPrivate; - -class SocketApiSocket : public QIODevice -{ - Q_OBJECT -public: - SocketApiSocket(QObject *parent, SocketApiSocketPrivate *p); - ~SocketApiSocket() override; - - qint64 readData(char *data, qint64 maxlen) override; - qint64 writeData(const char *data, qint64 len) override; - - bool isSequential() const override { return true; } - qint64 bytesAvailable() const override; - bool canReadLine() const override; - -signals: - void disconnected(); - -private: - // Use Qt's p-impl system to hide objective-c types from C++ code including this file - Q_DECLARE_PRIVATE(SocketApiSocket) - QScopedPointer d_ptr; - friend class SocketApiServerPrivate; -}; - -class SocketApiServer : public QObject -{ - Q_OBJECT -public: - SocketApiServer(); - ~SocketApiServer() override; - - void close(); - bool listen(const QString &name); - SocketApiSocket *nextPendingConnection(); - - static bool removeServer(const QString &) { return false; } - -signals: - void newConnection(); - -private: - Q_DECLARE_PRIVATE(SocketApiServer) - QScopedPointer d_ptr; -}; - -#endif // SOCKETAPISOCKET_OSX_H diff --git a/src/gui/socketapi/socketapisocket_mac.mm b/src/gui/socketapi/socketapisocket_mac.mm deleted file mode 100644 index 938494e21..000000000 --- a/src/gui/socketapi/socketapisocket_mac.mm +++ /dev/null @@ -1,273 +0,0 @@ -/* - * Copyright (C) by Jocelyn Turcotte - * - * 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. - */ - -#include "socketapisocket_mac.h" -#import - -@protocol ChannelProtocol - -- (void)sendMessage:(NSData *)msg; - -@end - -@protocol RemoteEndProtocol - -- (void)registerTransmitter:(id)tx; - -@end - -@interface LocalEnd : NSObject - -@property (atomic) SocketApiSocketPrivate *wrapper; - -- (instancetype)initWithWrapper:(SocketApiSocketPrivate *)wrapper; - -@end - -@interface Server : NSObject - -@property (atomic) SocketApiServerPrivate *wrapper; - -- (instancetype)initWithWrapper:(SocketApiServerPrivate *)wrapper; -- (void)registerClient:(NSDistantObject *)remoteEnd; - -@end - -class SocketApiSocketPrivate -{ -public: - SocketApiSocket *q_ptr; - - SocketApiSocketPrivate(NSDistantObject *remoteEnd); - ~SocketApiSocketPrivate(); - - // release remoteEnd - void disconnectRemote(); - - NSDistantObject *remoteEnd; - LocalEnd *localEnd; - QByteArray inBuffer; - bool isRemoteDisconnected = false; -}; - -class SocketApiServerPrivate -{ -public: - SocketApiServer *q_ptr; - - SocketApiServerPrivate(); - ~SocketApiServerPrivate(); - - QList pendingConnections; - NSConnection *connection; - Server *server; -}; - - -@implementation LocalEnd - -@synthesize wrapper = _wrapper; - -- (instancetype)initWithWrapper:(SocketApiSocketPrivate *)wrapper -{ - self = [super init]; - self.wrapper = wrapper; - return self; -} - -- (void)sendMessage:(NSData *)msg -{ - if (self.wrapper) { - self.wrapper->inBuffer += QByteArray::fromRawNSData(msg); - emit self.wrapper->q_ptr->readyRead(); - } -} - -- (void)connectionDidDie:(NSNotification *)notification -{ - // The NSConnectionDidDieNotification docs say to disconnect from NSConnection here - [[NSNotificationCenter defaultCenter] removeObserver:self]; - - if (self.wrapper) { - self.wrapper->disconnectRemote(); - emit self.wrapper->q_ptr->disconnected(); - } -} -@end - -@implementation Server - -@synthesize wrapper = _wrapper; - -- (instancetype)initWithWrapper:(SocketApiServerPrivate *)wrapper -{ - self = [super init]; - self.wrapper = wrapper; - return self; -} - -- (void)registerClient:(NSDistantObject *)remoteEnd -{ - // This saves a few mach messages that would otherwise be needed to query the interface - [remoteEnd setProtocolForProxy:@protocol(RemoteEndProtocol)]; - - SocketApiServer *server = self.wrapper->q_ptr; - SocketApiSocketPrivate *socketPrivate = new SocketApiSocketPrivate(remoteEnd); - SocketApiSocket *socket = new SocketApiSocket(server, socketPrivate); - self.wrapper->pendingConnections.append(socket); - emit server->newConnection(); - - [remoteEnd registerTransmitter:socketPrivate->localEnd]; -} -@end - - -SocketApiSocket::SocketApiSocket(QObject *parent, SocketApiSocketPrivate *p) - : QIODevice(parent) - , d_ptr(p) -{ - Q_D(SocketApiSocket); - d->q_ptr = this; - open(ReadWrite); -} - -SocketApiSocket::~SocketApiSocket() -{ -} - -qint64 SocketApiSocket::readData(char *data, qint64 maxlen) -{ - Q_D(SocketApiSocket); - qint64 len = std::min(maxlen, static_cast(d->inBuffer.size())); - if (len < 0 || len > std::numeric_limits::max()) { - return -1; - } - - memcpy(data, d->inBuffer.constData(), static_cast(len)); - d->inBuffer.remove(0, static_cast(len)); - return len; -} - -qint64 SocketApiSocket::writeData(const char *data, qint64 len) -{ - Q_D(SocketApiSocket); - if (d->isRemoteDisconnected) { - return -1; - } - - if (len < std::numeric_limits::min() || len > std::numeric_limits::max()) { - return -1; - } - - @try { - // 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. - // Since FinderSync already runs in a separate process, blocking isn't too critical. - NSData *payload = QByteArray::fromRawData(data, static_cast(len)).toRawNSData(); - [d->remoteEnd sendMessage:payload]; - return len; - } @catch (NSException *) { - // connectionDidDie can be notified too late, also interpret any sending exception as a disconnection. - d->disconnectRemote(); - emit disconnected(); - return -1; - } -} - -qint64 SocketApiSocket::bytesAvailable() const -{ - Q_D(const SocketApiSocket); - return d->inBuffer.size() + QIODevice::bytesAvailable(); -} - -bool SocketApiSocket::canReadLine() const -{ - Q_D(const SocketApiSocket); - return d->inBuffer.indexOf('\n', int(pos())) != -1 || QIODevice::canReadLine(); -} - -SocketApiSocketPrivate::SocketApiSocketPrivate(NSDistantObject *remoteEnd) - : remoteEnd(remoteEnd) - , localEnd([[LocalEnd alloc] initWithWrapper:this]) -{ - [remoteEnd retain]; - // (Ab)use our objective-c object just to catch the notification - [[NSNotificationCenter defaultCenter] addObserver:localEnd - selector:@selector(connectionDidDie:) - name:NSConnectionDidDieNotification - object:[remoteEnd connectionForProxy]]; -} - -SocketApiSocketPrivate::~SocketApiSocketPrivate() -{ - 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) -{ - Q_D(SocketApiServer); - d->q_ptr = this; -} - -SocketApiServer::~SocketApiServer() -{ -} - -void SocketApiServer::close() -{ - // Assume we'll be destroyed right after -} - -bool SocketApiServer::listen(const QString &name) -{ - Q_D(SocketApiServer); - // Set the name of the root object - return [d->connection registerName:name.toNSString()]; -} - -SocketApiSocket *SocketApiServer::nextPendingConnection() -{ - Q_D(SocketApiServer); - return d->pendingConnections.takeFirst(); -} - -SocketApiServerPrivate::SocketApiServerPrivate() -{ - // Create the connection and server object to vend over Disributed Objects - connection = [[NSConnection alloc] init]; - server = [[Server alloc] initWithWrapper:this]; - [connection setRootObject:server]; -} - -SocketApiServerPrivate::~SocketApiServerPrivate() -{ - [connection release]; - server.wrapper = nil; - [server release]; -} -- cgit v1.2.3