* Implemented a basic infrastructure for a netstat command.
* Started a netstat command. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@19560 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -3,6 +3,7 @@ SubDir HAIKU_TOP src bin network ;
|
||||
SubInclude HAIKU_TOP src bin network arp ;
|
||||
SubInclude HAIKU_TOP src bin network ftp ;
|
||||
SubInclude HAIKU_TOP src bin network ifconfig ;
|
||||
SubInclude HAIKU_TOP src bin network netstat ;
|
||||
#SubInclude HAIKU_TOP src bin network pppconfig ;
|
||||
#SubInclude HAIKU_TOP src bin network ppp_up ;
|
||||
SubInclude HAIKU_TOP src bin network ping ;
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
SubDir HAIKU_TOP src bin network netstat ;
|
||||
|
||||
UsePrivateHeaders net ;
|
||||
|
||||
BinCommand netstat :
|
||||
netstat.cpp
|
||||
: libnetwork.so
|
||||
;
|
||||
@@ -0,0 +1,182 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku, Inc. All Rights Reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Axel Dörfler, [email protected]
|
||||
*/
|
||||
|
||||
|
||||
#include <SupportDefs.h>
|
||||
|
||||
#include <net_stack_driver.h>
|
||||
#include <net_stat.h>
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
#include <net/if.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
extern const char* __progname;
|
||||
const char* kProgramName = __progname;
|
||||
|
||||
|
||||
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("%-28s", "-");
|
||||
return;
|
||||
}
|
||||
|
||||
hostent* host = gethostbyaddr((const char*)_address, sizeof(sockaddr_in), AF_INET);
|
||||
servent* service = getservbyport(ntohs(address.sin_port), NULL);
|
||||
|
||||
char buffer[128];
|
||||
int length = strlcpy(buffer, host != NULL
|
||||
? host->h_name : inet_ntoa(address.sin_addr), sizeof(buffer));
|
||||
|
||||
if (service != NULL)
|
||||
snprintf(buffer + length, sizeof(buffer) - length, ":%s", service->s_name);
|
||||
else
|
||||
snprintf(buffer + length, sizeof(buffer) - length, ":%u", ntohs(address.sin_port));
|
||||
|
||||
printf("%-28s", buffer);
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
void
|
||||
usage(int status)
|
||||
{
|
||||
printf("usage: %s\n", kProgramName);
|
||||
|
||||
exit(status);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
get_next_stat(int stack, uint32& cookie, int family, net_stat& stat)
|
||||
{
|
||||
get_next_stat_args args;
|
||||
args.cookie = cookie;
|
||||
args.family = family;
|
||||
|
||||
if (ioctl(stack, NET_STACK_GET_NEXT_STAT, &args, sizeof(args)) < 0)
|
||||
return errno;
|
||||
|
||||
cookie = args.cookie;
|
||||
memcpy(&stat, &args.stat, sizeof(net_stat));
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
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)
|
||||
{
|
||||
if (argc > 1 && (!strcmp(argv[1], "--help") || !strcmp(argv[1], "-h")))
|
||||
usage(0);
|
||||
|
||||
int stack = open(NET_STACK_DRIVER_PATH, O_RDWR);
|
||||
if (stack < 0) {
|
||||
fprintf(stderr, "%s: The networking stack doesn't seem to be available.\n",
|
||||
kProgramName);
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool printProgram = true;
|
||||
// TODO: add some program options... :-)
|
||||
|
||||
printf("Proto Local Address Foreign Address State Program\n");
|
||||
|
||||
uint32 cookie = 0;
|
||||
int family = -1;
|
||||
net_stat stat;
|
||||
while (get_next_stat(stack, cookie, family, stat) == B_OK) {
|
||||
protoent* proto = getprotobynumber(stat.protocol);
|
||||
if (proto != NULL)
|
||||
printf("%-6s ", proto->p_name);
|
||||
else
|
||||
printf("%-6d ", stat.protocol);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
close(stack);
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user