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
27extern const char* __progname;
28const char* kProgramName = __progname;
29
30static int sResolveNames = 1;
31
32struct 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
40static void inet_print_address(sockaddr* address);
41
42static 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
53static void
54inet_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
99void
100usage(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
111bool
112get_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
133int
134main(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