void
ProxyGateway_DoWork (
    REMOTE_MODULE_HANDLE remote_module
) {
    if (NULL == remote_module) {
        /* Codes_SRS_PROXY_GATEWAY_027_026: [Prerequisite Check - If the `remote_module` parameter is `NULL`, then `ProxyGateway_DoWork` shall do nothing] */
        LogError("%s: NULL parameter - remote_module!", __FUNCTION__);
    } else {
        int32_t bytes_received;
        void * control_message = NULL;

        /* Codes_SRS_PROXY_GATEWAY_027_027: [Control Channel - `ProxyGateway_DoWork` shall poll the gateway control channel by calling `int nn_recv(int s, void * buf, size_t len, int flags)` with the control socket for `s`, `NULL` for `buf`, `NN_MSG` for `len` and NN_DONTWAIT for `flags`] */
        if (0 > (bytes_received = nn_recv(remote_module->control_socket, &control_message, NN_MSG, NN_DONTWAIT))) {
            if (EAGAIN == nn_errno()) {
                /* Codes_SRS_PROXY_GATEWAY_027_028: [Control Channel - If no message is available, then `ProxyGateway_DoWork` shall abandon the control channel request] */
            } else {
                /* Codes_SRS_PROXY_GATEWAY_027_066: [Control Channel - If an error occurred when polling the gateway, then `ProxyGateway_DoWork` shall signal the gateway abandon the control channel request] */
                LogError("%s: Unexpected error received from the control channel!", __FUNCTION__);
                (void)send_control_reply(remote_module, (uint8_t)REMOTE_MODULE_GATEWAY_CONNECTION_ERROR);
            }
        } else {
            CONTROL_MESSAGE * structured_control_message;

            /* Codes_SRS_PROXY_GATEWAY_027_029: [Control Channel - If a control message was received, then `ProxyGateway_DoWork` will parse that message by calling `CONTROL_MESSAGE * ControlMessage_CreateFromByteArray(const unsigned char * source, size_t size)` with the buffer received from `nn_recv` as `source` and return value from `nn_recv` as `size`] */
            if (NULL == (structured_control_message = ControlMessage_CreateFromByteArray((const unsigned char *)control_message, bytes_received))) {
                /* Codes_SRS_PROXY_GATEWAY_027_030: [Control Channel - If unable to parse the control message, then `ProxyGateway_DoWork` shall signal the gateway, free any previously allocated memory and abandon the control channel request] */
                LogError("%s: Unable to parse control message!", __FUNCTION__);
                (void)send_control_reply(remote_module, (uint8_t)REMOTE_MODULE_GATEWAY_CONNECTION_ERROR);
            } else {
                // Route control channel messages to appropriate functions
                switch (structured_control_message->type) {
                  case CONTROL_MESSAGE_TYPE_MODULE_CREATE:
                    /* Codes_SRS_PROXY_GATEWAY_027_031: [Control Channel - If the message type is CONTROL_MESSAGE_TYPE_MODULE_CREATE, then `ProxyGateway_DoWork` shall process the create message] */
                    if (0 != process_module_create_message(remote_module, (const CONTROL_MESSAGE_MODULE_CREATE *)structured_control_message)) {
                        LogError("%s: Unable to process create message!", __FUNCTION__);
                    }
                    break;
                  case CONTROL_MESSAGE_TYPE_MODULE_START:
                    /* Codes_SRS_PROXY_GATEWAY_027_032: [Control Channel - If the message type is CONTROL_MESSAGE_TYPE_MODULE_START and `Module_Start` was provided, then `ProxyGateway_DoWork` shall call `void Module_Start(MODULE_HANDLE moduleHandle)`] */
                    if (((MODULE_API_1 *)remote_module->module.module_apis)->Module_Start) {
                        ((MODULE_API_1 *)remote_module->module.module_apis)->Module_Start(remote_module->module.module_handle);
                    }
                    break;
                  case CONTROL_MESSAGE_TYPE_MODULE_DESTROY:
                    /* Codes_SRS_PROXY_GATEWAY_027_033: [Control Channel - If the message type is CONTROL_MESSAGE_TYPE_MODULE_DESTROY, then `ProxyGateway_DoWork` shall call `void Module_Destroy(MODULE_HANDLE moduleHandle)`] */
                    ((MODULE_API_1 *)remote_module->module.module_apis)->Module_Destroy(remote_module->module.module_handle);
                    remote_module->module.module_handle = NULL;
                    /* Codes_SRS_PROXY_GATEWAY_027_034: [Control Channel - If the message type is CONTROL_MESSAGE_TYPE_MODULE_DESTROY, then `ProxyGateway_DoWork` shall disconnect from the message channel] */
                    disconnect_from_message_channel(remote_module);
                    break;
                  default: LogError("ERROR: REMOTE_MODULE - Received unsupported message type! [%d]\n", structured_control_message->type); break;
                }
                /* Codes_SRS_PROXY_GATEWAY_027_035: [Control Channel - `ProxyGateway_DoWork` shall free the resources held by the parsed control message by calling `void ControlMessage_Destroy(CONTROL_MESSAGE * message)` using the parsed control message as `message`] */
                ControlMessage_Destroy(structured_control_message);
            }
            /* Codes_SRS_PROXY_GATEWAY_027_036: [Control Channel - `ProxyGateway_DoWork` shall free the resources held by the gateway message by calling `int nn_freemsg(void * msg)` with the resulting buffer from the previous call to `nn_recv`] */
            (void)nn_freemsg(control_message);
        }

        /* Codes_SRS_PROXY_GATEWAY_027_037: [Message Channel - `ProxyGateway_DoWork` shall not check for messages, if the message socket is not available] */
        if ( 0 > remote_module->message_socket ) {
            // not connected to message channel
        } else {
            void * module_message = NULL;

            /* Codes_SRS_PROXY_GATEWAY_027_038: [Message Channel - `ProxyGateway_DoWork` shall poll the gateway message channel by calling `int nn_recv(int s, void * buf, size_t len, int flags)` with each message socket for `s`, `NULL` for `buf`, `NN_MSG` for `len` and NN_DONTWAIT for `flags`] */
            if (0 > (bytes_received = nn_recv(remote_module->message_socket, &module_message, NN_MSG, NN_DONTWAIT))) {
                /* Codes_SRS_PROXY_GATEWAY_027_039: [Message Channel - If no message is available or an error occurred, then `ProxyGateway_DoWork` shall abandon the message channel request] */
                if (EAGAIN == nn_errno()) {
                    // no messages available at this time
                } else {
                    LogError("%s: Unexpected error received from the message channel!", __FUNCTION__);
                }
            } else {
                MESSAGE_HANDLE structured_module_message;

                /* Codes_SRS_PROXY_GATEWAY_027_040: [Message Channel - If a module message was received, then `ProxyGateway_DoWork` will parse that message by calling `MESSAGE_HANDLE Message_CreateFromByteArray(const unsigned char * source, int32_t size)` with the buffer received from `nn_recv` as `source` and return value from `nn_recv` as `size`] */
                if (NULL == (structured_module_message = Message_CreateFromByteArray((const unsigned char *)module_message, bytes_received))) {
                    /* Codes_SRS_PROXY_GATEWAY_027_041: [Message Channel - If unable to parse the module message, then `ProxyGateway_DoWork` shall free any previously allocated memory and abandon the message channel request] */
                    LogError("%s: Unable to parse control message!", __FUNCTION__);
                } else {
                    /* Codes_SRS_PROXY_GATEWAY_027_042: [Message Channel - `ProxyGateway_DoWork` shall pass the structured message to the module by calling `void Module_Receive(MODULE_HANDLE moduleHandle)` using the parsed message as `moduleHandle`] */
                    ((MODULE_API_1 *)remote_module->module.module_apis)->Module_Receive(remote_module->module.module_handle, structured_module_message);
                    /* Codes_SRS_PROXY_GATEWAY_027_043: [Message Channel - `ProxyGateway_DoWork` shall free the resources held by the parsed module message by calling `void Message_Destroy(MESSAGE_HANDLE * message)` using the parsed module message as `message`] */
                    Message_Destroy(structured_module_message);
                }
                /* Codes_SRS_PROXY_GATEWAY_027_044: [Message Channel - `ProxyGateway_DoWork` shall free the resources held by the gateway message by calling `int nn_freemsg(void * msg)` with the resulting buffer from the previous call to `nn_recv`] */
                (void)nn_freemsg(module_message);
            }
        }
    }

    return;
}
/**
* This function runs for each module. It receives a pointer to a MODULE_INFO
* object that describes the module. Its job is to call the Receive function on
* the associated module whenever it receives a message.
*/
static int module_worker(void * user_data)
{
    /*Codes_SRS_BROKER_13_026: [This function shall assign `user_data` to a local variable called `module_info` of type `BROKER_MODULEINFO*`.]*/
    BROKER_MODULEINFO* module_info = (BROKER_MODULEINFO*)user_data;

    int should_continue = 1;
    while (should_continue)
    {
        /*Codes_SRS_BROKER_13_089: [ This function shall acquire the lock on module_info->socket_lock. ]*/
        if (Lock(module_info->socket_lock))
        {
            /*Codes_SRS_BROKER_02_004: [ If acquiring the lock fails, then module_worker shall return. ]*/
            LogError("unable to Lock");
            should_continue = 0;
            break;
        }
        int nn_fd = module_info->receive_socket;
        int nbytes;
        unsigned char *buf = NULL;

        /*Codes_SRS_BROKER_17_005: [ For every iteration of the loop, the function shall wait on the receive_socket for messages. ]*/
        nbytes = nn_recv(nn_fd, (void *)&buf, NN_MSG, 0);
        /*Codes_SRS_BROKER_13_091: [ The function shall unlock module_info->socket_lock. ]*/
        if (Unlock(module_info->socket_lock) != LOCK_OK)
        {
            /*Codes_SRS_BROKER_17_016: [ If releasing the lock fails, then module_worker shall return. ]*/
            should_continue = 0;
            if (nbytes > 0)
            {
                /*Codes_SRS_BROKER_17_019: [ The function shall free the buffer received on the receive_socket. ]*/
                nn_freemsg(buf);
            }
            break;
        }

        if (nbytes < 0)
        {
            /*Codes_SRS_BROKER_17_006: [ An error on receiving a message shall terminate the loop. ]*/
            should_continue = 0;
        }
        else
        {
            if (nbytes == BROKER_GUID_SIZE &&
                (strncmp(STRING_c_str(module_info->quit_message_guid), (const char *)buf, BROKER_GUID_SIZE-1)==0))
            {
                /*Codes_SRS_BROKER_13_068: [ This function shall run a loop that keeps running until module_info->quit_message_guid is sent to the thread. ]*/
                /* received special quit message for this module */
                should_continue = 0;
            }
            else
            {
                /*Codes_SRS_BROKER_17_024: [ The function shall strip off the topic from the message. ]*/
                const unsigned char*buf_bytes = (const unsigned char*)buf;
                buf_bytes += sizeof(MODULE_HANDLE);
                /*Codes_SRS_BROKER_17_017: [ The function shall deserialize the message received. ]*/
                MESSAGE_HANDLE msg = Message_CreateFromByteArray(buf_bytes, nbytes - sizeof(MODULE_HANDLE));
                /*Codes_SRS_BROKER_17_018: [ If the deserialization is not successful, the message loop shall continue. ]*/
                if (msg != NULL)
                {
                    /*Codes_SRS_BROKER_13_092: [The function shall deliver the message to the module's callback function via module_info->module_apis. ]*/
                    MODULE_RECEIVE(module_info->module->module_apis)(module_info->module->module_handle, msg);
                    /*Codes_SRS_BROKER_13_093: [ The function shall destroy the message that was dequeued by calling Message_Destroy. ]*/
                    Message_Destroy(msg);
                }
            }
            /*Codes_SRS_BROKER_17_019: [ The function shall free the buffer received on the receive_socket. ]*/
            nn_freemsg(buf);
        }    
    }

    return 0;
}
int outprocessIncomingMessageThread(void *param)
{
	/*Codes_SRS_OUTPROCESS_MODULE_17_037: [ This function shall receive the module handle data as the thread parameter. ]*/
	OUTPROCESS_HANDLE_DATA * handleData = (OUTPROCESS_HANDLE_DATA*)param;
	if (handleData == NULL)
	{
		LogError("outprocess thread: parameter is NULL");
	}
	else
	{
		int should_continue = 1;

		while (should_continue)
		{
			/*Codes_SRS_OUTPROCESS_MODULE_17_036: [ This function shall ensure thread safety on execution. ]*/
			if (Lock(handleData->handle_lock) != LOCK_OK)
			{
				LogError("unable to Lock handle data");
				should_continue = 0;
				break;
			}
			int nn_fd = handleData->message_socket;
			if (Unlock(handleData->handle_lock) != LOCK_OK)
			{
				should_continue = 0;
				break;
			}

			/*Codes_SRS_OUTPROCESS_MODULE_17_036: [ This function shall ensure thread safety on execution. ]*/
			if (Lock(handleData->message_receive_thread.thread_lock) != LOCK_OK)
			{
				LogError("unable to Lock");
				should_continue = 0;
				break;
			}
			if (handleData->message_receive_thread.thread_flag == THREAD_FLAG_STOP)
			{
				should_continue = 0;
				(void)Unlock(handleData->message_receive_thread.thread_lock);
				break;
			}
			if (Unlock(handleData->message_receive_thread.thread_lock) != LOCK_OK)
			{
				should_continue = 0;
				break;
			}

			int nbytes;
			unsigned char *buf = NULL;
			errno = 0;
			/*Codes_SRS_OUTPROCESS_MODULE_17_038: [ This function shall read from the message channel for gateway messages from the module host. ]*/
			nbytes = nn_recv(nn_fd, (void *)&buf, NN_MSG, 0);
			if (nbytes < 0)
			{
				int receive_error = nn_errno();
				if (receive_error != ETIMEDOUT && receive_error != EINTR)
					should_continue = 0;
			}
			else
			{
				/*Codes_SRS_OUTPROCESS_MODULE_17_039: [ Upon successful receiving a gateway message, this function shall deserialize the message. ]*/
				const unsigned char*buf_bytes = (const unsigned char*)buf;
				MESSAGE_HANDLE msg = Message_CreateFromByteArray(buf_bytes, nbytes);
				if (msg != NULL)
				{
					/*Codes_SRS_OUTPROCESS_MODULE_17_040: [ This function shall publish any successfully created gateway message to the broker. ]*/
					Broker_Publish(handleData->broker, (MODULE_HANDLE)handleData, msg);
					Message_Destroy(msg);
				}
				nn_freemsg(buf);
			}
			ThreadAPI_Sleep(1);
		}
	}
	return 0;
}