bool StopNovad() { bool retSuccess; //Keep the scope of the following Ticket out of the call to Disconnect { Ticket ticket = MessageManager::Instance().StartConversation(IPCSocketFD); ControlMessage killRequest(CONTROL_EXIT_REQUEST); if(!MessageManager::Instance().WriteMessage(ticket, &killRequest)) { LOG(ERROR, "Error sending command to NOVAD (CONTROL_EXIT_REQUEST)", ""); return false; } Message *reply = MessageManager::Instance().ReadMessage(ticket); if(reply->m_messageType == ERROR_MESSAGE && ((ErrorMessage*)reply)->m_errorType == ERROR_TIMEOUT) { LOG(ERROR, "Timeout error when waiting for message reply", ""); delete ((ErrorMessage*)reply); return false; } if(reply->m_messageType != CONTROL_MESSAGE ) { LOG(ERROR, "Received the wrong kind of reply message", ""); reply->DeleteContents(); delete reply; return false; } ControlMessage *killReply = (ControlMessage*)reply; if( killReply->m_controlType != CONTROL_EXIT_REPLY ) { LOG(ERROR, "Received the wrong kind of control message", ""); reply->DeleteContents(); delete reply; return false; } retSuccess = killReply->m_success; delete killReply; LOG(DEBUG, "Call to StopNovad complete", ""); } DisconnectFromNovad(); return retSuccess; }
void *EventDispatcherThread(void *arg) { int ret = event_base_dispatch(libeventBase); if(ret != 0) { stringstream ss; ss << ret; //LOG(DEBUG, "Message loop ended. Error code: " + ss.str(), ""); } else { LOG(DEBUG, "Message loop ended cleanly.", ""); } DisconnectFromNovad(); return NULL; }
bool IsNovadUp(bool tryToConnect) { bool isUp = true; if(tryToConnect) { //If we couldn't connect, then it's definitely not up if(!ConnectToNovad()) { return false; } } //Funny syntax just so I can break; out of the context do { Ticket ticket = MessageManager::Instance().StartConversation(IPCSocketFD); RequestMessage ping(REQUEST_PING); if(!MessageManager::Instance().WriteMessage(ticket, &ping)) { //There was an error in sending the message isUp = false; break; } Message *reply = MessageManager::Instance().ReadMessage(ticket); if(reply->m_messageType == ERROR_MESSAGE && ((ErrorMessage*)reply)->m_errorType == ERROR_TIMEOUT) { LOG(WARNING, "Timeout error when waiting for message reply", ""); reply->DeleteContents(); delete reply; isUp = false; break; } if(reply->m_messageType == ERROR_MESSAGE ) { ErrorMessage *error = (ErrorMessage*)reply; if(error->m_errorType == ERROR_SOCKET_CLOSED) { // This was breaking things during the mess of isNovadUp calls // when the QT GUi starts and connects to novad. If there was some // important reason for it being here that I don't know about, we // might need to put it back and track down why exactly it was // causing problems. //CloseNovadConnection(); } delete error; isUp = false; break; } if(reply->m_messageType != REQUEST_MESSAGE ) { //Received the wrong kind of message reply->DeleteContents(); delete reply; isUp = false; break; } RequestMessage *pong = (RequestMessage*)reply; if(pong->m_requestType != REQUEST_PONG) { //Received the wrong kind of control message pong->DeleteContents(); isUp = false; } delete pong; }while(0); if(isUp == false) { DisconnectFromNovad(); } return isUp; }
bool ConnectToNovad() { if(IsNovadUp(false)) { return true; } DisconnectFromNovad(); //Create new base if(libeventBase == NULL) { evthread_use_pthreads(); libeventBase = event_base_new(); pthread_mutex_init(&bufferevent_mutex, NULL); } //Builds the key path string key = Config::Inst()->GetPathHome(); key += "/config/keys"; key += NOVAD_LISTEN_FILENAME; //Builds the address struct sockaddr_un novadAddress; novadAddress.sun_family = AF_UNIX; memset(novadAddress.sun_path, '\0', sizeof(novadAddress.sun_path)); strncpy(novadAddress.sun_path, key.c_str(), sizeof(novadAddress.sun_path)); { Lock buffereventLock(&bufferevent_mutex); bufferevent = bufferevent_socket_new(libeventBase, -1, BEV_OPT_CLOSE_ON_FREE | BEV_OPT_THREADSAFE | BEV_OPT_UNLOCK_CALLBACKS | BEV_OPT_DEFER_CALLBACKS ); if(bufferevent == NULL) { LOG(ERROR, "Unable to create a socket to Nova", ""); DisconnectFromNovad(); return false; } bufferevent_setcb(bufferevent, MessageManager::MessageDispatcher, NULL, MessageManager::ErrorDispatcher, NULL); if(bufferevent_enable(bufferevent, EV_READ) == -1) { LOG(ERROR, "Unable to enable socket events", ""); return false; } if(bufferevent_socket_connect(bufferevent, (struct sockaddr *)&novadAddress, sizeof(novadAddress)) == -1) { bufferevent = NULL; LOG(DEBUG, "Unable to connect to NOVAD: "+string(strerror(errno))+".", ""); return false; } IPCSocketFD = bufferevent_getfd(bufferevent); if(IPCSocketFD == -1) { LOG(DEBUG, "Unable to connect to Novad: "+string(strerror(errno))+".", ""); bufferevent_free(bufferevent); bufferevent = NULL; return false; } if(evutil_make_socket_nonblocking(IPCSocketFD) == -1) { LOG(DEBUG, "Unable to connect to Novad", "Could not set socket to non-blocking mode"); bufferevent_free(bufferevent); bufferevent = NULL; return false; } MessageManager::Instance().DeleteEndpoint(IPCSocketFD); MessageManager::Instance().StartSocket(IPCSocketFD, bufferevent); } pthread_create(&eventDispatchThread, NULL, EventDispatcherThread, NULL); //Test if the connection is up Ticket ticket = MessageManager::Instance().StartConversation(IPCSocketFD); RequestMessage connectRequest(REQUEST_PING); if(!MessageManager::Instance().WriteMessage(ticket, &connectRequest)) { return false; } Message *reply = MessageManager::Instance().ReadMessage(ticket); if(reply->m_messageType == ERROR_MESSAGE && ((ErrorMessage*)reply)->m_errorType == ERROR_TIMEOUT) { LOG(DEBUG, "Timeout error when waiting for message reply", ""); delete reply; return false; } if(reply->m_messageType != REQUEST_MESSAGE) { stringstream s; s << "Expected message type of REQUEST_MESSAGE but got " << reply->m_messageType; LOG(DEBUG, s.str(), ""); reply->DeleteContents(); delete reply; return false; } RequestMessage *connectionReply = (RequestMessage*)reply; if(connectionReply->m_contents.m_requesttype() != REQUEST_PONG) { stringstream s; s << "Expected control type of CONTROL_CONNECT_REPLY but got " <<connectionReply->m_contents.m_requesttype(); LOG(DEBUG, s.str(), ""); reply->DeleteContents(); delete reply; return false; } delete connectionReply; return true; }