/** ======================================================================== * ========================================================================= */ 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; }
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
/** ======================================================================== * ========================================================================= */ 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); }
/** ======================================================================== * ========================================================================= */ 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
/** ======================================================================== * ========================================================================= */ 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
/** ======================================================================== * ========================================================================= */ 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