const json IPCClientPrivate::receiveOne() { char *data = new char[1<<20]; ssize_t recv_size; if ((recv_size = qb_ipcc_event_recv(_qb_conn, data, 1<<20, 500)) < 0) { disconnect(); throw IPCException(IPCException::ProtocolError, "Receive error"); } if (recv_size < (ssize_t)sizeof(struct qb_ipc_response_header)) { disconnect(); throw IPCException(IPCException::ProtocolError, "Message too small"); } const struct qb_ipc_response_header *hdr = \ (const struct qb_ipc_response_header *)data; if (hdr->size != recv_size) { disconnect(); throw IPCException(IPCException::ProtocolError, "Invalid size in header"); } const char *jdata = data + sizeof(struct qb_ipc_response_header); const size_t jsize = recv_size - sizeof(struct qb_ipc_response_header); const std::string json_string(jdata, jsize); const json jobj = json::parse(json_string); delete [] data; return std::move(jobj); }
Socket::Type Socket::getType() const { int family; socklen_t length = sizeof(family); if (::getsockopt(mFD, SOL_SOCKET, SO_DOMAIN, &family, &length)) { if (errno == EBADF) { return Type::INVALID; } else { const std::string msg = "Error getting socket type: " + getSystemErrorMessage(); LOGE(msg); throw IPCException(msg); } } if (family == AF_UNIX || family == AF_LOCAL) { return Type::UNIX; } if (family == AF_INET || family == AF_INET6) { return Type::INET; } return Type::INVALID; }
IPCException IPC::IPCExceptionFromMessage(const MessagePointer& message) { const IPC::Exception* const exception_message = \ reinterpret_cast<const IPC::Exception*>(message.get()); return IPCException(exception_message->context(), exception_message->object(), exception_message->reason(), exception_message->request_id()); }
std::shared_ptr<Socket> Socket::accept() { int sockfd = ::accept(mFD, nullptr, nullptr); if (sockfd == -1) { const std::string msg = "Error in accept: " + getSystemErrorMessage(); LOGE(msg); throw IPCException(msg); } setFdOptions(sockfd); return std::make_shared<Socket>(sockfd); }
int AbstractSharedMemory::getId(const char *fileName, int id, int flags) { key_t clave = ftok (fileName, id); if ( clave == -1 ) { char error[255]; sprintf(error, "Fallo la operacion ftok: %s", strerror(errno)); char className[255]; strcpy(className, "AbstractSharedMemory"); throw IPCException((const char*)className, error); } this->id = shmget( clave, this->getMemorySize() , flags); if ( this->id == -1 ) { char error[255]; sprintf(error, "Fallo la operacion shmget: %s", strerror(errno)); char className[255]; strcpy(className, "AbstractSharedMemory"); throw IPCException((const char*)className, error); } return 0; }
void IPCClientPrivate::connect() { _qb_conn = qb_ipcc_connect("usbguard", 1<<20); if (_qb_conn == nullptr) { throw IPCException(IPCException::ConnectionError, "IPC Connection not established"); } qb_ipcc_fd_get(_qb_conn, &_qb_conn_fd); if (_qb_conn_fd < 0) { qb_ipcc_disconnect(_qb_conn); _qb_conn = nullptr; _qb_conn_fd = -1; throw IPCException(IPCException::ConnectionError, "Bad file descriptor"); } qb_loop_poll_add(_qb_loop, QB_LOOP_HIGH, _qb_conn_fd, POLLIN, this, qbIPCMessageProcessFn); _p_instance.IPCConnected(); return; }
//----------------------------------------------------------------------------- int Semaphore::destroy(void) { int resultado = semctl(this->id, 0, IPC_RMID, (struct semid_ds *) 0); if ( resultado == -1 ) { char error[255]; sprintf(error, "Fallo la operacion semctl (destroy): %s", strerror(errno)); char className[255]; strcpy(className, "Semaphore"); throw IPCException(className, error); } return resultado; }
//----------------------------------------------------------------------------- int Semaphore::getId(char *fileName, int id, int qty, int flags) { char buffer[255]; key_t clave = ftok (fileName, id); if ( clave == -1 ) { char error[255]; sprintf(error, "Fallo la operacion ftok: %s", strerror(errno)); char className[255]; strcpy(className, "Semaphore"); throw IPCException(className, error); } this->id = semget( clave, qty, flags); if ( this->id == -1 ) { char error[255]; sprintf(error, "Fallo la operacion semget: %s", strerror(errno)); char className[255]; strcpy(className, "Semaphore"); throw IPCException(className, error); } return 0; }
int AbstractSharedMemory::attachMemory() { // Me attacho a la memoria dejando al SO que elija donde ubicar la memoria //(atributo en NULL)y para lectura/escritura (atributo en 0) void *shmaddr = shmat(this->id, NULL, 0); if (shmaddr == (void *)-1) { char error[255]; sprintf(error, "Fallo la operacion shmat: %s", strerror(errno)); char className[255]; strcpy(className, "AbstractSharedMemory"); throw IPCException((const char*)className, error); } data = shmaddr; return 0; }
//----------------------------------------------------------------------------- void Semaphore::wait(int numSem) { struct sembuf oper; oper.sem_num = numSem; oper.sem_op = -1; int resultado = semop(this->id, &oper, 1); if (resultado == -1) { char error[255]; sprintf(error, "Fallo la operacion wait: %s", strerror(errno)); char className[255]; strcpy(className, "Semaphore"); throw IPCException(className, error); } }
int AbstractMessageQueue::getId(char *fileName, int id, int flags) { char buffer[255]; key_t clave = ftok (fileName, id); if ( clave == -1 ) { char error[255]; sprintf(error, "Fallo la operacion ftok: %s", strerror(errno)); char className[255]; strcpy(className, "AbstractMessageQueue"); throw IPCException(className, error); } this->id = msgget ( clave ,flags ); if ( this->id == -1 ) { char error[255]; sprintf(error, "Fallo la operacion msgget: %s", strerror(errno)); char className[255]; strcpy(className, "AbstractMessageQueue"); throw IPCException(className, error); } return 0; }
unsigned short Socket::getPort() const { ::sockaddr_storage address = {0, 0, {0}}; ::socklen_t length = sizeof(address); if (::getsockname(mFD, reinterpret_cast<sockaddr*>(&address), &length) != 0) { const std::string msg = "Failed to get socked address: " + getSystemErrorMessage(); LOGE(msg); throw IPCException(msg); } if (length == sizeof(sockaddr_in)) { return ntohs(reinterpret_cast<const sockaddr_in*>(&address)->sin_port); } else { return ntohs(reinterpret_cast<const sockaddr_in6*>(&address)->sin6_port); } }
int Socket::createSocketInternal(const std::string& path) { // Isn't the path too long? if (path.size() >= sizeof(sockaddr_un::sun_path)) { const std::string msg = "Socket's path too long"; LOGE(msg); throw IPCException(msg); } ::sockaddr_un serverAddress; serverAddress.sun_family = AF_UNIX; ::strncpy(serverAddress.sun_path, path.c_str(), path.length() + 1); return getBoundFd(AF_UNIX, SOCK_STREAM, UNIX_SOCKET_PROTOCOL, reinterpret_cast<struct sockaddr*>(&serverAddress), sizeof(struct sockaddr_un)); }
int Socket::getSystemdSocketInternal(const std::string& path) { int n = ::sd_listen_fds(-1 /*Block further calls to sd_listen_fds*/); if (n < 0) { const std::string msg = "sd_listen_fds failed: " + getSystemErrorMessage(-n); LOGE(msg); throw IPCException(msg); } for (int fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; ++fd) { if (0 < ::sd_is_socket_unix(fd, SOCK_STREAM, 1, path.c_str(), 0)) { setFdOptions(fd); return fd; } } LOGW("No usable sockets were passed by systemd."); return -1; }
void IPCClientPrivate::processOne(const json& jobj) { if (!jobj["_e"].is_null()) { processExceptionJSON(jobj); } else if (!jobj["_s"].is_null()) { processSignalJSON(jobj); } else if (!jobj["_r"].is_null()) { processMethodReturnJSON(jobj); } else if (!jobj["_m"].is_null()) { processMethodCallJSON(jobj); } else { disconnect(); throw IPCException(IPCException::ProtocolError, "Unknown message"); } return; }
uint32_t IPCClientPrivate::appendRule(const std::string& rule_spec, uint32_t parent_seqn, uint32_t timeout_sec) { const json jreq = { { "_m", "appendRule" }, { "rule_spec", rule_spec }, { "parent_seqn", parent_seqn }, { "timeout_sec", timeout_sec }, { "_i", IPC::uniqueID() } }; const json jrep = qbIPCSendRecvJSON(jreq); try { const uint32_t retval = jrep["retval"]; return retval; } catch(...) { throw IPCException(IPCException::ProtocolError, "Invalid or missing return value after calling appendRule"); } }
//----------------------------------------------------------------------------- int Semaphore::initializeSemaphore(int numSem, int val) { // Structure used in semctl union semun { int val; // Value for SETVAL struct semid_ds *buf; // Buffer por IPC_STAT, IPC_SET unsigned short *array; // Array for GETALL, SETALL struct semifo *__buf; // Buffer for IPC_INFO(Linux specific) } arg; arg.val = val; int resultado = semctl(this->id, numSem, SETVAL, arg); if ( resultado == -1 ) { char error[255]; sprintf(error, "Fallo la operacion semctl (init): %s", strerror(errno)); char className[255]; strcpy(className, "Semaphore"); throw IPCException(className, error); } return resultado; }
Socket Socket::connectUNIX(const std::string& path, const int timeoutMs) { // Isn't the path too long? if (path.size() >= sizeof(::sockaddr_un::sun_path)) { const std::string msg = "Socket's path too long"; LOGE(msg); throw IPCException(msg); } // Fill address struct ::sockaddr_un serverAddress; serverAddress.sun_family = AF_UNIX; ::strncpy(serverAddress.sun_path, path.c_str(), sizeof(::sockaddr_un::sun_path)); int fd = getConnectedFd(AF_UNIX, SOCK_STREAM, UNIX_SOCKET_PROTOCOL, reinterpret_cast<struct sockaddr*>(&serverAddress), sizeof(struct ::sockaddr_un), timeoutMs); return Socket(fd); }
//----------------------------------------------------------------------- //----------------------------------------------------------------------- void RtSigSet::del (unsigned signum) throw (IPCException) { if (sigdelset(this, SIGRTMIN + signum)) throw IPCException (errno); }
json IPCClientPrivate::qbIPCSendRecvJSON(const json& jval) { if (!isConnected()) { throw IPCException(IPCException::ConnectionError, "Not connected"); } const std::string json_string = jval.dump(); struct qb_ipc_request_header hdr; hdr.id = 0; hdr.size = sizeof hdr + json_string.size(); struct iovec iov[2]; iov[0].iov_base = &hdr; iov[0].iov_len = sizeof hdr; iov[1].iov_base = (void *)json_string.c_str(); iov[1].iov_len = json_string.size(); const uint64_t id = jval["_i"]; /* Lock the return value slot map */ std::unique_lock<std::mutex> rv_map_lock(_rv_map_mutex); /* * Create the promise and future objects. * The promise will be fullfiled by the message * processing handlers after they process * a reply from the server. */ auto& promise = _rv_map[id]; auto future = promise.get_future(); qb_ipcc_sendv(_qb_conn, iov, 2); /* * Unlock the return value map so that the message * processing handler aren't blocked. */ rv_map_lock.unlock(); /* Wait for some time for the reply to be received */ const std::chrono::milliseconds timeout_ms(5*1000); const bool timed_out = \ future.wait_for(timeout_ms) == std::future_status::timeout; json retval; if (!timed_out) { retval = future.get(); } /* Remove the slot from the return value slot map */ rv_map_lock.lock(); _rv_map.erase(id); rv_map_lock.unlock(); if (timed_out) { throw IPCException(IPCException::TransientError, "Timed out while waiting for IPC reply"); } else { /* * We might have caused an exception. Check whether * that's the case and if true, throw it here. */ if (isExceptionJSON(retval)) { throw IPCException(IPCException::ProtocolError, "The remote end sent an exception"); } else { return std::move(retval); } } return json(); }
void IPCClientPrivate::processSignalJSON(const json& jobj) { try { const std::string name = jobj["_s"]; if (name == "DeviceInserted") { const json attributes_json = jobj.at("attributes"); std::map<std::string,std::string> attributes; for (auto it = attributes_json.begin(); it != attributes_json.end(); ++it) { const std::string key = it.key(); const std::string value = it.value(); attributes[key] = value; } std::vector<USBInterfaceType> interfaces; for (auto const& jitem : jobj["interfaces"]) { const std::string type_string = jitem; interfaces.push_back(USBInterfaceType(type_string)); } _p_instance.DeviceInserted(jobj["seqn"], attributes, interfaces, jobj["rule_match"], jobj["rule_seqn"]); } else if (name == "DevicePresent") { const json attributes_json = jobj.at("attributes"); std::map<std::string,std::string> attributes; for (auto it = attributes_json.begin(); it != attributes_json.end(); ++it) { const std::string key = it.key(); const std::string value = it.value(); attributes[key] = value; } std::vector<USBInterfaceType> interfaces; for (auto const& jitem : jobj["interfaces"]) { const std::string type_string = jitem; interfaces.push_back(USBInterfaceType(type_string)); } _p_instance.DevicePresent(jobj["seqn"], attributes, interfaces, Rule::targetFromString(jobj["target"])); } else if (name == "DeviceRemoved") { const json attributes_json = jobj.at("attributes"); std::map<std::string,std::string> attributes; for (auto it = attributes_json.begin(); it != attributes_json.end(); ++it) { const std::string key = it.key(); const std::string value = it.value(); attributes[key] = value; } _p_instance.DeviceRemoved(jobj["seqn"], attributes); } else if (name == "DeviceAllowed") { const json attributes_json = jobj.at("attributes"); std::map<std::string,std::string> attributes; for (auto it = attributes_json.begin(); it != attributes_json.end(); ++it) { const std::string key = it.key(); const std::string value = it.value(); attributes[key] = value; } _p_instance.DeviceAllowed(jobj["seqn"], attributes, jobj["rule_match"], jobj["rule_seqn"]); } else if (name == "DeviceBlocked") { const json attributes_json = jobj.at("attributes"); std::map<std::string,std::string> attributes; for (auto it = attributes_json.begin(); it != attributes_json.end(); ++it) { const std::string key = it.key(); const std::string value = it.value(); attributes[key] = value; } _p_instance.DeviceBlocked(jobj["seqn"], attributes, jobj["rule_match"], jobj["rule_seqn"]); } else if (name == "DeviceRejected") { const json attributes_json = jobj.at("attributes"); std::map<std::string,std::string> attributes; for (auto it = attributes_json.begin(); it != attributes_json.end(); ++it) { const std::string key = it.key(); const std::string value = it.value(); attributes[key] = value; } _p_instance.DeviceRejected(jobj["seqn"], attributes, jobj["rule_match"], jobj["rule_seqn"]); } else { throw 0; } } catch(...) { disconnect(); throw IPCException(IPCException::ProtocolError, "Invalid IPC signal data"); } return; }