/* called to setup the UL stack statistics/logging */ void ci_tcp_stats_init(ci_netif* ni, ci_tcp_state* ts) { int val; ci_assert( ni && ts ); LOG_STATS( ci_log("%s(%p, %p)", __FUNCTION__, ni, ts )); ts->stats_fmt = CI_IP_STATS_OUTPUT_DEFAULT; val = CI_TCONST_STATS; /* mS */ NI_CONF(ni).tconst_stats = val ? ci_tcp_time_ms2ticks(ni, val) : 0; LOG_STATS( ci_log("Statistics: %u ticks, %dmS, (format:%s)", NI_CONF(ni).tconst_stats, val, ts->stats_fmt ? "Text" : "XML" )); ci_tcp_stats_init_data( &ts->stats_snapshot ); ci_tcp_stats_init_data( &ts->stats_cumulative ); /* Setting the timeout to -1 implies collection through sockopt */ if( val ) ci_tcp_stats_action( ni, ts, CI_IP_STATS_START, CI_IP_STATS_OUTPUT_DEFAULT, NULL, NULL ); }
void ci_tcp_listenq_insert(ci_netif* ni, ci_tcp_socket_listen* tls, ci_tcp_state_synrecv* tsr) { int is_first; tls->n_listenq++; ci_tcp_listenq_bucket_insert(ni, tls, ci_ni_aux_p2bucket(ni, tls->bucket), tsr, 0); if( OO_SP_NOT_NULL(tsr->local_peer) ) return; is_first = ci_ni_dllist_is_empty(ni, &tls->listenq[0]); ci_ni_dllist_push_tail(ni, &tls->listenq[0], ci_tcp_synrecv2link(tsr)); tsr->retries = 0; tsr->timeout = ci_tcp_time_now(ni) + NI_CONF(ni).tconst_rto_initial; ++tls->n_listenq_new; if( is_first ) ci_tcp_listen_timer_set(ni, tls, tsr->timeout); }
/* Called when the statistics report timer fires OR at start/end of * the session or for a manual update through a sockopt * \param ni netif context * \param ts TCP state context * \param reason Action to perform * \param type Type of output (0=default, 1 = text, 2 = XML) * \param ptr Pointer to the memory where statistics is put on STATS_GET * action. It has no sense with other actions and should be set to * NULL. * \param which Type of statistics to report (TCP, netif or both) */ extern void ci_tcp_stats_action(__NI_STRUCT__ *ni, __STATE_STRUCT__ *ts, ci_ip_stats_action_type action, ci_ip_stats_output_fmt fmt, void *data, socklen_t *size) { ci_iptime_t it; ci_assert(ni); ci_assert( IPTIMER_STATE(ni) ); ci_assert(ts); LOG_STATS( ci_log( "%s( %p, %p, %d, %d, %p )", __FUNCTION__, ni, ts, action, fmt, data)); /* update snapshot timestamp */ ci_ip_time_get(IPTIMER_STATE(ni), &it); /* ci_ip_time_ticks2ms() is not defined in KERNEL space */ #ifndef __KERNEL__ ts->stats_snapshot.now = ci_ip_time_ticks2ms(ni, it); #endif switch (action) { case CI_IP_STATS_START: ci_tcp_stats_init_data( &ts->stats_snapshot); ci_tcp_stats_init_data( &ts->stats_cumulative); it = NI_CONF(ni).tconst_stats; ci_tcp_stats_handle_timer(ni, ts, it ); break; case CI_IP_STATS_GET: if ((data != NULL) && (size != NULL) && (*size >= 2 * sizeof(ci_ip_stats))){ /* assumed to be a valid user memory area to update */ ci_ip_sock_stats* ii = (ci_ip_sock_stats*)data; memcpy( &ii[0], &ts->stats_snapshot, sizeof(*ii) ); memcpy( &ii[1], &ts->stats_cumulative, sizeof(*ii)); *size = 2 * sizeof(ci_ip_sock_stats); } break; case CI_IP_STATS_REPORT: #if CI_CFG_SEND_STATS_TO_LOG ci_tcp_stats_report(ni, ts, ni->state->stats_fmt, NULL, 0); #else if ((data != NULL) && (size != NULL)) { *size = ci_tcp_stats_report(ni, ts, ni->state->stats_fmt, data, *size); } #endif break; case CI_IP_STATS_END: case CI_IP_STATS_FLUSH: ci_tcp_stats_update( ts ); /* Stop stats timer on CI_IP_STATS_END */ it = action != CI_IP_STATS_END ? NI_CONF(ni).tconst_stats : 0; ci_tcp_stats_handle_timer(ni, ts, it ); break; default: break; } }
/* [fd] is unused in the kernel version */ int ci_tcp_getsockopt(citp_socket* ep, ci_fd_t fd, int level, int optname, void *optval, socklen_t *optlen ) { ci_sock_cmn* s = ep->s; #if defined(__linux__) || \ defined(__sun__) && defined(TCP_KEEPALIVE_THRESHOLD) || \ defined(__sun__) && defined(TCP_KEEPALIVE_ABORT_THRESHOLD) ci_tcp_socket_cmn *c = &(SOCK_TO_WAITABLE_OBJ(s)->tcp.c); #endif ci_netif* netif = ep->netif; unsigned u = 0; /* NOTE: The setsockopt() call is reflected into the os socket to * keep the two in sync - it's assumed that we know everything * to allow us to give good answers here - and therefore we don't * bother the os with the get call */ /* ?? what to do about optval and optlen checking * Kernel can raise EFAULT, here we are a little in the dark. * - sockcall_intercept.c checks that optlen is non-NULL and if *optlen * is non-zero that optval is non-NULL, returning EFAULT if false */ if(level == SOL_SOCKET) { /* Common SOL_SOCKET handler */ return ci_get_sol_socket(netif, s, optname, optval, optlen); } else if (level == IPPROTO_IP) { /* IP level options valid for TCP */ return ci_get_sol_ip(ep, s, fd, optname, optval, optlen); #if CI_CFG_FAKE_IPV6 } else if (level == IPPROTO_IPV6 && s->domain == AF_INET6) { /* IP6 level options valid for TCP */ return ci_get_sol_ip6(ep, s, fd, optname, optval, optlen); #endif } else if (level == IPPROTO_TCP) { /* TCP level options valid for TCP */ switch(optname){ case TCP_NODELAY: /* gets status of TCP Nagle algorithm */ u = ((s->s_aflags & CI_SOCK_AFLAG_NODELAY) != 0); goto u_out; case TCP_MAXSEG: /* gets the MSS size for this connection */ if ((s->b.state & CI_TCP_STATE_TCP_CONN)) { u = tcp_eff_mss(SOCK_TO_TCP(s)); } else { u = 536; } goto u_out; # ifdef TCP_CORK case TCP_CORK: /* don't send partial framses, all partial frames sent ** when the option is cleared */ u = ((s->s_aflags & CI_SOCK_AFLAG_CORK) != 0); goto u_out; # endif case TCP_KEEPIDLE: { /* idle time for keepalives */ u = (unsigned) c->t_ka_time_in_secs; } goto u_out; case TCP_KEEPINTVL: { /* time between keepalives */ u = (unsigned) c->t_ka_intvl_in_secs; } goto u_out; case TCP_KEEPCNT: { /* number of keepalives before giving up */ u = c->ka_probe_th; } goto u_out; case TCP_INFO: /* struct tcp_info to be filled */ return ci_tcp_info_get(netif, s, (struct ci_tcp_info*) optval); case TCP_DEFER_ACCEPT: { u = 0; if( c->tcp_defer_accept != OO_TCP_DEFER_ACCEPT_OFF ) { u = ci_ip_time_ticks2ms(netif, NI_CONF(netif).tconst_rto_initial); u = ((u + 500) / 1000) << c->tcp_defer_accept; } goto u_out; } case TCP_QUICKACK: { u = 0; if( s->b.state & CI_TCP_STATE_TCP_CONN ) { ci_tcp_state* ts = SOCK_TO_TCP(s); u = ci_tcp_is_in_faststart(ts); } goto u_out; } default: LOG_TC( log(LPF "getsockopt: unimplemented or bad option: %i", optname)); RET_WITH_ERRNO(ENOPROTOOPT); } } else { SOCKOPT_RET_INVALID_LEVEL(s); } return 0; u_out: return ci_getsockopt_final(optval, optlen, level, &u, sizeof(u)); }