/**
 *******************************************************************************
 * @brief Allocate a new outgoing queue.
 *
 * @retval  queue on success
 * @retval  NULL on failure
 *******************************************************************************
 */
_LSTransportOutgoing*
_LSTransportOutgoingNew(void)
{
    _LSTransportOutgoing *outgoing = g_slice_new0(_LSTransportOutgoing);

    if (pthread_mutex_init(&outgoing->lock, NULL))
    {
        LOG_LS_ERROR(MSGID_LS_MUTEX_ERR, 0, "Could not initialize mutex");
        goto error_before_mutex;
    }

    outgoing->queue = g_queue_new();
    outgoing->serial = _LSTransportSerialNew();
    if (!outgoing->serial)
    {
        LOG_LS_ERROR(MSGID_LS_SERIAL_ERROR, 0, "Could not initialize serial map");
        goto error;
    }

    return outgoing;

error:
    pthread_mutex_destroy(&outgoing->lock);

error_before_mutex:
    _LSTransportOutgoingFree(outgoing);
    return NULL;
}
/** 
 *******************************************************************************
 * @brief Free a client.
 * 
 * @param  client   IN  client
 *******************************************************************************
 */
void
_LSTransportClientFree(_LSTransportClient* client)
{
    if (client->unique_name) g_free(client->unique_name);
    if (client->service_name) g_free(client->service_name);
    _LSTransportCredFree(client->cred);
    _LSTransportOutgoingFree(client->outgoing);
    _LSTransportIncomingFree(client->incoming);
    _LSTransportChannelClose(&client->channel, true);
    _LSTransportChannelDeinit(&client->channel);

#ifdef MEMCHECK
    memset(client, 0xFF, sizeof(_LSTransportClient));
#endif

    g_slice_free(_LSTransportClient, client);
}
/** 
 *******************************************************************************
 * @brief Allocate a new client.
 * 
 * @param  transport        IN  transport 
 * @param  fd               IN  fd 
 * @param  service_name     IN  client service name 
 * @param  unique_name      IN  client unique name 
 * @param  outgoing         IN  outgoing queue (NULL means allocate) 
 * @param  initiator        IN  true if this is the end of the connection that initiated the connection
 * 
 * @retval client on success
 * @retval NULL on failure
 *******************************************************************************
 */
_LSTransportClient*
_LSTransportClientNew(_LSTransport* transport, int fd, const char *service_name, const char *unique_name, _LSTransportOutgoing *outgoing, bool initiator)
{
    _LSTransportClient *new_client = g_slice_new0(_LSTransportClient);

    if (!new_client)
    {
        g_debug("OOM when attempting to add new incoming connection");
        return NULL;
    }

    //new_client->sh = sh;
    new_client->service_name = g_strdup(service_name);
    new_client->unique_name = g_strdup(unique_name);
    new_client->transport = transport;
    new_client->state = _LSTransportClientStateInvalid;
    new_client->is_sysmgr_app_proxy = false;
    new_client->is_dynamic = false;
    new_client->initiator = initiator;

    _LSTransportChannelInit(transport, &new_client->channel, fd, transport->source_priority);

    new_client->cred = _LSTransportCredNew();
    if (!new_client->cred)
    {
        goto error;
    }

    /* Get pid, gid, and uid of client if we're local. It won't work for obvious
     * reasons if it's a TCP/IP connection */
    if (_LSTransportGetTransportType(transport) == _LSTransportTypeLocal)
    {
        LSError lserror;
        LSErrorInit(&lserror);

        if (!_LSTransportGetCredentials(fd, new_client->cred, &lserror))
        {
            LSErrorPrint(&lserror, stderr);
            LSErrorFree(&lserror);
        }
    }

    if (outgoing)
    {
        new_client->outgoing = outgoing;
    }
    else
    {
        new_client->outgoing = _LSTransportOutgoingNew();
        if (!new_client->outgoing)
        {
            goto error;
        }
    }

    new_client->incoming = _LSTransportIncomingNew();
    if (!new_client->incoming)
    {
        goto error;
    }

    return new_client;

error:

    if (new_client->service_name) g_free(new_client->service_name);
    if (new_client->unique_name) g_free(new_client->unique_name);

    if (new_client->outgoing && !outgoing)
    {
        _LSTransportOutgoingFree(new_client->outgoing);
    }
    if (new_client->incoming)
    {
        _LSTransportIncomingFree(new_client->incoming);
    }
    if (new_client)
    {
        g_slice_free(_LSTransportClient, new_client);
    }

    return NULL;
}