/* adds PIDs matching process *name to the *pids array, starting from pid_index */
void get_pids_by_name(const char *name, int *pids)
{
    int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0 };
    unsigned int i = 0;
    size_t buffer_size, num_procs;
    struct kinfo_proc *pproc, *proc_list;
    sysctl(mib, 4, NULL, &buffer_size, NULL, 0);

    proc_list = (kinfo_proc *)malloc(buffer_size);
    sysctl(mib, 4, proc_list, &buffer_size, NULL, 0);

    num_procs = buffer_size / sizeof(struct kinfo_proc);
    for (i = 0; i < num_procs; i++) {
        pproc = proc_list + i;
        if(!strncmp(pproc->kp_proc.p_comm, name, strnlen_(name, MAXCOMLEN)))
        {
                *pids++ = pproc->kp_proc.p_pid;
        }
    }
    free(proc_list);
}
REMOTE_MODULE_HANDLE
ProxyGateway_Attach (
    const MODULE_API * module_apis,
    const char * connection_id
) {
    REMOTE_MODULE_HANDLE remote_module;
    if (NULL == module_apis) {
        /* Codes_SRS_PROXY_GATEWAY_027_000: [Prerequisite Check - If the `module_apis` parameter is `NULL`, then `ProxyGateway_Attach` shall do nothing and return `NULL`] */
        LogError("%s: NULL parameter - module_apis", __FUNCTION__);
        remote_module = NULL;
    } else if (MODULE_API_VERSION_1 < (int)module_apis->version) {
        /* Codes_SRS_PROXY_GATEWAY_027_001: [Prerequisite Check - If the `module_apis` version is beyond `MODULE_API_VERSION_1`, then `ProxyGateway_Attach` shall do nothing and return `NULL`] */
        LogError("%s: Incompatible API version: %d!", __FUNCTION__, (1 + (int)module_apis->version));
        remote_module = NULL;
    } else if (NULL == ((MODULE_API_1 *)module_apis)->Module_Create) {
        /* Codes_SRS_PROXY_GATEWAY_027_002: [Prerequisite Check - If the `module_apis` interface fails to provide `Module_Create`, then `ProxyGateway_Attach` shall do nothing and return `NULL`] */
        LogError("%s: Required interface not met - module_apis->Module_Create", __FUNCTION__);
        remote_module = NULL;
    } else if (NULL == ((MODULE_API_1 *)module_apis)->Module_Destroy) {
        /* Codes_SRS_PROXY_GATEWAY_027_003: [Prerequisite Check - If the `module_apis` interface fails to provide `Module_Destroy`, then `ProxyGateway_Attach` shall do nothing and return `NULL`] */
        LogError("%s: Required interface not met - module_apis->Module_Destroy", __FUNCTION__);
        remote_module = NULL;
    } else if (NULL == ((MODULE_API_1 *)module_apis)->Module_Receive) {
        /* Codes_SRS_PROXY_GATEWAY_027_004: [Prerequisite Check - If the `module_apis` interface fails to provide `Module_Receive`, then `ProxyGateway_Attach` shall do nothing and return `NULL`] */
        LogError("%s: Required interface not met - module_apis->Module_Receive", __FUNCTION__);
        remote_module = NULL;
    } else if (NULL == connection_id) {
        /* Codes_SRS_PROXY_GATEWAY_027_005: [Prerequisite Check - If the `connection_id` parameter is `NULL`, then `ProxyGateway_Attach` shall do nothing and return `NULL`] */
        LogError("%s: NULL parameter - connection_id", __FUNCTION__);
        remote_module = NULL;
    } else if (GATEWAY_CONNECTION_ID_MAX + 1 == strnlen_(connection_id, GATEWAY_CONNECTION_ID_MAX + 1)) {
        /* Codes_SRS_PROXY_GATEWAY_027_006: [Prerequisite Check - If the `connection_id` parameter is longer than `GATEWAY_CONNECTION_ID_MAX`, then `ProxyGateway_Attach` shall do nothing and return `NULL`] */
        LogError("%s: connection_id exceeds GATEWAY_CONNECTION_ID_MAX in length", __FUNCTION__);
        remote_module = NULL;
    /* Codes_SRS_PROXY_GATEWAY_027_007: [`ProxyGateway_Attach` shall allocate the memory required to support its instance data] */
    } else if (NULL == (remote_module = (REMOTE_MODULE_HANDLE)calloc(1, sizeof(REMOTE_MODULE)))) {
        /* Codes_SRS_PROXY_GATEWAY_027_008: [If memory allocation fails for the instance data, then `ProxyGateway_Attach` shall return `NULL`] */
        LogError("%s: Unable to allocate memory!", __FUNCTION__);
    } else {
        static const size_t ENDPOINT_DECORATION_SIZE = sizeof("ipc://") - 1;

        const size_t control_channel_uri_size = strlen(connection_id) + ENDPOINT_DECORATION_SIZE + 1;
        char * control_channel_uri;

        // Transform the connection id into a nanomsg URI
        /* Codes_SRS_PROXY_GATEWAY_027_009: [`ProxyGateway_Attach` shall allocate the memory required to formulate the connection string to the Azure IoT Gateway] */
        if (NULL == (control_channel_uri = (char *)malloc(control_channel_uri_size))) {
            /* Codes_SRS_PROXY_GATEWAY_027_010: [If memory allocation fails for the connection string, then `ProxyGateway_Attach` shall free any previously allocated memory and return `NULL`] */
            LogError("%s: Unable to allocate memory!", __FUNCTION__);
            free(remote_module);
            remote_module = NULL;
        } else if (NULL == strcpy(control_channel_uri, "ipc://")) {
            LogError("%s: Unable to compose channel uri prefix!", __FUNCTION__);
            free(remote_module);
            remote_module = NULL;
        } else if (NULL == strncat(control_channel_uri, connection_id, GATEWAY_CONNECTION_ID_MAX + 1)) {
            LogError("%s: Unable to compose channel uri body!", __FUNCTION__);
            free(remote_module);
            remote_module = NULL;
        } else {
            /* Codes_SRS_PROXY_GATEWAY_027_011: [`ProxyGateway_Attach` shall create a socket for the Azure IoT Gateway control channel by calling `int nn_socket(int domain, int protocol)` with `AF_SP` as the `domain` and `NN_PAIR` as the `protocol`] */
            if (-1 == (remote_module->control_socket = nn_socket(AF_SP, NN_PAIR))) {
                /* Codes_SRS_PROXY_GATEWAY_027_012: [If the call to `nn_socket` returns -1, then `ProxyGateway_Attach` shall free any previously allocated memory and return `NULL`] */
                LogError("%s: Unable to create the gateway socket!", __FUNCTION__);
                free(remote_module);
                remote_module = NULL;
            /* Codes_SRS_PROXY_GATEWAY_027_013: [`ProxyGateway_Attach` shall bind to the Azure IoT Gateway control channel by calling `int nn_bind(int s, const char * addr)` with the newly created socket as `s` and the newly formulated connection string as `addr`] */
            } else if (0 > (remote_module->control_endpoint = nn_bind(remote_module->control_socket, control_channel_uri))) {
                /* Codes_SRS_PROXY_GATEWAY_027_014: [If the call to `nn_bind` returns a negative value, then `ProxyGateway_Attach` shall close the socket, free any previously allocated memory and return `NULL`] */
                LogError("%s: Unable to connect to the gateway control channel!", __FUNCTION__);
				nn_really_close(remote_module->control_socket);
                free(remote_module);
                remote_module = NULL;
            } else {
                // Save the module API
                remote_module->module.module_apis = module_apis;

                // Initialize remaining fields
                remote_module->message_socket = -1;
                remote_module->message_endpoint = -1;
            }
        }
        /* Codes_SRS_PROXY_GATEWAY_027_015: [`ProxyGateway_Attach` shall release the memory required to formulate the connection string] */
        free(control_channel_uri);
    }

    /* Codes_SRS_PROXY_GATEWAY_027_016: [If no errors are encountered, then `ProxyGateway_Attach` return a handle to the OopModule instance] */
    return remote_module;
}