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