/** ======================================================================== * ========================================================================= */ 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
/** ======================================================================== * ========================================================================= */ 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
/** ======================================================================== * ========================================================================= */ 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
/** ======================================================================== * ========================================================================= */ 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