1 #include "socketexternalcom.h" 2 3 #include <QLocalServer> 4 #include <QLocalSocket> 5 #include <QSharedMemory> 6 7 #ifdef Q_OS_UNIX 8 #include <signal.h> 9 #include <unistd.h> 10 #endif 11 12 #include "log.h" 13 14 static const char* GLOG_SERVICE_NAME = "org.bonnefon.glogg"; 15 16 #ifdef Q_OS_UNIX 17 QSharedMemory* g_staticSharedMemory = nullptr; 18 19 void terminate(int signum) 20 { 21 if (g_staticSharedMemory) { 22 delete g_staticSharedMemory; 23 } 24 ::exit(128 + signum); 25 } 26 27 void setCrashHandler(QSharedMemory* memory) 28 { 29 g_staticSharedMemory = memory; 30 31 // Handle any further termination signals to ensure the 32 // QSharedMemory block is deleted even if the process crashes 33 signal(SIGSEGV, terminate); 34 signal(SIGABRT, terminate); 35 signal(SIGFPE, terminate); 36 signal(SIGILL, terminate); 37 signal(SIGINT, terminate); 38 signal(SIGTERM, terminate); 39 } 40 41 #endif 42 43 SocketExternalInstance::SocketExternalInstance() 44 : ExternalInstance(), memory_(new QSharedMemory(GLOG_SERVICE_NAME) ) 45 { 46 if ( !memory_->attach( QSharedMemory::ReadOnly ) ) { 47 throw CantCreateExternalErr(); 48 } 49 50 #ifdef Q_OS_UNIX 51 // Handle any further termination signals to ensure the 52 // QSharedMemory block is deleted even if the process crashes 53 setCrashHandler(memory_); 54 #endif 55 } 56 57 void SocketExternalInstance::loadFile(const QString &file_name) const 58 { 59 QLocalSocket socket; 60 socket.connectToServer(GLOG_SERVICE_NAME); 61 if (!socket.waitForConnected(1000)) { 62 LOG( logERROR ) << "Failed to connect to socket"; 63 return; 64 } 65 66 socket.write(file_name.toUtf8()); 67 if (!socket.waitForBytesWritten(1000)) { 68 LOG( logERROR ) << "Failed to send filename"; 69 } 70 71 socket.close(); 72 } 73 74 uint32_t SocketExternalInstance::getVersion() const 75 { 76 return *reinterpret_cast<uint32_t*>(memory_->data()); 77 } 78 79 SocketExternalCommunicator::SocketExternalCommunicator() 80 : ExternalCommunicator() 81 , memory_(new QSharedMemory(GLOG_SERVICE_NAME)) 82 , server_(new QLocalServer) 83 {} 84 85 SocketExternalCommunicator::~SocketExternalCommunicator() 86 { 87 delete memory_; 88 server_->close(); 89 delete server_; 90 } 91 92 void SocketExternalCommunicator::startListening() 93 { 94 if ( memory_->create(sizeof(qint32))) { 95 #ifdef Q_OS_UNIX 96 // Handle any further termination signals to ensure the 97 // QSharedMemory block is deleted even if the process crashes 98 setCrashHandler(memory_); 99 #endif 100 101 *reinterpret_cast<qint32*>(memory_->data()) = version(); 102 QLocalServer::removeServer(GLOG_SERVICE_NAME); 103 104 connect(server_, SIGNAL(newConnection()), SLOT(onConnection())); 105 server_->listen(GLOG_SERVICE_NAME); 106 } 107 } 108 109 qint32 SocketExternalCommunicator::version() const 110 { 111 return 3; 112 } 113 114 ExternalInstance* SocketExternalCommunicator::otherInstance() const 115 { 116 try { 117 return static_cast<ExternalInstance*>( new SocketExternalInstance() ); 118 } 119 catch ( CantCreateExternalErr ) { 120 LOG(logINFO) << "Cannot find external correspondant, we are the only glogg out there."; 121 return nullptr; 122 } 123 } 124 125 void SocketExternalCommunicator::onConnection() 126 { 127 QLocalSocket *socket = server_->nextPendingConnection(); 128 QByteArray data; 129 while(socket->waitForReadyRead(100)) { 130 data.append(socket->readAll()); 131 } 132 133 socket->close(); 134 135 emit loadFile(QString::fromUtf8(data)); 136 } 137 138 139 140