#include #include #include #include #include #include #include #include #include #include #ifndef SOL_TCP #define SOL_TCP 6 #endif struct tcp_info2 { u_int8_t tcpi_state; u_int8_t tcpi_ca_state; u_int8_t tcpi_retransmits; u_int8_t tcpi_probes; u_int8_t tcpi_backoff; u_int8_t tcpi_options; u_int8_t tcpi_snd_wscale:4, tcpi_rcv_wscale:4; u_int32_t tcpi_rto; u_int32_t tcpi_ato; u_int32_t tcpi_snd_mss; u_int32_t tcpi_rcv_mss; u_int32_t tcpi_unacked; u_int32_t tcpi_sacked; u_int32_t tcpi_lost; u_int32_t tcpi_retrans; u_int32_t tcpi_fackets; /* Times. */ u_int32_t tcpi_last_data_sent; u_int32_t tcpi_last_ack_sent; /* Not remembered, sorry. */ u_int32_t tcpi_last_data_recv; u_int32_t tcpi_last_ack_recv; /* Metrics. */ u_int32_t tcpi_pmtu; u_int32_t tcpi_rcv_ssthresh; u_int32_t tcpi_rtt; u_int32_t tcpi_rttvar; u_int32_t tcpi_snd_ssthresh; u_int32_t tcpi_snd_cwnd; u_int32_t tcpi_advmss; u_int32_t tcpi_reordering; u_int32_t tcpi_rcv_rtt; u_int32_t tcpi_rcv_space; u_int32_t tcpi_total_retrans; }; static unsigned char zeroes[65536]; static char *tcpi_state(int state) { switch (state) { case TCP_ESTABLISHED: return "ESTABLISHED"; case TCP_SYN_SENT: return "SYN_SENT"; case TCP_SYN_RECV: return "SYN_RECV"; case TCP_FIN_WAIT1: return "FIN_WAIT1"; case TCP_FIN_WAIT2: return "FIN_WAIT2"; case TCP_TIME_WAIT: return "TIME_WAIT"; case TCP_CLOSE: return "CLOSE"; case TCP_CLOSE_WAIT: return "CLOSE_WAIT"; case TCP_LAST_ACK: return "LAST_ACK"; case TCP_LISTEN: return "LISTEN"; case TCP_CLOSING: return "CLOSING"; } return "invalid"; } static char *tcpi_ca_state(int state) { switch (state) { case TCP_CA_Open: return "CA_Open"; case TCP_CA_Disorder: return "CA_Disorder"; case TCP_CA_CWR: return "CA_CWR"; case TCP_CA_Recovery: return "CA_Recovery"; case TCP_CA_Loss: return "CA_Loss"; } return "invalid"; } int main(int argc, char *argv[]) { struct sockaddr_in addr; struct tcp_info2 tcpi; struct hostent *he; int bytes; int port; int ret; int fd; if (argc <= 1) { fprintf(stderr, "syntax: %s [port] [megs]\n", argv[0]); exit(-1); } he = gethostbyname(argv[1]); if (he == NULL) { herror("gethostbyname"); exit(-1); } addr.sin_family = he->h_addrtype; memcpy(&(addr.sin_addr), he->h_addr_list[0], he->h_length); endhostent(); port = 9; if (argc > 2 && sscanf(argv[2], "%d", &port) != 1) { fprintf(stderr, "%s: second argument not numeric\n", argv[0]); exit(-1); } addr.sin_port = htons(port); bytes = 1024; if (argc > 3 && sscanf(argv[3], "%d", &bytes) != 1) { fprintf(stderr, "%s: third argument not numeric\n", argv[0]); exit(-1); } bytes <<= 20; fd = socket(AF_INET, SOCK_STREAM, 0); if (fd < 0) { perror("socket"); return 1; } ret = connect(fd, (struct sockaddr *)&addr, sizeof(addr)); if (ret < 0) { perror("connect"); return 1; } ret = sizeof(tcpi); if (getsockopt(fd, SOL_TCP, TCP_INFO, &tcpi, &ret) < 0) { perror("getsockopt(TCP_INFO)"); return 1; } while (bytes) { int tosend; tosend = bytes; if (tosend > sizeof(zeroes)) tosend = sizeof(zeroes); ret = write(fd, zeroes, tosend); if (ret < 0) { perror("write"); break; } bytes -= ret; } shutdown(fd, SHUT_RDWR); sleep(1); tcpi.tcpi_total_retrans = 0xdeadbeef; ret = sizeof(tcpi); if (getsockopt(fd, SOL_TCP, TCP_INFO, &tcpi, &ret) < 0) { perror("getsockopt(TCP_INFO)"); return 1; } printf("tcpi_state\t\t%d, %s\n", tcpi.tcpi_state, tcpi_state(tcpi.tcpi_state)); printf("tcpi_ca_state\t\t%d, %s\n", tcpi.tcpi_ca_state, tcpi_ca_state(tcpi.tcpi_ca_state)); printf("tcpi_retransmits\t%d\n", tcpi.tcpi_retransmits); printf("tcpi_probes\t\t%d\n", tcpi.tcpi_probes); printf("tcpi_backoff\t\t%d\n", tcpi.tcpi_backoff); printf("tcpi_options\t\t%d", tcpi.tcpi_options); if (tcpi.tcpi_options) { printf(" ["); if (tcpi.tcpi_options & TCPI_OPT_TIMESTAMPS) printf("TIMESTAMPS "); if (tcpi.tcpi_options & TCPI_OPT_SACK) printf("SACK "); if (tcpi.tcpi_options & TCPI_OPT_WSCALE) printf("WSCALE "); if (tcpi.tcpi_options & TCPI_OPT_ECN) printf("ECN "); printf("]"); } printf("\n"); if (tcpi.tcpi_options & TCPI_OPT_WSCALE) { printf("tcpi_snd_wscale\t\t%d\n", tcpi.tcpi_snd_wscale); printf("tcpi_rcv_wscale\t\t%d\n", tcpi.tcpi_rcv_wscale); } printf("\n"); printf("tcpi_rto\t\t%d\n", tcpi.tcpi_rto); printf("tcpi_ato\t\t%d\n", tcpi.tcpi_ato); printf("tcpi_snd_mss\t\t%d\n", tcpi.tcpi_snd_mss); printf("tcpi_rcv_mss\t\t%d\n", tcpi.tcpi_rcv_mss); printf("\n"); printf("tcpi_unacked\t\t%d\n", tcpi.tcpi_unacked); printf("tcpi_sacked\t\t%d\n", tcpi.tcpi_sacked); printf("tcpi_lost\t\t%d\n", tcpi.tcpi_lost); printf("tcpi_retrans\t\t%d\n", tcpi.tcpi_retrans); printf("tcpi_fackets\t\t%d\n", tcpi.tcpi_fackets); printf("\n"); printf("tcpi_last_data_sent\t%d\n", tcpi.tcpi_last_data_sent); printf("tcpi_last_ack_sent\t%d\n", tcpi.tcpi_last_ack_sent); printf("tcpi_last_data_recv\t%d\n", tcpi.tcpi_last_data_recv); printf("tcpi_last_ack_recv\t%d\n", tcpi.tcpi_last_ack_recv); printf("\n"); printf("tcpi_pmtu\t\t%d\n", tcpi.tcpi_pmtu); printf("tcpi_rcv_sstresh\t%d\n", tcpi.tcpi_rcv_ssthresh); printf("tcpi_rtt\t\t%d\n", tcpi.tcpi_rtt); printf("tcpi_rttvar\t\t%d\n", tcpi.tcpi_rttvar); printf("tcpi_snd_sstresh\t%d\n", tcpi.tcpi_snd_ssthresh); printf("tcpi_snd_cwnd\t\t%d\n", tcpi.tcpi_snd_cwnd); printf("tcpi_advmss\t\t%d\n", tcpi.tcpi_advmss); printf("tcpi_reordering\t\t%d\n", tcpi.tcpi_reordering); printf("\n"); printf("tcpi_rcv_rtt\t\t%d\n", tcpi.tcpi_rcv_rtt); printf("tcpi_rcv_space\t\t%d\n", tcpi.tcpi_rcv_space); printf("\n"); if (tcpi.tcpi_total_retrans != 0xdeadbeef) { printf("tcpi_total_retrans\t%d\n", tcpi.tcpi_total_retrans); printf("\n"); } close(fd); return 0; }