static void tcp_conn_state_set(tcp_conn_t *conn, tcp_cstate_t nstate) { tcp_cstate_t old_state; log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_conn_state_set(%p)", conn); old_state = conn->cstate; conn->cstate = nstate; fibril_condvar_broadcast(&conn->cstate_cv); /* Run user callback function */ if (conn->cb != NULL && conn->cb->cstate_change != NULL) { log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_conn_state_set() - run user CB"); conn->cb->cstate_change(conn, conn->cb_arg, old_state); } else { log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_conn_state_set() - no user CB"); } assert(old_state != st_closed); if (nstate == st_closed) { tcp_conn_remove(conn); /* Drop one reference for now being in closed state */ tcp_conn_delref(conn); } }
/** Clear the Time-Wait timeout. * * @param conn Connection */ void tcp_conn_tw_timer_clear(tcp_conn_t *conn) { log_msg(LOG_DEFAULT, LVL_DEBUG2, "tcp_conn_tw_timer_clear() begin"); if (fibril_timer_clear_locked(conn->tw_timer) == fts_active) tcp_conn_delref(conn); log_msg(LOG_DEFAULT, LVL_DEBUG2, "tcp_conn_tw_timer_clear() end"); }
/** Delist connection. * * Remove connection from the connection map. */ void tcp_conn_remove(tcp_conn_t *conn) { fibril_mutex_lock(&conn_list_lock); amap_remove(amap, &conn->ident); list_remove(&conn->link); fibril_mutex_unlock(&conn_list_lock); tcp_conn_delref(conn); }
/** Delete connection. * * The caller promises not make no further references to @a conn. * TCP will free @a conn eventually. * * @param conn Connection */ void tcp_conn_delete(tcp_conn_t *conn) { log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: tcp_conn_delete(%p)", conn->name, conn); assert(conn->deleted == false); conn->deleted = true; conn->cb = NULL; conn->cb_arg = NULL; tcp_conn_delref(conn); }
/** Time-Wait timeout handler. * * @param arg Connection */ static void tw_timeout_func(void *arg) { tcp_conn_t *conn = (tcp_conn_t *) arg; log_msg(LOG_DEFAULT, LVL_DEBUG, "tw_timeout_func(%p)", conn); tcp_conn_lock(conn); if (conn->cstate == st_closed) { log_msg(LOG_DEFAULT, LVL_DEBUG, "Connection already closed."); tcp_conn_unlock(conn); tcp_conn_delref(conn); return; } log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: TW Timeout -> Closed", conn->name); tcp_conn_state_set(conn, st_closed); tcp_conn_unlock(conn); tcp_conn_delref(conn); log_msg(LOG_DEFAULT, LVL_DEBUG, "tw_timeout_func(%p) end", conn); }
/** Segment arrived */ void tcp_as_segment_arrived(tcp_sockpair_t *sp, tcp_segment_t *seg) { tcp_conn_t *conn; log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_as_segment_arrived(f:(%x,%u), l:(%x,%u))", sp->foreign.addr.ipv4, sp->foreign.port, sp->local.addr.ipv4, sp->local.port); conn = tcp_conn_find_ref(sp); if (conn == NULL) { log_msg(LOG_DEFAULT, LVL_WARN, "No connection found."); tcp_unexpected_segment(sp, seg); return; } fibril_mutex_lock(&conn->lock); if (conn->cstate == st_closed) { log_msg(LOG_DEFAULT, LVL_WARN, "Connection is closed."); tcp_unexpected_segment(sp, seg); fibril_mutex_unlock(&conn->lock); tcp_conn_delref(conn); return; } if (conn->ident.foreign.addr.ipv4 == TCP_IPV4_ANY) conn->ident.foreign.addr.ipv4 = sp->foreign.addr.ipv4; if (conn->ident.foreign.port == TCP_PORT_ANY) conn->ident.foreign.port = sp->foreign.port; if (conn->ident.local.addr.ipv4 == TCP_IPV4_ANY) conn->ident.local.addr.ipv4 = sp->local.addr.ipv4; tcp_conn_segment_arrived(conn, seg); fibril_mutex_unlock(&conn->lock); tcp_conn_delref(conn); }
/** Segment arrived */ void tcp_as_segment_arrived(inet_ep2_t *epp, tcp_segment_t *seg) { tcp_conn_t *conn; log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_as_segment_arrived(f:(%u), l:(%u))", epp->remote.port, epp->local.port); conn = tcp_conn_find_ref(epp); if (conn == NULL) { log_msg(LOG_DEFAULT, LVL_WARN, "No connection found."); tcp_unexpected_segment(epp, seg); return; } tcp_conn_segment_arrived(conn, epp, seg); tcp_conn_delref(conn); }
/** Enlist connection. * * Add connection to the connection map. */ int tcp_conn_add(tcp_conn_t *conn) { inet_ep2_t aepp; int rc; tcp_conn_addref(conn); fibril_mutex_lock(&conn_list_lock); log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_conn_add: conn=%p", conn); rc = amap_insert(amap, &conn->ident, conn, af_allow_system, &aepp); if (rc != EOK) { tcp_conn_delref(conn); fibril_mutex_unlock(&conn_list_lock); return rc; } conn->ident = aepp; list_append(&conn->link, &conn_list); fibril_mutex_unlock(&conn_list_lock); return EOK; }