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 LOG( logERROR ) << "attach failed!"; 48 throw CantCreateExternalErr(); 49 } 50 51 #ifdef Q_OS_UNIX 52 // Handle any further termination signals to ensure the 53 // QSharedMemory block is deleted even if the process crashes 54 setCrashHandler(memory_); 55 #endif 56 } 57 58 void SocketExternalInstance::loadFile(const QString &file_name) const 59 { 60 QLocalSocket socket; 61 socket.connectToServer(GLOG_SERVICE_NAME); 62 if (!socket.waitForConnected(1000)) { 63 LOG( logERROR ) << "Failed to connect to socket"; 64 return; 65 } 66 67 socket.write(file_name.toUtf8()); 68 if (!socket.waitForBytesWritten(1000)) { 69 LOG( logERROR ) << "Failed to send filename"; 70 } 71 72 socket.close(); 73 } 74 75 uint32_t SocketExternalInstance::getVersion() const 76 { 77 return *reinterpret_cast<uint32_t*>(memory_->data()); 78 } 79 80 SocketExternalCommunicator::SocketExternalCommunicator() 81 : ExternalCommunicator() 82 , memory_(new QSharedMemory(GLOG_SERVICE_NAME)) 83 , server_(new QLocalServer) 84 {} 85 86 SocketExternalCommunicator::~SocketExternalCommunicator() 87 { 88 delete memory_; 89 server_->close(); 90 delete server_; 91 } 92 93 void SocketExternalCommunicator::startListening() 94 { 95 if ( memory_->create(sizeof(qint32))) { 96 #ifdef Q_OS_UNIX 97 // Handle any further termination signals to ensure the 98 // QSharedMemory block is deleted even if the process crashes 99 setCrashHandler(memory_); 100 #endif 101 102 *reinterpret_cast<qint32*>(memory_->data()) = version(); 103 QLocalServer::removeServer(GLOG_SERVICE_NAME); 104 105 connect(server_, SIGNAL(newConnection()), SLOT(onConnection())); 106 server_->listen(GLOG_SERVICE_NAME); 107 } 108 } 109 110 qint32 SocketExternalCommunicator::version() const 111 { 112 return 3; 113 } 114 115 ExternalInstance* SocketExternalCommunicator::otherInstance() const 116 { 117 try { 118 return static_cast<ExternalInstance*>( new SocketExternalInstance() ); 119 } 120 catch ( CantCreateExternalErr ) { 121 LOG(logINFO) << "Cannot find external correspondant, we are the only glogg out there."; 122 return nullptr; 123 } 124 } 125 126 void SocketExternalCommunicator::onConnection() 127 { 128 QLocalSocket *socket = server_->nextPendingConnection(); 129 QByteArray data; 130 while(socket->waitForReadyRead(100)) { 131 data.append(socket->readAll()); 132 } 133 134 socket->close(); 135 136 emit loadFile(QString::fromUtf8(data)); 137 } 138 139 140 141