//-------------------------------------------------------------------------------------------------- static bool AreServiceIdsTheSame ( const void* firstKeyPtr, const void* secondKeyPtr ) //-------------------------------------------------------------------------------------------------- { const ServiceId_t* firstIdPtr = firstKeyPtr; const ServiceId_t* secondIdPtr = secondKeyPtr; return ( le_hashmap_EqualsString(firstIdPtr->name, secondIdPtr->name) && le_hashmap_EqualsString(le_msg_GetProtocolIdStr(firstIdPtr->protocolRef), le_msg_GetProtocolIdStr(secondIdPtr->protocolRef)) ); }
//-------------------------------------------------------------------------------------------------- le_msg_SessionEventHandlerRef_t le_msg_AddServiceCloseHandler ( le_msg_ServiceRef_t serviceRef, ///< [in] Reference to the service. le_msg_SessionEventHandler_t handlerFunc,///< [in] Handler function. void* contextPtr ///< [in] Opaque pointer value to pass to handler. ) //-------------------------------------------------------------------------------------------------- { LE_FATAL_IF(serviceRef == NULL, "Service doesn't exist. Make sure service is started before setting handlers"); LE_FATAL_IF(serviceRef->serverThread != le_thread_GetCurrent(), "Service (%s:%s) not owned by calling thread.", serviceRef->id.name, le_msg_GetProtocolIdStr(serviceRef->id.protocolRef)); // Create the node. SessionEventHandler_t* closeEventPtr = le_mem_ForceAlloc(HandlerEventPoolRef); // Initialize the node. closeEventPtr->handler = handlerFunc; closeEventPtr->contextPtr = contextPtr; closeEventPtr->link = LE_DLS_LINK_INIT; closeEventPtr->listPtr = &serviceRef->closeListPtr; // Add the node to the head of the list by passing in the node's link. le_dls_Stack(&serviceRef->closeListPtr, &closeEventPtr->link); // Need to return a unique reference that will be used by the remove function. closeEventPtr->ref = le_ref_CreateRef(HandlersRefMap, &closeEventPtr->link); return closeEventPtr->ref; }
//-------------------------------------------------------------------------------------------------- void le_msg_DeleteService ( le_msg_ServiceRef_t serviceRef ///< [in] Reference to the service. ) //-------------------------------------------------------------------------------------------------- { LE_FATAL_IF(serviceRef->serverThread != le_thread_GetCurrent(), "Attempted to delete service (%s:%s) not owned by thread.", serviceRef->id.name, le_msg_GetProtocolIdStr(serviceRef->id.protocolRef)); // If the service is still advertised, hide it. le_msg_HideService(serviceRef); // Close any remaining open sessions. CloseAllSessions(serviceRef); // NOTE: Lock the mutex here to prevent a race between this thread dropping ownership // of the service and another thread trying to offer the same service. This is very // unlikely to ever happen, but just in case, make sure it fails with a sensible // ("duplicate") log message, instead of just quietly messing up the hashmap or something. LOCK // Clear out the server thread reference. serviceRef->serverThread = NULL; // Release the server's hold on the object. le_mem_Release(serviceRef); UNLOCK }
//-------------------------------------------------------------------------------------------------- le_msg_ServiceRef_t le_msg_CreateService ( le_msg_ProtocolRef_t protocolRef, ///< [in] Reference to the protocol to be used. const char* serviceName ///< [in] The service instance name. ) //-------------------------------------------------------------------------------------------------- { // Must lock the mutex to prevent races between different threads trying to offer the // same service at the same time, or one thread trying to delete a service while another // tries to create it, or accessing the Service List hashmap while another thread // is updating it. LOCK // Get a Service object. Service_t* servicePtr = GetService(protocolRef, serviceName); // If the Service object already has a server thread, then it means that this service // is already being offered by someone else in this very process. LE_FATAL_IF(servicePtr->serverThread != NULL, "Duplicate service (%s:%s) offered in same process.", serviceName, le_msg_GetProtocolIdStr(protocolRef)); servicePtr->serverThread = le_thread_GetCurrent(); UNLOCK return servicePtr; }
//-------------------------------------------------------------------------------------------------- void msgService_ProcessMessageFromClient ( le_msg_ServiceRef_t serviceRef, ///< [IN] Reference to the Service object. le_msg_MessageRef_t msgRef ///< [IN] Message reference for the received message. ) //-------------------------------------------------------------------------------------------------- { // Pass the message to the server's registered receive handler, if there is one. if (serviceRef->recvHandler != NULL) { // Set the thread-local received message reference so it can be retrieved by the handler. pthread_setspecific(ThreadLocalRxMsgKey, msgRef); // Call the handler function. serviceRef->recvHandler(msgRef, serviceRef->recvContextPtr); // Clear the thread-local reference. pthread_setspecific(ThreadLocalRxMsgKey, NULL); } // Discard the message if no handler is registered. else { LE_WARN("No service receive handler (%s:%s). Discarding message. Closing session.", serviceRef->id.name, le_msg_GetProtocolIdStr(serviceRef->id.protocolRef)); le_msg_DeleteSession(le_msg_GetSession(msgRef)); le_msg_ReleaseMsg(msgRef); } }
//-------------------------------------------------------------------------------------------------- void msgService_SendServiceId ( le_msg_ServiceRef_t serviceRef, ///< [in] Pointer to the service whose ID is to be sent. int socketFd ///< [in] File descriptor of the connected socket to send on. ) //-------------------------------------------------------------------------------------------------- { svcdir_ServiceId_t serviceId; memset(&serviceId, 0, sizeof(serviceId)); serviceId.maxProtocolMsgSize = le_msg_GetProtocolMaxMsgSize(serviceRef->id.protocolRef); le_utf8_Copy(serviceId.protocolId, le_msg_GetProtocolIdStr(serviceRef->id.protocolRef), sizeof(serviceId.protocolId), NULL); le_utf8_Copy(serviceId.serviceName, serviceRef->id.name, sizeof(serviceId.serviceName), NULL); le_result_t result = unixSocket_SendDataMsg(socketFd, &serviceId, sizeof(serviceId)); if (result != LE_OK) { LE_FATAL("Failed to send. Result = %d (%s)", result, LE_RESULT_TXT(result)); } // NOTE: This is only done when the socket is newly opened, so this shouldn't ever // return LE_NO_MEMORY to indicate send buffers being full. }
//-------------------------------------------------------------------------------------------------- static void StartMonitoringDirectorySocket ( Service_t* servicePtr ) //-------------------------------------------------------------------------------------------------- { le_event_FdHandlerRef_t handlerRef; char name[128]; size_t bytes; le_utf8_Copy(name, le_msg_GetProtocolIdStr(servicePtr->id.protocolRef), sizeof(name), &bytes); le_utf8_Copy(name + bytes, servicePtr->id.name, sizeof(name) - bytes, NULL); servicePtr->fdMonitorRef = le_event_CreateFdMonitor(name, servicePtr->directorySocketFd); handlerRef = le_event_SetFdHandler(servicePtr->fdMonitorRef, LE_EVENT_FD_READABLE, DirectorySocketReadable); le_event_SetFdHandlerContextPtr(handlerRef, servicePtr); handlerRef = le_event_SetFdHandler(servicePtr->fdMonitorRef, LE_EVENT_FD_READ_HANG_UP, DirectorySocketClosed); le_event_SetFdHandlerContextPtr(handlerRef, servicePtr); handlerRef = le_event_SetFdHandler(servicePtr->fdMonitorRef, LE_EVENT_FD_WRITE_HANG_UP, DirectorySocketClosed); le_event_SetFdHandlerContextPtr(handlerRef, servicePtr); handlerRef = le_event_SetFdHandler(servicePtr->fdMonitorRef, LE_EVENT_FD_ERROR, DirectorySocketError); le_event_SetFdHandlerContextPtr(handlerRef, servicePtr); }
//-------------------------------------------------------------------------------------------------- void le_msg_AdvertiseService ( le_msg_ServiceRef_t serviceRef ///< [in] Reference to the service. ) //-------------------------------------------------------------------------------------------------- { LE_FATAL_IF(serviceRef->state != LE_MSG_SERVICE_HIDDEN, "Re-advertising before hiding service '%s:%s'.", serviceRef->id.name, le_msg_GetProtocolIdStr(serviceRef->id.protocolRef)); serviceRef->state = LE_MSG_SERVICE_CONNECTING; // Open a socket. int fd = unixSocket_CreateSeqPacketUnnamed(); serviceRef->directorySocketFd = fd; // Check for failure. LE_FATAL_IF(fd == LE_NOT_PERMITTED, "Permission to open socket denied."); LE_FATAL_IF(fd == LE_FAULT, "Failed to open socket."); // Warn if one of the three standard I/O streams have been somehow connected to the // Service Directory. if (fd < 3) { const char* streamNameStr; switch (fd) { case 0: streamNameStr = "stdin"; break; case 1: streamNameStr = "stdout"; break; case 2: streamNameStr = "stderr"; break; } LE_WARN("Service Directory connection mapped to %s.", streamNameStr); } // Set the socket non-blocking. fd_SetNonBlocking(fd); // Start monitoring the socket for events. StartMonitoringDirectorySocket(serviceRef); // Connect the socket to the Service Directory. le_result_t result = unixSocket_Connect(fd, LE_SVCDIR_SERVER_SOCKET_NAME); LE_FATAL_IF((result != LE_OK) && (result != LE_WOULD_BLOCK), "Failed to connect to Service Directory. Result = %d (%s).", result, LE_RESULT_TXT(result)); // Wait for writeability notification on the socket. See DirectorySocketWriteable(). }
//-------------------------------------------------------------------------------------------------- static void DirectorySocketError ( int fd ) //-------------------------------------------------------------------------------------------------- { Service_t* servicePtr = le_event_GetContextPtr(); LE_FATAL("Error on Service Directory connection for service (%s:%s).", servicePtr->id.name, le_msg_GetProtocolIdStr(servicePtr->id.protocolRef)); }
//-------------------------------------------------------------------------------------------------- static void DirectorySocketClosed ( int fd ) //-------------------------------------------------------------------------------------------------- { Service_t* servicePtr = le_event_GetContextPtr(); LE_FATAL("Permission to offer service (%s:%s) has been denied.", servicePtr->id.name, le_msg_GetProtocolIdStr(servicePtr->id.protocolRef)); }
//-------------------------------------------------------------------------------------------------- void le_msg_SetServiceRecvHandler ( le_msg_ServiceRef_t serviceRef, ///< [in] Reference to the service. le_msg_ReceiveHandler_t handlerFunc,///< [in] Handler function. void* contextPtr ///< [in] Opaque pointer value to pass to the handler. ) //-------------------------------------------------------------------------------------------------- { LE_FATAL_IF(serviceRef->serverThread != le_thread_GetCurrent(), "Service (%s:%s) not owned by calling thread.", serviceRef->id.name, le_msg_GetProtocolIdStr(serviceRef->id.protocolRef)); serviceRef->recvHandler = handlerFunc; serviceRef->recvContextPtr = contextPtr; }
//-------------------------------------------------------------------------------------------------- static void StartMonitoringDirectorySocket ( Service_t* servicePtr ) //-------------------------------------------------------------------------------------------------- { le_event_FdHandlerRef_t handlerRef; char name[LIMIT_MAX_MEM_POOL_NAME_BYTES]; char* destPtr = name; size_t spaceLeft = sizeof(name); size_t bytesCopied; le_utf8_Copy(destPtr, servicePtr->id.name, spaceLeft, &bytesCopied); destPtr += bytesCopied; spaceLeft -= bytesCopied; le_utf8_Copy(destPtr, ":", spaceLeft, &bytesCopied); destPtr += bytesCopied; spaceLeft -= bytesCopied; le_utf8_Copy(destPtr, le_msg_GetProtocolIdStr(servicePtr->id.protocolRef), spaceLeft, NULL); servicePtr->fdMonitorRef = le_event_CreateFdMonitor(name, servicePtr->directorySocketFd); handlerRef = le_event_SetFdHandler(servicePtr->fdMonitorRef, LE_EVENT_FD_WRITEABLE, DirectorySocketWriteable); le_event_SetFdHandlerContextPtr(handlerRef, servicePtr); handlerRef = le_event_SetFdHandler(servicePtr->fdMonitorRef, LE_EVENT_FD_READABLE, DirectorySocketReadable); le_event_SetFdHandlerContextPtr(handlerRef, servicePtr); handlerRef = le_event_SetFdHandler(servicePtr->fdMonitorRef, LE_EVENT_FD_READ_HANG_UP, DirectorySocketClosed); le_event_SetFdHandlerContextPtr(handlerRef, servicePtr); handlerRef = le_event_SetFdHandler(servicePtr->fdMonitorRef, LE_EVENT_FD_WRITE_HANG_UP, DirectorySocketClosed); le_event_SetFdHandlerContextPtr(handlerRef, servicePtr); handlerRef = le_event_SetFdHandler(servicePtr->fdMonitorRef, LE_EVENT_FD_ERROR, DirectorySocketError); le_event_SetFdHandlerContextPtr(handlerRef, servicePtr); }
//-------------------------------------------------------------------------------------------------- static void DirectorySocketReadable ( int fd ) //-------------------------------------------------------------------------------------------------- { Service_t* servicePtr = le_event_GetContextPtr(); le_result_t result; int clientSocketFd; // Receive the Client connection file descriptor from the Service Directory. result = unixSocket_ReceiveMsg(fd, NULL, // dataBuffPtr 0, // dataBuffSize &clientSocketFd, NULL); // credPtr if (result == LE_CLOSED) { LE_DEBUG("Connection has closed."); } else if (result != LE_OK) { LE_FATAL("Failed to receive client fd from Service Directory (%d: %s).", result, LE_RESULT_TXT(result)); } else if (clientSocketFd < 0) { LE_ERROR("Received something other than a file descriptor from Service Directory for (%s:%s).", servicePtr->id.name, le_msg_GetProtocolIdStr(servicePtr->id.protocolRef)); } else { // Create a server-side Session object for that connection to this Service. le_msg_SessionRef_t sessionRef = msgSession_CreateServerSideSession(servicePtr, clientSocketFd); // If successful, call the registered "open" handler, if there is one. if (sessionRef != NULL) { CallOpenHandler(servicePtr, sessionRef); } } }