xref: /haiku/src/bin/network/netstat/netstat.cpp (revision 2f470aec1c92ce6917b8a903e343795dc77af41f)
1 /*
2  * Copyright 2006, Haiku, Inc. All Rights Reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Axel Dörfler, axeld@pinc-software.de
7  */
8 
9 
10 #include <SupportDefs.h>
11 
12 #include <net_stack_driver.h>
13 #include <net_stat.h>
14 
15 #include <arpa/inet.h>
16 #include <netdb.h>
17 #include <net/if.h>
18 #include <netinet/in.h>
19 
20 #include <errno.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <unistd.h>
25 
26 
27 extern const char* __progname;
28 const char* kProgramName = __progname;
29 
30 
31 struct address_family {
32 	int			family;
33 	const char*	name;
34 	const char*	identifiers[4];
35 	void		(*print_address)(sockaddr* address);
36 };
37 
38 // AF_INET family
39 static void inet_print_address(sockaddr* address);
40 
41 static const address_family kFamilies[] = {
42 	{
43 		AF_INET,
44 		"inet",
45 		{"AF_INET", "inet", "ipv4", NULL},
46 		inet_print_address
47 	},
48 	{ -1, NULL, {NULL}, NULL }
49 };
50 
51 
52 static void
53 inet_print_address(sockaddr* _address)
54 {
55 	sockaddr_in& address = *(sockaddr_in *)_address;
56 
57 	if (address.sin_family != AF_INET || address.sin_len == 0) {
58 		printf("%-22s", "-");
59 		return;
60 	}
61 
62 	hostent* host = gethostbyaddr((const char*)_address, sizeof(sockaddr_in), AF_INET);
63 	servent* service = getservbyport(ntohs(address.sin_port), NULL);
64 
65 	const char *hostName;
66 	if (host != NULL)
67 		hostName = host->h_name;
68 	else if (address.sin_addr.s_addr == INADDR_ANY)
69 		hostName = "*";
70 	else
71 		hostName = inet_ntoa(address.sin_addr);
72 
73 	char buffer[128];
74 	int length = strlcpy(buffer, hostName, sizeof(buffer));
75 
76 	char port[64];
77 	if (service != NULL)
78 		strlcpy(port, service->s_name, sizeof(port));
79 	else if (address.sin_port == 0)
80 		strcpy(port, "*");
81 	else
82 		snprintf(port, sizeof(port), "%u", ntohs(address.sin_port));
83 
84 	snprintf(buffer + length, sizeof(buffer) - length, ":%s", port);
85 
86 	printf("%-22s", buffer);
87 }
88 
89 
90 //	#pragma mark -
91 
92 
93 void
94 usage(int status)
95 {
96 	printf("usage: %s\n", kProgramName);
97 
98 	exit(status);
99 }
100 
101 
102 status_t
103 get_next_stat(int stack, uint32& cookie, int family, net_stat& stat)
104 {
105 	get_next_stat_args args;
106 	args.cookie = cookie;
107 	args.family = family;
108 
109 	if (ioctl(stack, NET_STACK_GET_NEXT_STAT, &args, sizeof(args)) < 0)
110 		return errno;
111 
112 	cookie = args.cookie;
113 	memcpy(&stat, &args.stat, sizeof(net_stat));
114 	return B_OK;
115 }
116 
117 
118 bool
119 get_address_family(const char* argument, int32& familyIndex)
120 {
121 	for (int32 i = 0; kFamilies[i].family >= 0; i++) {
122 		for (int32 j = 0; kFamilies[i].identifiers[j]; j++) {
123 			if (!strcmp(argument, kFamilies[i].identifiers[j])) {
124 				// found a match
125 				familyIndex = i;
126 				return true;
127 			}
128 		}
129 	}
130 
131 	// defaults to AF_INET
132 	familyIndex = 0;
133 	return false;
134 }
135 
136 
137 //	#pragma mark -
138 
139 
140 int
141 main(int argc, char** argv)
142 {
143 	if (argc > 1 && (!strcmp(argv[1], "--help") || !strcmp(argv[1], "-h")))
144 		usage(0);
145 
146 	int stack = open(NET_STACK_DRIVER_PATH, O_RDWR);
147 	if (stack < 0) {
148 		fprintf(stderr, "%s: The networking stack doesn't seem to be available.\n",
149 			kProgramName);
150 		return -1;
151 	}
152 
153 	bool printProgram = true;
154 		// TODO: add some program options... :-)
155 
156 	printf("Proto  Recv-Q Send-Q Local Address         Foreign Address       State        Program\n");
157 
158 	uint32 cookie = 0;
159 	int family = -1;
160 	net_stat stat;
161 	while (get_next_stat(stack, cookie, family, stat) == B_OK) {
162 		protoent* proto = getprotobynumber(stat.protocol);
163 		if (proto != NULL)
164 			printf("%-6s ", proto->p_name);
165 		else
166 			printf("%-6d ", stat.protocol);
167 
168 		printf("%6lu ", stat.receive_queue_size);
169 		printf("%6lu ", stat.send_queue_size);
170 
171 		inet_print_address((sockaddr*)&stat.address);
172 		inet_print_address((sockaddr*)&stat.peer);
173 		printf("%-12s ", stat.state);
174 
175 		team_info info;
176 		if (printProgram && get_team_info(stat.owner, &info) == B_OK) {
177 			// remove arguments
178 			char* name = strchr(info.args, ' ');
179 			if (name != NULL)
180 				name[0] = '\0';
181 
182 			// remove path name
183 			name = strrchr(info.args, '/');
184 			if (name != NULL)
185 				name++;
186 			else
187 				name = info.args;
188 
189 			printf("%ld/%s\n", stat.owner, name);
190 		} else
191 			printf("%ld\n", stat.owner);
192 	}
193 
194 	close(stack);
195 	return 0;
196 }
197 
198