/*
 * Copyright 2006-2009, Haiku, Inc. All Rights Reserved.
 * Distributed under the terms of the MIT License.
 *
 * Authors:
 *		Axel Dörfler, axeld@pinc-software.de
 *		James Woodcock
 */
 
#include <arpa/inet.h>
#include <errno.h>
#include <getopt.h>
#include <net/if.h>
#include <netdb.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
 
#include <SupportDefs.h>
 
#include <net_stat.h>
#include <syscalls.h>
 
 
extern const char* __progname;
const char* kProgramName = __progname;
 
static int sResolveNames = 1;
 
struct address_family {
	int			family;
	const char*	name;
	const char*	identifiers[4];
	void		(*print_address)(sockaddr* address);
};
 
// AF_INET family
static void inet_print_address(sockaddr* address);
 
static const address_family kFamilies[] = {
	{
		AF_INET,
		"inet",
		{"AF_INET", "inet", "ipv4", NULL},
		inet_print_address
	},
	{ -1, NULL, {NULL}, NULL }
};
 
 
static void
inet_print_address(sockaddr* _address)
{
	sockaddr_in& address = *(sockaddr_in *)_address;
 
	if (address.sin_family != AF_INET || address.sin_len == 0) {
		printf("%-22s", "-");
		return;
	}
 
	hostent* host = NULL;
	servent* service = NULL;
	if (sResolveNames) {
		host = gethostbyaddr((const char*)&address.sin_addr, sizeof(in_addr),
			AF_INET);
		service = getservbyport(address.sin_port, NULL);
	}
 
	const char *hostName;
	if (host != NULL)
		hostName = host->h_name;
	else if (address.sin_addr.s_addr == INADDR_ANY)
		hostName = "*";
	else
		hostName = inet_ntoa(address.sin_addr);
 
	char buffer[128];
	int length = strlcpy(buffer, hostName, sizeof(buffer));
 
	char port[64];
	if (service != NULL)
		strlcpy(port, service->s_name, sizeof(port));
	else if (address.sin_port == 0)
		strcpy(port, "*");
	else
		snprintf(port, sizeof(port), "%u", ntohs(address.sin_port));
 
	snprintf(buffer + length, sizeof(buffer) - length, ":%s", port);
 
	printf("%-22s", buffer);
}
 
 
//	#pragma mark -
 
 
void
usage(int status)
{
	printf("usage: %s [-nh]\n", kProgramName);
	printf("options:\n");
	printf("	-n	don't resolve names\n");
	printf("	-h	this help\n");
 
	exit(status);
}
 
 
bool
get_address_family(const char* argument, int32& familyIndex)
{
	for (int32 i = 0; kFamilies[i].family >= 0; i++) {
		for (int32 j = 0; kFamilies[i].identifiers[j]; j++) {
			if (!strcmp(argument, kFamilies[i].identifiers[j])) {
				// found a match
				familyIndex = i;
				return true;
			}
		}
	}
 
	// defaults to AF_INET
	familyIndex = 0;
	return false;
}
 
 
//	#pragma mark -
 
 
int
main(int argc, char** argv)
{
	int optionIndex = 0;
	int opt;
	static struct option longOptions[] = {
		{"help", no_argument, 0, 'h'},
		{"numeric", no_argument, 0, 'n'},
		{0, 0, 0, 0}
	};
 
	do {
		opt = getopt_long(argc, argv, "hn", longOptions, &optionIndex);
		switch (opt) {
			case -1:
				// end of arguments, do nothing
				break;
 
			case 'n':
				sResolveNames = 0;
				break;
 
			case 'h':
			default:
				usage(0);
				break;
		}
	} while (opt != -1);
 
	bool printProgram = true;
		// TODO: add some more program options... :-)
 
	printf("Proto  Recv-Q Send-Q Local Address         Foreign Address       "
		"State        Program\n");
 
	uint32 cookie = 0;
	int family = -1;
	net_stat stat;
	while (_kern_get_next_socket_stat(family, &cookie, &stat) == B_OK) {
		protoent* proto = getprotobynumber(stat.protocol);
		if (proto != NULL)
			printf("%-6s ", proto->p_name);
		else
			printf("%-6d ", stat.protocol);
 
		printf("%6lu ", stat.receive_queue_size);
		printf("%6lu ", stat.send_queue_size);
 
		inet_print_address((sockaddr*)&stat.address);
		inet_print_address((sockaddr*)&stat.peer);
		printf("%-12s ", stat.state);
 
		team_info info;
		if (printProgram && get_team_info(stat.owner, &info) == B_OK) {
			// remove arguments
			char* name = strchr(info.args, ' ');
			if (name != NULL)
				name[0] = '\0';
 
			// remove path name
			name = strrchr(info.args, '/');
			if (name != NULL)
				name++;
			else
				name = info.args;
 
			printf("%ld/%s\n", stat.owner, name);
		} else
			printf("%ld\n", stat.owner);
	}
 
	return 0;
}
 

V576 Incorrect format. Consider checking the second actual argument of the 'printf' function. The memsize type argument is expected.

V576 Incorrect format. Consider checking the second actual argument of the 'printf' function. The memsize type argument is expected.