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