/** ========================================================================
 * =========================================================================
 */
void
psl_chan_fsm_set_gerror_from_last_error(
    const PslChanFsm*       const fsm,
    GError**                const pError,
    PslChanFsmGErrorTarget  const targetDomain)
{
    PSL_ASSERT(fsm);


    /// @note We should only be called if an error was indicated
    PSL_ASSERT(fsm->lastError);

    if (!pError) {
        return;
    }

    *pError = NULL;

    switch (targetDomain) {
    case kPslChanFsmGErrorTarget_giochannel:
        *pError = psl_err_giochangerror_from_pslerror(fsm->lastError);
        break;

    case kPslChanFsmGErrorTarget_psl:
        *pError = psl_err_pslgerror_from_pslerror(fsm->lastError);
        break;
    }

    PSL_ASSERT(*pError);
}
/** ========================================================================
 * =========================================================================
 */
static void
chan_fsm_free(PslChanFsm* const pFsm)
{
    PSL_LOG_INFO("%s (fsm=%p)", __func__, pFsm);

    PSL_ASSERT(pFsm);

    /**
     * If the FSM was successfully started, then we should have been
     * finalized by the channel via psl_chan_fsm_finalize() before 
     * our reference count dropped to zero 
     */
    PSL_ASSERT(!pFsm->fsmStarted || pFsm->fsmFinalized);

    /// Our sock should be closed by the state handlers
    if (pFsm->fd >= 0) {
        PSL_LOG_ERROR("%s: ERROR: pFsm->fd not closed!", __func__);
    }

    if (!pFsm->fsmStarted) {
        chan_fsm_destroy_widgets(pFsm);
    }

    g_free(pFsm);

    PSL_LOG_DEBUGLOW("%s (fsm=%p): LEAVING", __func__, pFsm);
}
/** ========================================================================
 * =========================================================================
 */
void
psl_chan_fsm_unref(PslChanFsm* const pFsm)
{
    PSL_LOG_DEBUGLOW("%s (fsm=%p)", __func__, pFsm);

    PSL_ASSERT(pFsm);
    PSL_ASSERT(!pFsm->base.inEvtDispatch &&
               "MUST avoid FSM run-to-completion violation");

    if (psl_refcount_atomic_unref(&pFsm->refCount)) {
        chan_fsm_free(pFsm);
    }
}
/* =========================================================================
 * =========================================================================
 */
PslError
PmSockThreadCtxNewFromGMain(GMainContext*                 gmainCtx,
                            const char*             const userLabel,
                            PmSockThreadContext**   const pThreadCtx)
{
    PSL_LOG_DEBUG("%s: pThreadCtx=%p, userLabel=\"%s\", gmaincxt=%p", 
                  __func__, pThreadCtx, PSL_LOG_MAKE_SAFE_STR(userLabel),
                  gmainCtx);

    PSL_ASSERT(pThreadCtx); *pThreadCtx = NULL;

    struct PmSockThreadContext_* const ctx =
        g_new0(struct PmSockThreadContext_, 1);

    PslError    pslerr = 0;

    if (!ctx) {
        pslerr = PSL_ERR_MEM;
        goto error_cleanup;
    }

    psl_refcount_init(&ctx->refCount_, "PSL_THREAD_CTX", ctx);

    ctx->userLabel = g_strdup(userLabel ? userLabel : "PSL_user");
    if (!ctx->userLabel) {
        pslerr = PSL_ERR_MEM;
        goto error_cleanup;
    }

    gmainCtx = gmainCtx ? gmainCtx : g_main_context_default();
    ctx->gmainCtx = g_main_context_ref(gmainCtx);


    PSL_LOG_DEBUG("%s (%s): PSL Thread Context created: ctx=%p",
                  __func__, ctx->userLabel, ctx);
    *pThreadCtx = ctx;
    return 0;

error_cleanup:
    PSL_ASSERT(pslerr);
    PSL_LOG_FATAL("%s (%s): ERROR: PslError=%d (%s)", __func__,
                  PSL_LOG_MAKE_SAFE_STR(userLabel),
                  (int)pslerr, PmSockErrStringFromError(pslerr));
    if (ctx) {
        thread_context_destroy_internal(ctx);
    }
    return pslerr;
}//PmSockThreadCtxNewFromGMain
/** ========================================================================
 * 
 * @param source
 * 
 * @return TRUE if timer has expired, FALSE if not.
 * 
 * =========================================================================
 */
static gboolean
multi_fd_watch_is_timer_expired(PslMultiFdWatchSource* source)
{
    PSL_LOG_DEBUGLOW("%s (watch=%p)", __func__, source);

    PSL_ASSERT(!source->restartTimer);

    if (MULTI_FD_WATCH_INFINITE_MSEC == source->timeoutMillisec) {
        PSL_LOG_DEBUGLOW("%s (watch=%p): using infinite timeout", __func__,
                         source);
        return false;
    }

    struct timespec now;
    if (!psl_time_get_current_mono_time(&now)) {
        return false;
    }

    if (psl_time_compare_timespecs(&now, &source->when) >= 0) {
        return true;
    }
    else {
        return false;
    }
}
/** ========================================================================
 * =========================================================================
 */
PslError
psl_multi_fd_watch_reset(PslMultiFdWatchSource* source)
{
    PSL_LOG_DEBUG("%s (watch=%p): ENTERING", __func__, source);

    source->restartTimer = true;
    source->timeoutMillisec = MULTI_FD_WATCH_INFINITE_MSEC;

    GHashTableIter iter;
    gpointer key, value;
    g_hash_table_iter_init(&iter, source->descTable);
    while (g_hash_table_iter_next(&iter, &key, &value)) {
        PslMultiFdDescriptor* desc = (PslMultiFdDescriptor*)value;
        const gint fd = GPOINTER_TO_INT(key);
        PSL_ASSERT(fd == desc->pollFd.fd);

        if (desc->pollAdded) {
            g_source_remove_poll((GSource*)source, &desc->pollFd);
        }
        g_hash_table_iter_remove(&iter);
    }

    PSL_LOG_DEBUGLOW("%s (watch=%p): LEAVING", __func__, source);
    return 0;
}
/** ========================================================================
 * =========================================================================
 */
PslError
psl_multi_fd_watch_remove_fd(PslMultiFdWatchSource* source, int const fd)
{
    gboolean removed;
    PslMultiFdDescriptor* desc;

    PSL_LOG_DEBUGLOW("%s (watch=%p), fd=%d", __func__, source, (int)fd);

    desc = (PslMultiFdDescriptor*) g_hash_table_lookup(source->descTable,
                                                       GINT_TO_POINTER(fd));

    if (!desc) {
        PSL_LOG_ERROR("%s (watch=%p): ERROR: fd=%d not found", __func__,
                      source, (int)fd);
        return PSL_ERR_INVAL;
    }

    if (desc->pollAdded) {
        g_source_remove_poll((GSource*)source, &desc->pollFd);
    }

    removed = g_hash_table_remove(source->descTable, GINT_TO_POINTER(fd));
    PSL_ASSERT(removed);

    return 0;
}
/** ========================================================================
 * =========================================================================
 */
bool
psl_chan_fsm_is_closed(const PslChanFsm* const pFsm)
{
    PSL_ASSERT(pFsm);

    return pFsm->fsmClosed;
}
/** ========================================================================
 * =========================================================================
 */
void
psl_chan_fsm_set_last_error(PslChanFsm*             const fsm,
                            PslChanFsmErrorSource   const errSrc,
                            int                           code)
{
    PSL_ASSERT(fsm);
    PSL_ASSERT(kPslChanFsmErrorSource_errno == errSrc ||
               kPslChanFsmErrorSource_psl == errSrc);
    PSL_ASSERT(code);

    if (kPslChanFsmErrorSource_errno == errSrc) {
        code = psl_err_pslerror_from_errno(code, PSL_ERR_FAILED);
    }

    fsm->lastError = code;
}
/** ========================================================================
 * =========================================================================
 */
PslError
psl_chan_fsm_get_last_error(const PslChanFsm* const fsm)
{
    PSL_ASSERT(fsm);

    return fsm->lastError;
}
/** ========================================================================
 * =========================================================================
 */
void
psl_chan_fsm_set_userdata(PslChanFsm* const pFsm, void* const userData)
{
    PSL_ASSERT(pFsm);

    pFsm->userSettings.userData = userData;
}
/** ========================================================================
 * =========================================================================
 */
void
psl_chan_fsm_reset_last_error(PslChanFsm* const fsm)
{
    PSL_ASSERT(fsm);

    fsm->lastError = 0;
}
/** ========================================================================
 * =========================================================================
 */
void*
psl_chan_fsm_get_userdata(const PslChanFsm* const pFsm)
{
    PSL_ASSERT(pFsm);

    return pFsm->userSettings.userData;
}
Example #14
0
int
psl_sme_default_state_evt_handler(FsmState*         const pStateBase,
                                  FsmMachine*       const pFsmBase,
                                  const FsmEvent*   const pEvtBase)
{
    PslSmeMachineBase*  const pFsm = (PslSmeMachineBase*)pFsmBase;
    PslSmeStateBase*    const pState = (PslSmeStateBase*)pStateBase;

    if (pEvtBase->evtId < kFsmEventFirstUserEvent) {

        void*               pArg = NULL;

        /// Set up the arg (if any) for kFsmEventBegin
        if (pEvtBase->evtId == kFsmEventBegin &&
            pFsm->beginEvtData_.reqArgSize > 0) {

            PSL_ASSERT(pState == pFsm->beginEvtData_.reqTargetState);

            memcpy(pFsm->beginEvtData_.beginDispatchArgBuf,
                   pFsm->beginEvtData_.beginRequestArgBuf,
                   pFsm->beginEvtData_.reqArgSize);

            pArg = pFsm->beginEvtData_.beginDispatchArgBuf;

            /// Reset the request arg after reaping it, so that a new one
            /// may be set if the kFsmEventBegin requests an initial transition
            pFsm->beginEvtData_.reqArgSize = 0;
            pFsm->beginEvtData_.reqTargetState = NULL;
        }

        PslSmeEventStatus const status = pState->handler_(pState,
                                                          pFsm,
                                                          pEvtBase->evtId,
                                                          pArg);

        if (status != kPslSmeEventStatus_success &&
            status != kPslSmeEventStatus_notHandled) {
            PSL_LOG_WARNING("%s (fsm=%p/%s): WARNING: handler for " \
                            "system evt=%d returned unexpected status=%d",
                            __func__, pFsm, FsmDbgPeekMachineName(&pFsm->base),
                            pEvtBase->evtId, (int)status);
        }

        return (status != kPslSmeEventStatus_notHandled);
    }

    else {
        const PslSmeEvent_* const pEvt = (const PslSmeEvent_*) pEvtBase;

        PslSmeEventStatus const status = pState->handler_(pState,
                                                          pFsm,
                                                          pEvtBase->evtId,
                                                          pEvt->arg);

        pEvt->res->status = status; ///< for psl_sme_dispatch_event()

        return (status != kPslSmeEventStatus_notHandled);
    }
}
/** ========================================================================
 * =========================================================================
 */
void
psl_chan_fsm_finalize(PslChanFsm* const pFsm)
{
    PSL_LOG_DEBUG("%s (fsm=%p)", __func__, pFsm);

    PSL_ASSERT(pFsm);

    if (pFsm->fsmStarted) {
        if (!pFsm->fsmClosed) {
            psl_chan_fsm_evt_dispatch_CLOSE(pFsm);
            PSL_ASSERT(pFsm->fsmClosed);
        }

        /// Trigger exits out of the active states to ensure orderly clean-up
        psl_chan_fsm_evt_dispatch_FINALIZE(pFsm);
    }
}///psl_chan_fsm_finalize
Example #16
0
/** ========================================================================
 * =========================================================================
 */
void
psl_sme_begin_transition(PslSmeMachineBase* const pFsm,
                         PslSmeStateBase*   const pTargetState,
                         const void*        const beginEvtArg,
                         size_t             const beginEvtArgSize,
                         const char*        const requesterFuncName)
{
    PSL_ASSERT(pFsm);
    PSL_ASSERT(pTargetState);

    if (!pFsm->inEvtDispatch) {
        PSL_LOG_FATAL("%s (fsm=%p/%s): FATAL ERROR: %s() requested transition " \
                      "to state=%s from non-event-handler scope",
                      __func__, pFsm, FsmDbgPeekMachineName(&pFsm->base),
                      requesterFuncName,
                      FsmDbgPeekStateName(&pTargetState->base));
        PSL_ASSERT(pFsm->inEvtDispatch);
    }

    if (pFsm->beginEvtData_.reqArgSize) {
        PSL_LOG_FATAL(
            "%s (fsm=%p/%s): ERROR: Prior kFsmEventBegin arg not " \
            "reaped: prior targetState=%s, arg size=%zd, " \
            "requester=%s",
            __func__, pFsm, FsmDbgPeekMachineName(&pFsm->base),
            (pFsm->beginEvtData_.reqTargetState
             ? FsmDbgPeekStateName(&pFsm->beginEvtData_.reqTargetState->base)
             : "(NULL)"),
            pFsm->beginEvtData_.reqArgSize,
            pFsm->beginEvtData_.requesterFuncName);
        PSL_ASSERT(!pFsm->beginEvtData_.reqArgSize);
    }

    if (beginEvtArg) {
        PSL_ASSERT(beginEvtArgSize > 0 &&
                   beginEvtArgSize <= pFsm->beginEvtData_.beginArgBufSize);
        pFsm->beginEvtData_.reqTargetState = pTargetState;
        pFsm->beginEvtData_.reqArgSize = beginEvtArgSize;
        pFsm->beginEvtData_.requesterFuncName = requesterFuncName;
        memcpy(pFsm->beginEvtData_.beginRequestArgBuf, beginEvtArg,
               beginEvtArgSize);
    }

    FsmBeginTransition(&pFsm->base, &pTargetState->base);
}
/* =========================================================================
 * =========================================================================
 */
GMainContext*
PmSockThreadCtxPeekGMainContext(PmSockThreadContext* const ctx)
{
    PSL_ASSERT(ctx);

    PSL_LOG_DEBUGLOW("%s (ctx=%p/%s): gmainCtx=%p",
                     __func__, ctx, ctx->userLabel, ctx->gmainCtx);

    return ctx->gmainCtx;
}
/* =========================================================================
 * =========================================================================
 */
PmSockThreadContext*
PmSockThreadCtxRef(PmSockThreadContext* const ctx)
{
    PSL_ASSERT(ctx);

    PSL_LOG_DEBUGLOW("%s (ctx=%p/%s)", __func__, ctx, ctx->userLabel);

    psl_refcount_atomic_ref(&ctx->refCount_);

    return ctx;
}
/** ========================================================================
 * =========================================================================
 */
PslChanFsm*
psl_chan_fsm_ref(PslChanFsm* const pFsm)
{
    PSL_LOG_DEBUGLOW("%s (fsm=%p)", __func__, pFsm);

    PSL_ASSERT(pFsm);

    psl_refcount_atomic_ref(&pFsm->refCount);

    return pFsm;
}
/** ========================================================================
 * chan_fsm_destroy_widgets(): Called by chan_fsm_free() and the 
 * PslChanFsmFinalState's kFsmEventEnterScope event handler to 
 * destroy the "widgets" used the the FSM. 
 *  
 * @note See the note about deadlock work-around in 
 *       psl_chan_fsm_finalize() header comments.
 *  
 * @param pFsm 
 * =========================================================================
 */
static void
chan_fsm_destroy_widgets(PslChanFsm* const pFsm)
{
    PSL_LOG_INFO("%s (fsm=%p)", __func__, pFsm);

    PSL_ASSERT(pFsm);

    if (pFsm->fdWatchInfo.fdWatch) {
        /**
         * @note Multi-level GSource arrangements such as ours (a 
         *       GSource that monitors our channel instance and another
         *       GSource owned by the channel instance) are susceptible
         *       to deadlock in glib's gmain code if we're not careful.
         *       We use lots of low-level logging below to help with
         *       debugging should a deadlock be triggered.
         */

        (void)psl_multi_fd_watch_reset(pFsm->fdWatchInfo.fdWatch);

        PSL_LOG_DEBUGLOW("%s (fsm=%p): Detaching multi-fd-watch=%p",
                         __func__, pFsm, pFsm->fdWatchInfo.fdWatch);

        g_source_destroy((GSource*)pFsm->fdWatchInfo.fdWatch);

        PSL_LOG_DEBUGLOW("%s (fsm=%p): Finished detaching multi-fd-watch=%p",
                         __func__, pFsm, pFsm->fdWatchInfo.fdWatch);

        PSL_LOG_DEBUGLOW("%s (fsm=%p): Unref'ing multi-fd-watch=%p",
                         __func__, pFsm, pFsm->fdWatchInfo.fdWatch);

        g_source_unref((GSource*)pFsm->fdWatchInfo.fdWatch);

        PSL_LOG_DEBUGLOW("%s (fsm=%p): Finished unref'ing multi-fd-watch=%p",
                         __func__, pFsm, pFsm->fdWatchInfo.fdWatch);

        pFsm->fdWatchInfo.fdWatch = NULL;
    }

    g_free(pFsm->userSettings.bindAddr.hostStr);
    pFsm->userSettings.bindAddr.hostStr = NULL;
    g_free(pFsm->userSettings.serverAddr.hostStr);
    pFsm->userSettings.serverAddr.hostStr = NULL;

    if (pFsm->userSettings.threadCtx) {
        PmSockThreadCtxUnref(pFsm->userSettings.threadCtx);
        pFsm->userSettings.threadCtx = NULL;
    }

    PSL_LOG_DEBUGLOW("%s (fsm=%p): LEAVING", __func__, pFsm);
}
/* =========================================================================
 * =========================================================================
 */
void
PmSockThreadCtxUnref(PmSockThreadContext* const ctx)
{
    PSL_ASSERT(ctx);

    PSL_LOG_DEBUGLOW("%s (ctx=%p/%s)", __func__, ctx, ctx->userLabel);


    if (!psl_refcount_atomic_unref (&ctx->refCount_)) {
        return;
    }

    thread_context_destroy_internal(ctx);
}
Example #22
0
/** ========================================================================
 * =========================================================================
 */
PslError
psl_inet_connect_sock(int         const s,
                      int         const addrFamily,
                      const char* const addrStr,
                      int         const port,
                      const char* const userLabel,
                      const void* const cookie)
{
    PslInetGenericSockAddr  server;

    PSL_LOG_DEBUG("%s (%s=%p): fd=%d, addrfamily=%d, addrStr=%s, port=%d",
                  __func__, userLabel, cookie, s, addrFamily,
                  PSL_LOG_OBFUSCATE_STR(addrStr), port);

    bool success = !psl_inet_make_sock_addr(addrFamily, addrStr,
                                            port, &server, userLabel, cookie);
    if (!success) {
        return PSL_ERR_BAD_SERV_ADDR;
    }

    int rc = connect(s, (struct sockaddr*)&server.sa, server.addrLength);
    PSL_ASSERT(rc <= 0);
    if (0 == rc) {
        PSL_LOG_DEBUG("%s (%s=%p): connect() succeeded immediately",
                      __func__, userLabel, cookie);
        return 0;
    }
    else if (rc < 0 && EINPROGRESS == errno) {
        PSL_LOG_DEBUG("%s (%s=%p): connect() returned EINPROGRESS",
                      __func__, userLabel, cookie);
        return 0;
    }
    /* @todo The implication of EINTR
             when connecting on a non-blocking socket is vague, at best.
             Should we retry connect(), assume that all is well, or give up
             on this connection?
    else if (rc < 0 && EINTR == errno) {
        PSL_LOG_DEBUG("%s (fsm=%p): connect() returned EINTR",
                      __func__, pFsm);
        return 0;
    }
    */
    else { /// (rc < 0)
        int const saverrno = errno;
        PSL_LOG_ERROR("%s (%s=%p): ERROR: connect() failed; errno=%d (%s)",
                      __func__, userLabel, cookie, saverrno, strerror(saverrno));

        return psl_err_pslerror_from_connect_errno(saverrno);
    }
}//psl_inet_connect_sock
/** ========================================================================
 * =========================================================================
 */
static PslSmeEventStatus
chan_fsm_final_state_handler(PslChanFsmFinalState*      const pState,
                             PslChanFsm*                const pFsm,
                             PslSmeEventId              const evtId,
                             const PslChanFsmEvtArg*    const evtArg)
{   
    switch (evtId) 
    {
    case kFsmEventEnterScope:
        PSL_ASSERT(pFsm->fsmClosed); ///< we should have been closed first
        chan_fsm_destroy_widgets(pFsm);
        pFsm->fsmFinalized = true;
        /// FALLTHROUGH
    case kFsmEventExitScope:
        /// FALLTHROUGH
    case kFsmEventBegin:
        return kPslSmeEventStatus_success;
        break;

    default:
        if (evtId >= kFsmEventFirstUserEvent) {
            /// We don't expect any other events in the final state, since
            /// we're supposed to be an ephemeral state used only during
            /// destruction of the FSM instance.
            PSL_LOG_FATAL("%s (fsm=%p): ERROR: %s.%s received unexpected " \
                          "event %d", __func__, pFsm,
                          FsmDbgPeekMachineName(&pFsm->base.base),
                          FsmDbgPeekStateName(&pState->base.base),
                          evtId);
            PSL_ASSERT(false && "unexpected event in 'final' state");
        }
        break;
    }

    return kPslSmeEventStatus_passToParent;
}
/** ========================================================================
 * PslMultiFdWatchSourceCb callback from the multi-fd watch
 * source
 * 
 * @see PslMultiFdWatchSourceCb for arg info
 * 
 * @param userData
 * @param pollrecs
 * @param numrecs
 * 
 * @return gboolean
 * 
 * =========================================================================
 */
static gboolean
chan_fsm_fd_watch_cb(gpointer const userData, const PslMultiFdPollRec* pollrecs,
                     int const numrecs)
{
    PslChanFsm* const pFsm = (PslChanFsm*)userData;

    PSL_ASSERT(!pFsm->fdWatchInfo.inFdWatchCb);

    pFsm->fdWatchInfo.inFdWatchCb = true;

    PslSmeEventStatus const status =
        psl_chan_fsm_evt_dispatch_FD_WATCH(pFsm, pollrecs, numrecs);

    if (kPslSmeEventStatus_errorCatchAll == status ||
        kPslSmeEventStatus_notHandled == status) {
        PSL_LOG_ERROR("%s (fsm=%p): ERROR: FD_WATCH event fell through",
                      __func__, pFsm);
    }

    /// Process external callbacks
    struct PslChanFsmFdWatchCompletion* const cb = &pFsm->fdWatchInfo.completionCb;

    if (kPslChanFsmEvtCompletionCbId_none != cb->cb.which) {

        /// So we don't get destroyed while in callbacks
        (void)psl_chan_fsm_ref(pFsm);

        psl_chan_fsm_dispatch_completion_cb(pFsm, &cb->cb, cb->pslErr,
                                            cb->switchingToCrypto);

        cb->cb.which = kPslChanFsmEvtCompletionCbId_none;

        pFsm->fdWatchInfo.inFdWatchCb = false;

        /// okay if the FSM gets destroyed now
        psl_chan_fsm_unref(pFsm);
        return true;
    }//if user callback scheduled

    else {
        pFsm->fdWatchInfo.inFdWatchCb = false;
    }

    return true; ///< true, so the GSource won't get detached from our gmain ctx
}//chan_fsm_fd_watch_cb
Example #25
0
/** ========================================================================
 * =========================================================================
 */
bool
psl_inet_ipaddr_from_string(const char*         const hn,
                            PslInetIPAddress*   const pBuf,
                            const char*         const userLabel,
                            const void*         const cookie)
{
    PSL_ASSERT(pBuf);

    pBuf->family = AF_UNSPEC;

    if (!hn || !*hn) {
        PSL_LOG_ERROR("%s (%s=%p): ERROR: NULL or empty hostname string",
                      __func__, userLabel, cookie);
        return false;
    }

    int             rc;

    rc = inet_pton(AF_INET, hn, &pBuf->addr);
    if (rc > 0) {
        PSL_LOG_DEBUGLOW("%s (%s=%p): hostname looks like IPv4 address",
                         __func__, userLabel, cookie);
        pBuf->family = AF_INET;
        pBuf->len = sizeof(struct in_addr);
        return true;
    }
    else {
        rc = inet_pton(AF_INET6, hn, &pBuf->addr);
        if (rc > 0) {
            PSL_LOG_DEBUGLOW("%s (%s=%p): hostname looks like IPv6 address",
                             __func__, userLabel, cookie);
            pBuf->family = AF_INET6;
            pBuf->len = sizeof(struct in6_addr);
            return true;
        }
        else {
            PSL_LOG_DEBUGLOW("%s (%s=%p): hostname string '%s' doesn't look " \
                             "like an IP address'.",
                             __func__, userLabel, cookie, PSL_LOG_OBFUSCATE_STR(hn));
        }
    }

    return false;
}//psl_inet_ipaddr_from_string
/* =========================================================================
 * =========================================================================
 */
static void
thread_context_destroy_internal(PmSockThreadContext* const ctx)
{
    PSL_LOG_DEBUG("%s (ctx=%p/%s)", __func__, ctx,
                  PSL_LOG_MAKE_SAFE_STR(ctx->userLabel));

    PSL_ASSERT(ctx);

    g_free(ctx->userLabel);

    if (ctx->gmainCtx) {
        g_main_context_unref(ctx->gmainCtx);
    }

    g_free(ctx);


    PSL_LOG_DEBUGLOW("%s (ctx=%p): LEAVING", __func__, ctx);
}
/** ========================================================================
 * =========================================================================
 */
PmSockThreadContext*
psl_chan_fsm_peek_thread_ctx(PslChanFsm* const pFsm)
{
    PSL_ASSERT(pFsm);
    return pFsm->userSettings.threadCtx;
}
/** ========================================================================
 * =========================================================================
 */
void
psl_chan_fsm_dispatch_completion_cb(
    PslChanFsm*                             const pFsm,
    const PslChanFsmEvtCompletionCbInfo*    const pCb,
    PslError                                const pslErr,
    bool                                    const switchingToCrypto)
{
    PSL_ASSERT(pFsm);
    PSL_ASSERT(pCb);

    if (pFsm->fsmClosed) {
        PSL_LOG_NOTICE("%s (fsm=%p): FSM is closed: suppressing callbacks",
                       __func__, pFsm);
        return;
    }

    enum PslChanFsmEvtCompletionCbId which = pCb->which;

    if (kPslChanFsmEvtCompletionCbId_none == which) {
        PSL_LOG_DEBUG("%s (fsm=%p): no callback to dispatch", __func__, pFsm);
        return;
    }

    /// Process external callback

    /// So we don't get destroyed while in callback
    (void)psl_chan_fsm_ref(pFsm);

    switch (which) {
    case kPslChanFsmEvtCompletionCbId_none:
        break;

    case kPslChanFsmEvtCompletionCbId_completion:
        {
            which = kPslChanFsmEvtCompletionCbId_none;

            PSL_LOG_DEBUG(
                "%s (fsm=%p/ch=%p): Dispatching 'completion' callback " \
                "to user: PslError=%d (%s)", __func__,
                pFsm, pFsm->channel, (int)pslErr,
                PmSockErrStringFromError(pslErr));

            PSL_ASSERT(pCb->u.completionCb.func);
            pCb->u.completionCb.func((PmSockIOChannel*)pFsm->channel,
                                        pFsm->userSettings.userData,
                                        pslErr);
        }
        break;

    case kPslChanFsmEvtCompletionCbId_connect: /// legacy support
        {
            which = kPslChanFsmEvtCompletionCbId_none;

            GError*     gerr = NULL;
            if (pslErr) {
                gerr = g_error_new(PmSockErrGErrorDomain(), pslErr, "%s",
                                   PmSockErrStringFromError(pslErr));
            }
            PSL_LOG_DEBUG(
                "%s (fsm=%p/ch=%p): Dispatching 'connect' callback " \
                "to legacy user: PslError=%d (%s)", __func__,
                pFsm, pFsm->channel, gerr ? (int)gerr->code : 0,
                gerr ? gerr->message : "success");

            PSL_ASSERT(pCb->u.connectCb.func);
            (void)pCb->u.connectCb.func(pFsm->channel,
                                      pCb->u.connectCb.userData, gerr);
            if (gerr) {g_error_free(gerr);}
        }
        break;

    case kPslChanFsmEvtCompletionCbId_switch: /// legacy support
        {
            which = kPslChanFsmEvtCompletionCbId_none;

            GError* gerr = NULL;
            if (pslErr) {
                gerr = g_error_new(PmSockErrGErrorDomain(), pslErr, "%s",
                                   PmSockErrStringFromError(pslErr));
            }
            PSL_LOG_DEBUG(
                "%s (fsm=%p/ch=%p): Dispatching 'security switch' callback " \
                "to legacy user: switchingToCrypto=%d, PslError code=%d (%s)",
                __func__, pFsm, pFsm->channel, switchingToCrypto,
                gerr ? (int)gerr->code : 0, gerr ? gerr->message : "success");

            PSL_ASSERT(pCb->u.switchCb.func);
            (void)pCb->u.switchCb.func(pFsm->channel, switchingToCrypto,
                                     pCb->u.switchCb.userData, gerr);
            if (gerr) {g_error_free(gerr);}
        }
        break;
    }

    PSL_ASSERT(kPslChanFsmEvtCompletionCbId_none == which);

    /// okay if the FSM gets destroyed now
    psl_chan_fsm_unref(pFsm);
    return;

}//psl_chan_fsm_dispatch_completion_cb
/** ========================================================================
 * =========================================================================
 */
static PslSmeEventStatus
chan_fsm_init_state_handler(PslChanFsmInitState*    const pState,
                            PslChanFsm*             const pFsm,
                            PslSmeEventId           const evtId,
                            const PslChanFsmEvtArg* const evtArg)
{   
    switch (evtId) 
    {
    case kFsmEventEnterScope:
    case kFsmEventExitScope:
    case kFsmEventBegin:
        return kPslSmeEventStatus_success;
        break;

    case PSL_CHAN_FSM_EVT_CONNECT:
        if (AF_UNSPEC == pFsm->userSettings.serverAddr.addrFamily && pFsm->fd < 0) {
            PSL_LOG_ERROR("%s (fsm=%p): ERROR: PSL_CHAN_FSM_EVT_CONNECT " \
                          "failed: connect address not set", __func__, pFsm);

            psl_chan_fsm_set_last_error(pFsm, kPslChanFsmErrorSource_psl,
                                        PSL_ERR_BAD_SERV_ADDR);
            return kPslSmeEventStatus_error;
        }


        if (pFsm->fd < 0) {
            psl_chan_fsm_goto_plain_lookup_state(pFsm, &evtArg->connect.data);
        }
        else {
            static const struct PslChanFsmEvtInetAddrText addrText = {
                .family = AF_UNSPEC
                };
            psl_chan_fsm_goto_plain_conn_state(pFsm, &evtArg->connect.data, &addrText);
        }
        return kPslSmeEventStatus_success;
        break;

    case PSL_CHAN_FSM_EVT_SET_CONN_FD:
        {
            const struct PslChanFsmEvtArgSetConnFD* const arg =
                &evtArg->setConnFD;

            PSL_ASSERT(arg->fd >= 0);

            if (AF_UNSPEC != pFsm->userSettings.serverAddr.addrFamily) {
                PSL_LOG_ERROR("%s (fsm=%p): SET_CONN_FD ERROR: " \
                              "not allowed when server address is set",
                              __func__, pFsm);
                return kPslSmeEventStatus_passToParent;
            }

            if (AF_UNSPEC != pFsm->userSettings.bindAddr.addrFamily) {
                PSL_LOG_ERROR("%s (fsm=%p): SET_CONN_FD ERROR: " \
                              "not allowed when bind address is set",
                              __func__, pFsm);
                return kPslSmeEventStatus_passToParent;
            }

            if (pFsm->fd >= 0) {
                PSL_LOG_ERROR("%s (fsm=%p): SET_CONN_FD ERROR: connected " \
                              "file descriptor was already set",
                              __func__, pFsm);
                return kPslSmeEventStatus_passToParent;
            }

            pFsm->fd = arg->fd;
            pFsm->userSettings.fdIsUserProvided = true;
            pFsm->userSettings.fdOpts = arg->opts;

            return kPslSmeEventStatus_success;
            break;
        }

    case PSL_CHAN_FSM_EVT_SET_SERVER:
        {
            const struct PslChanFsmEvtArgSetServer* const arg =
                &evtArg->setServer;

            if (pFsm->fd >= 0) {
                PSL_LOG_ERROR("%s (fsm=%p): SET_SERVER ADDR ERROR: not " \
                              "allowed when connected file descriptor is set",
                              __func__, pFsm);
                return kPslSmeEventStatus_passToParent;
            }

            if (AF_UNSPEC != pFsm->userSettings.serverAddr.addrFamily) {
                PSL_LOG_ERROR("%s (fsm=%p): SET_SERVER ADDR ERROR: " \
                              "server address was already set",
                              __func__, pFsm);
                return kPslSmeEventStatus_passToParent;
            }

            PSL_LOG_DEBUG("%s (fsm=%p): SET_SERVER ADDR: server: '%s:%d'/af=%d",
                          __func__, pFsm,
                          PSL_LOG_OBFUSCATE_STR(arg->hostStr),
                          (int)arg->port,
                          (int)arg->addrFamily);

            pFsm->userSettings.serverAddr.addrFamily = arg->addrFamily;
            pFsm->userSettings.serverAddr.port = arg->port;
            pFsm->userSettings.serverAddr.hostStr = g_strdup(arg->hostStr);
            PSL_ASSERT(pFsm->userSettings.serverAddr.hostStr);
        }
        return kPslSmeEventStatus_success;
        break;

    case PSL_CHAN_FSM_EVT_SET_SOCK_BIND:
        {
            const struct PslChanFsmEvtArgSetSockBind* const arg =
                &evtArg->setSockBind;

            if (pFsm->fd >= 0) {
                PSL_LOG_ERROR("%s (fsm=%p): SET_SOCK_BIND ERROR: not " \
                              "allowed when connected file descriptor is set",
                              __func__, pFsm);
                return kPslSmeEventStatus_passToParent;
            }

            if (AF_UNSPEC != pFsm->userSettings.bindAddr.addrFamily) {
                PSL_LOG_ERROR("%s (fsm=%p): SET_SOCK_BIND ERROR: " \
                              "socket bind address was already set",
                              __func__, pFsm);
                return kPslSmeEventStatus_passToParent;
            }

            PSL_LOG_DEBUG("%s (fsm=%p): SET_SOCK_BIND: local addr: '%s:%d'/af=%d",
                          __func__, pFsm,
                          PSL_LOG_MAKE_SAFE_STR(arg->ipAddrStr),
                          (int)arg->port,
                          (int)arg->addrFamily);

            pFsm->userSettings.bindAddr.addrFamily = arg->addrFamily;
            pFsm->userSettings.bindAddr.port = arg->port;
            pFsm->userSettings.bindAddr.hostStr = g_strdup(arg->ipAddrStr);
            PSL_ASSERT(!arg->ipAddrStr || pFsm->userSettings.bindAddr.hostStr);
        }
        return kPslSmeEventStatus_success;
        break;

    default:
        break; ///< allow default processing by parent
    }

    return kPslSmeEventStatus_passToParent;
}//chan_fsm_init_state_handler
Example #30
0
/** ========================================================================
 * =========================================================================
 */
int
psl_inet_make_sock_addr(int                       const reqFamily,
                        const char*               const addrStr,
                        int                       const port,
                        PslInetGenericSockAddr*   const res,
                        const char*               const userLabel,
                        const void*               const cookie)
{
    PSL_ASSERT(AF_INET == reqFamily || AF_INET6 == reqFamily ||
           AF_UNSPEC == reqFamily);
    PSL_ASSERT(AF_UNSPEC != reqFamily || (addrStr && addrStr[0]));
    PSL_ASSERT(res);

    memset(res, 0, sizeof(*res));

    res->family = AF_UNSPEC;


    PslInetIPAddress    pslinaddr;
    int                 inaddrlen = 0;

    int actualFamily = reqFamily;

    if (AF_UNSPEC == reqFamily) {
        PSL_LOG_DEBUGLOW("%s (%s=%p): resoloving addrfamily (was AF_UNSPEC)",
                         __func__, userLabel, cookie);
        PSL_ASSERT(addrStr);

        bool const gotAddr = psl_inet_ipaddr_from_string(addrStr, &pslinaddr,
                                                         userLabel, cookie);
        if (gotAddr) {
            actualFamily = pslinaddr.family;
            inaddrlen = pslinaddr.len;
        }
        else {
            PSL_LOG_ERROR("%s (%s=%p): ERROR: could not determine " \
                          "address family from address string '%s'.",
                          __func__, userLabel, cookie,
                          PSL_LOG_OBFUSCATE_STR(addrStr));
            return EINVAL;
        }
    }


    void*   addrDst = NULL;
    if (AF_INET == actualFamily) {
        res->addrLength = sizeof(res->sa);
        res->sa.sin_family = actualFamily;
        res->sa.sin_port = htons(port);
        res->sa.sin_addr.s_addr = INADDR_ANY;
        addrDst = &res->sa.sin_addr;
    }
    else {
        PSL_ASSERT(AF_INET6 == actualFamily);
        res->addrLength = sizeof(res->sa6);
        res->sa6.sin6_family = actualFamily;
        //res->sa6.sin6_flowinfo = 0; ///< what should we do with these?
        //res->sa6.sin6_scope_id = 0;
        res->sa6.sin6_port = htons(port);
        res->sa6.sin6_addr = in6addr_any;
        addrDst = &res->sa6.sin6_addr;
    }

    if (addrStr && inaddrlen) {
        memcpy(addrDst, &pslinaddr.addr, inaddrlen);
    }
    else if (addrStr) {
        PSL_ASSERT(addrDst);
        int const ptonRes = inet_pton(actualFamily, addrStr, addrDst);

        if (ptonRes < 0) {  /// unexpected address family - check errno
            int const saverrno = errno;
            PSL_LOG_ERROR("%s (%s=%p): ERROR: inet_pton() failed; " \
                          "family=%d, addrStr=%s, errno=%d (%s).",
                          __func__, userLabel, cookie, actualFamily,
                          PSL_LOG_OBFUSCATE_STR(addrStr), saverrno,
                          strerror(saverrno));
            PSL_ASSERT(saverrno);
            return saverrno;
        }
        else if (ptonRes == 0) {    /// addr does not match family
            /// @note This case does not set errno
            PSL_LOG_ERROR("%s (%s=%p): ERROR: inet_pton() failed; Address " \
                          "does not match family; family=%d, addrStr=%s.",
                          __func__, userLabel, cookie, actualFamily,
                          PSL_LOG_OBFUSCATE_STR(addrStr));
            return EINVAL;
        }
    }

    res->family = actualFamily;
    return 0;
}// psl_inet_make_sock_addr