342 lines
		
	
	
		
			6.9 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			342 lines
		
	
	
		
			6.9 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
| tcpstat.c
 | |
| 
 | |
| Created:	June 1995 by Philip Homburg <philip@f-mnx.phicoh.com>
 | |
| */
 | |
| 
 | |
| #define _MINIX_SOURCE
 | |
| #define _POSIX_C_SOURCE 2
 | |
| 
 | |
| #include <inet/inet.h>
 | |
| #undef printf
 | |
| #undef send
 | |
| 
 | |
| #include <fcntl.h>
 | |
| #include <stdio.h>
 | |
| #include <time.h>
 | |
| #include <unistd.h>
 | |
| #include <sys/svrctl.h>
 | |
| #ifndef __minix_vmd
 | |
| #include <sys/times.h>
 | |
| #endif
 | |
| #include <net/netlib.h>
 | |
| #include <net/gen/inet.h>
 | |
| #include <net/gen/netdb.h>
 | |
| #include <net/gen/socket.h>
 | |
| #include <minix/queryparam.h>
 | |
| #include <minix/com.h>
 | |
| #include <minix/sysinfo.h>
 | |
| 
 | |
| #include <inet/generic/buf.h>
 | |
| #include <inet/generic/clock.h>
 | |
| #include <inet/generic/event.h>
 | |
| #include <inet/generic/type.h>
 | |
| #include <inet/generic/tcp.h>
 | |
| #include <inet/generic/tcp_int.h>
 | |
| 
 | |
| u32_t system_hz;
 | |
| char *prog_name;
 | |
| tcp_conn_t tcp_conn_table[TCP_CONN_NR];
 | |
| char values[2 * sizeof(tcp_conn_table) + 1];
 | |
| int inclListen, numerical, verbose;
 | |
| 
 | |
| void print_conn(int i, clock_t now);
 | |
| void usage(void);
 | |
| 
 | |
| int main(int argc, char*argv[])
 | |
| {
 | |
| 	char *ipstat_device;
 | |
| 	int fd, i, r;
 | |
| 	char *query, *pval;
 | |
| 	size_t len;
 | |
| 	struct timeval uptime;
 | |
| 	clock_t now;
 | |
| 	int fl;
 | |
| 	int a_flag, n_flag, v_flag;
 | |
| 	struct tms tmsbuf;
 | |
| 
 | |
| 	getsysinfo_up(PM_PROC_NR, SIU_SYSTEMHZ, sizeof(system_hz), &system_hz);
 | |
| 
 | |
| 	(prog_name=strrchr(argv[0], '/')) ? prog_name++ : (prog_name=argv[0]);
 | |
| 
 | |
| 	a_flag= 0;
 | |
| 	n_flag= 0;
 | |
| 	v_flag= 0;
 | |
| 	while ((fl= getopt(argc, argv, "?anv")) != -1)
 | |
| 	{
 | |
| 		switch(fl)
 | |
| 		{
 | |
| 		case '?':
 | |
| 			usage();
 | |
| 		case 'a':
 | |
| 			a_flag= 1;
 | |
| 			break;
 | |
| 		case 'n':
 | |
| 			n_flag= 1;
 | |
| 			break;
 | |
| 		case 'v':
 | |
| 			v_flag= 1;
 | |
| 			break;
 | |
| 		default:
 | |
| 			fprintf(stderr, "%s: getopt failed: '%c'\n", 
 | |
| 				prog_name, fl);
 | |
| 			exit(1);
 | |
| 		}
 | |
| 	}
 | |
| 	inclListen= !!a_flag;
 | |
| 	numerical= !!n_flag;
 | |
| 	verbose= !!v_flag;
 | |
| 
 | |
| 	ipstat_device= IPSTAT_DEVICE;
 | |
| 	if ((fd= open(ipstat_device, O_RDWR)) == -1)
 | |
| 	{
 | |
| 		fprintf(stderr, "%s: unable to open '%s': %s\n", prog_name,
 | |
| 			ipstat_device, strerror(errno));
 | |
| 		exit(1);
 | |
| 	}
 | |
| 
 | |
| 	query= "tcp_conn_table";
 | |
| 	len= strlen(query);
 | |
| 	r= write(fd, query, len);
 | |
| 	if (r != len)
 | |
| 	{
 | |
| 		fprintf(stderr, "%s: write to %s failed: %s\n",
 | |
| 			prog_name, ipstat_device, r < 0 ? strerror(errno) :
 | |
| 			"short write");
 | |
| 		exit(1);
 | |
| 	}
 | |
| 	r= read(fd, values, sizeof(values));
 | |
| 	if (r == -1)
 | |
| 	{
 | |
| 		fprintf(stderr, "%s: read from %s failed: %s\n", prog_name,
 | |
| 			ipstat_device, strerror(errno));
 | |
| 		exit(1);
 | |
| 	}
 | |
| 	pval= values;
 | |
| 	if (paramvalue(&pval, tcp_conn_table, sizeof(tcp_conn_table)) !=
 | |
| 		sizeof(tcp_conn_table))
 | |
| 	{
 | |
| 		fprintf(stderr,
 | |
| 			"%s: unable to decode the results from queryparam\n",
 | |
| 			prog_name);
 | |
| 		exit(1);
 | |
| 	}
 | |
| 
 | |
| #ifdef __minix_vmd
 | |
| 	/* Get the uptime in clock ticks. */
 | |
| 	if (sysutime(UTIME_UPTIME, &uptime) == -1)
 | |
| 	{
 | |
| 		fprintf(stderr, "%s: sysutime failed: %s\n", prog_name,
 | |
| 			strerror(errno));
 | |
| 		exit(1);
 | |
| 	}
 | |
| 	now= uptime.tv_sec * HZ + (uptime.tv_usec*HZ/1000000);
 | |
| #else	/* Minix 3 */
 | |
| 	now= times(&tmsbuf);
 | |
| #endif
 | |
| 
 | |
| 	for (i= 0; i<TCP_CONN_NR; i++)
 | |
| 		print_conn(i, now);
 | |
| 	exit(0);
 | |
| }
 | |
| 
 | |
| void print_conn(int i, clock_t now)
 | |
| {
 | |
| 	tcp_conn_t *tcp_conn;
 | |
| 	char *addr_str;
 | |
| 	struct hostent *hostent;
 | |
| 	struct servent *servent;
 | |
| 	ipaddr_t a1, a2;
 | |
| 	tcpport_t p1, p2;
 | |
| 	unsigned flags;
 | |
| 	int no_verbose;
 | |
| 	clock_t rtt, artt, drtt;
 | |
| 
 | |
| 	tcp_conn= &tcp_conn_table[i];
 | |
| 	if (!(tcp_conn->tc_flags & TCF_INUSE))
 | |
| 		return;
 | |
| 	if (tcp_conn->tc_state == TCS_LISTEN && !inclListen)
 | |
| 		return;
 | |
| 	if (tcp_conn->tc_state == TCS_CLOSED && tcp_conn->tc_fd == NULL &&
 | |
| 		tcp_conn->tc_senddis < now)
 | |
| 	{
 | |
| 		return;
 | |
| 	}
 | |
| 	
 | |
| 	printf("%3d", i);
 | |
| 
 | |
| 	a1= tcp_conn->tc_locaddr;
 | |
| 	p1= tcp_conn->tc_locport;
 | |
| 	a2= tcp_conn->tc_remaddr;
 | |
| 	p2= tcp_conn->tc_remport;
 | |
| 
 | |
| 	if (a1 == 0)
 | |
| 		addr_str= "*";
 | |
| 	else if (!numerical &&
 | |
| 		(hostent= gethostbyaddr((char *)&a1,
 | |
| 		sizeof(a1), AF_INET)) != NULL)
 | |
| 	{
 | |
| 		addr_str= hostent->h_name;
 | |
| 	}
 | |
| 	else
 | |
| 		addr_str= inet_ntoa(a1);
 | |
| 	printf(" %s:", addr_str);
 | |
| 
 | |
| 	if (p1 == 0)
 | |
| 		printf("*");
 | |
| 	else if ((servent= getservbyport(p1, "tcp")) != NULL)
 | |
| 	{
 | |
| 		printf("%s", servent->s_name);
 | |
| 	}
 | |
| 	else
 | |
| 		printf("%u", ntohs(p1));
 | |
| 
 | |
| 	if (tcp_conn->tc_orglisten)
 | |
| 		printf(" <- ");
 | |
| 	else
 | |
| 		printf(" -> ");
 | |
| 
 | |
| 	if (a2 == 0)
 | |
| 		addr_str= "*";
 | |
| 	else if (!numerical &&
 | |
| 		(hostent= gethostbyaddr((char *)&a2,
 | |
| 		sizeof(a2), AF_INET)) != NULL)
 | |
| 	{
 | |
| 		addr_str= hostent->h_name;
 | |
| 	}
 | |
| 	else
 | |
| 		addr_str= inet_ntoa(a2);
 | |
| 	printf("%s:", addr_str);
 | |
| 
 | |
| 	if (p2 == 0)
 | |
| 		printf("*");
 | |
| 	else if ((servent= getservbyport(p2, "tcp")) !=
 | |
| 		NULL)
 | |
| 	{
 | |
| 		printf("%s", servent->s_name);
 | |
| 	}
 | |
| 	else
 | |
| 		printf("%u", ntohs(p2));
 | |
| 
 | |
| 	printf(" ");
 | |
| 	no_verbose= 0;
 | |
| 	switch(tcp_conn->tc_state)
 | |
| 	{
 | |
| 	case TCS_CLOSED:	printf("CLOSED");
 | |
| 				if (tcp_conn->tc_senddis >= now)
 | |
| 				{
 | |
| 					printf("(time wait %ld s)",
 | |
| 					(tcp_conn->tc_senddis-now)/system_hz);
 | |
| 				}
 | |
| 				no_verbose= 1;
 | |
| 				break;
 | |
| 	case TCS_LISTEN:	printf("LISTEN"); no_verbose= 1; break;
 | |
| 	case TCS_SYN_RECEIVED:	printf("SYN_RECEIVED"); break;
 | |
| 	case TCS_SYN_SENT:	printf("SYN_SENT"); break;
 | |
| 	case TCS_ESTABLISHED:	printf("ESTABLISHED"); break;
 | |
| 	case TCS_CLOSING:	printf("CLOSING"); break;
 | |
| 	default:		printf("state(%d)", tcp_conn->tc_state);
 | |
| 				break;
 | |
| 	}
 | |
| 
 | |
| 	if (tcp_conn->tc_flags & TCF_FIN_RECV)
 | |
| 		printf(" F<");
 | |
| 	if (tcp_conn->tc_flags & TCF_FIN_SENT)
 | |
| 	{
 | |
| 		printf(" F>");
 | |
| 		if (tcp_conn->tc_SND_UNA == tcp_conn->tc_SND_NXT)
 | |
| 			printf("+");
 | |
| 	}
 | |
| 	if (tcp_conn->tc_state != TCS_CLOSED &&
 | |
| 		tcp_conn->tc_state != TCS_LISTEN)
 | |
| 	{
 | |
| 		printf("\n\t");
 | |
| 		printf("RQ: %lu, SQ: %lu, RWnd: %u, SWnd: %lu, SWThresh: %lu",
 | |
| 			tcp_conn->tc_RCV_NXT - tcp_conn->tc_RCV_LO,
 | |
| 			tcp_conn->tc_SND_NXT - tcp_conn->tc_SND_UNA,
 | |
| 			tcp_conn->tc_rcv_wnd,
 | |
| 			tcp_conn->tc_snd_cwnd - tcp_conn->tc_SND_UNA,
 | |
| 			tcp_conn->tc_snd_cthresh);
 | |
| 	}
 | |
| 
 | |
| 	printf("\n");
 | |
| 
 | |
| 	if (!verbose || no_verbose)
 | |
| 		return;
 | |
| 	rtt= tcp_conn->tc_rtt;
 | |
| 	artt= tcp_conn->tc_artt;
 | |
| 	drtt= tcp_conn->tc_drtt;
 | |
| 	printf("\tmss %u, mtu %u%s, rtt %.3f (%.3f+%d*%.3f) s\n",
 | |
| 		tcp_conn->tc_max_mtu-IP_TCP_MIN_HDR_SIZE,
 | |
| 		tcp_conn->tc_mtu,
 | |
| 		(tcp_conn->tc_flags & TCF_PMTU) ? "" : " (no PMTU)",
 | |
| 		rtt/(system_hz+0.0),
 | |
| 		artt/(system_hz+0.0)/TCP_RTT_SCALE, TCP_DRTT_MULT,
 | |
| 		drtt/(system_hz+0.0)/TCP_RTT_SCALE);
 | |
| 	flags= tcp_conn->tc_flags;
 | |
| 	printf("\tflags:");
 | |
| 	if (!flags)
 | |
| 		printf(" TCF_EMPTY");
 | |
| 	if (flags & TCF_INUSE)
 | |
| 		flags &= ~TCF_INUSE;
 | |
| 	if (flags & TCF_FIN_RECV)
 | |
| 	{
 | |
| 		printf(" TCF_FIN_RECV");
 | |
| 		flags &= ~TCF_FIN_RECV;
 | |
| 	}
 | |
| 	if (flags & TCF_RCV_PUSH)
 | |
| 	{
 | |
| 		printf(" TCF_RCV_PUSH");
 | |
| 		flags &= ~TCF_RCV_PUSH;
 | |
| 	}
 | |
| 	if (flags & TCF_MORE2WRITE)
 | |
| 	{
 | |
| 		printf(" TCF_MORE2WRITE");
 | |
| 		flags &= ~TCF_MORE2WRITE;
 | |
| 	}
 | |
| 	if (flags & TCF_SEND_ACK)
 | |
| 	{
 | |
| 		printf(" TCF_SEND_ACK");
 | |
| 		flags &= ~TCF_SEND_ACK;
 | |
| 	}
 | |
| 	if (flags & TCF_FIN_SENT)
 | |
| 	{
 | |
| 		printf(" TCF_FIN_SENT");
 | |
| 		flags &= ~TCF_FIN_SENT;
 | |
| 	}
 | |
| 	if (flags & TCF_BSD_URG)
 | |
| 	{
 | |
| 		printf(" TCF_BSD_URG");
 | |
| 		flags &= ~TCF_BSD_URG;
 | |
| 	}
 | |
| 	if (flags & TCF_NO_PUSH)
 | |
| 	{
 | |
| 		printf(" TCF_NO_PUSH");
 | |
| 		flags &= ~TCF_NO_PUSH;
 | |
| 	}
 | |
| 	if (flags & TCF_PUSH_NOW)
 | |
| 	{
 | |
| 		printf(" TCF_PUSH_NOW");
 | |
| 		flags &= ~TCF_PUSH_NOW;
 | |
| 	}
 | |
| 	if (flags & TCF_PMTU)
 | |
| 		flags &= ~TCF_PMTU;
 | |
| 	if (flags)
 | |
| 		printf(" 0x%x", flags);
 | |
| 	printf("\n");
 | |
| 	printf("\ttimer: ref %d, time %f, active %d\n",
 | |
| 		tcp_conn->tc_transmit_timer.tim_ref,
 | |
| 		(0.0+tcp_conn->tc_transmit_timer.tim_time-now)/system_hz,
 | |
| 		tcp_conn->tc_transmit_timer.tim_active);
 | |
| }
 | |
| 
 | |
| void usage(void)
 | |
| {
 | |
| 	fprintf(stderr, "Usage: %s [-anv]\n", prog_name);
 | |
| 	exit(1);
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * $PchId: tcpstat.c,v 1.8 2005/01/30 01:04:38 philip Exp $
 | |
|  */
 | 
