* 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:
parent
6f9f14ec88
commit
8dfd7ea7bf
@ -11,10 +11,10 @@
|
|||||||
|
|
||||||
|
|
||||||
// level flags to pass to control()
|
// level flags to pass to control()
|
||||||
#define LEVEL_SET_OPTION 0x10000000
|
#define LEVEL_SET_OPTION 0x10000000
|
||||||
#define LEVEL_GET_OPTION 0x20000000
|
#define LEVEL_GET_OPTION 0x20000000
|
||||||
#define LEVEL_DRIVER_IOCTL 0x0f000000
|
#define LEVEL_DRIVER_IOCTL 0x0f000000
|
||||||
#define LEVEL_MASK 0x0fffffff
|
#define LEVEL_MASK 0x0fffffff
|
||||||
|
|
||||||
typedef struct net_protocol {
|
typedef struct net_protocol {
|
||||||
struct net_protocol *next;
|
struct net_protocol *next;
|
||||||
|
@ -68,6 +68,8 @@ struct net_socket_module_info {
|
|||||||
status_t (*receive_data)(net_socket *socket, size_t length, uint32 flags,
|
status_t (*receive_data)(net_socket *socket, size_t length, uint32 flags,
|
||||||
net_buffer **_buffer);
|
net_buffer **_buffer);
|
||||||
|
|
||||||
|
status_t (*get_next_stat)(uint32 *cookie, int family, struct net_stat *stat);
|
||||||
|
|
||||||
// connections
|
// connections
|
||||||
status_t (*spawn_pending_socket)(net_socket *parent, net_socket **_socket);
|
status_t (*spawn_pending_socket)(net_socket *parent, net_socket **_socket);
|
||||||
void (*delete_socket)(net_socket *socket);
|
void (*delete_socket)(net_socket *socket);
|
||||||
|
@ -6,10 +6,9 @@
|
|||||||
#define NET_STACK_DRIVER_H
|
#define NET_STACK_DRIVER_H
|
||||||
|
|
||||||
|
|
||||||
#include <OS.h>
|
#include <net_stat.h>
|
||||||
|
|
||||||
#include <sys/select.h>
|
#include <sys/select.h>
|
||||||
#include <sys/socket.h>
|
|
||||||
|
|
||||||
|
|
||||||
// Forward declaration
|
// Forward declaration
|
||||||
@ -26,8 +25,8 @@ enum {
|
|||||||
NET_STACK_SOCKET = NET_STACK_IOCTL_BASE, // socket_args *
|
NET_STACK_SOCKET = NET_STACK_IOCTL_BASE, // socket_args *
|
||||||
NET_STACK_GET_COOKIE, // void **
|
NET_STACK_GET_COOKIE, // void **
|
||||||
NET_STACK_CONTROL_NET_MODULE, // control_net_module_args *
|
NET_STACK_CONTROL_NET_MODULE, // control_net_module_args *
|
||||||
NET_STACK_SYSCTL, // sysctl_args *
|
NET_STACK_GET_NEXT_STAT, // get_next_stat_args *
|
||||||
|
|
||||||
// ops acting on an existing socket
|
// ops acting on an existing socket
|
||||||
NET_STACK_BIND, // sockaddr_args *
|
NET_STACK_BIND, // sockaddr_args *
|
||||||
NET_STACK_RECVFROM, // struct msghdr *
|
NET_STACK_RECVFROM, // struct msghdr *
|
||||||
@ -43,13 +42,9 @@ enum {
|
|||||||
NET_STACK_GETSOCKNAME, // sockaddr_args *
|
NET_STACK_GETSOCKNAME, // sockaddr_args *
|
||||||
NET_STACK_GETPEERNAME, // sockaddr_args *
|
NET_STACK_GETPEERNAME, // sockaddr_args *
|
||||||
NET_STACK_SOCKETPAIR, // socketpair_args *
|
NET_STACK_SOCKETPAIR, // socketpair_args *
|
||||||
|
|
||||||
// TODO: remove R5 select() emulation
|
|
||||||
NET_STACK_SELECT, // select_args *
|
|
||||||
NET_STACK_DESELECT, // select_args *
|
|
||||||
|
|
||||||
NET_STACK_NOTIFY_SOCKET_EVENT, // notify_socket_event_args * (userland stack only)
|
NET_STACK_NOTIFY_SOCKET_EVENT, // notify_socket_event_args * (userland stack only)
|
||||||
|
|
||||||
NET_STACK_IOCTL_MAX
|
NET_STACK_IOCTL_MAX
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -89,13 +84,10 @@ struct accept_args { // used by NET_STACK_ACCEPT
|
|||||||
socklen_t address_length;
|
socklen_t address_length;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct sysctl_args { // used by NET_STACK_SYSCTL
|
struct get_next_stat_args { // used by NET_STACK_GET_NEXT_STAT
|
||||||
int *name;
|
uint32 cookie;
|
||||||
uint namelen;
|
int family;
|
||||||
void *oldp;
|
struct net_stat stat;
|
||||||
size_t *oldlenp;
|
|
||||||
void *newp;
|
|
||||||
size_t newlen;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct control_net_module_args { // used by NET_STACK_CONTROL_NET_MODULE
|
struct control_net_module_args { // used by NET_STACK_CONTROL_NET_MODULE
|
||||||
|
28
headers/private/net/net_stat.h
Normal file
28
headers/private/net/net_stat.h
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2006, Haiku, Inc. All Rights Reserved.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
#ifndef NET_STAT_H
|
||||||
|
#define NET_STAT_H
|
||||||
|
|
||||||
|
|
||||||
|
#include <OS.h>
|
||||||
|
|
||||||
|
#include <sys/socket.h>
|
||||||
|
|
||||||
|
|
||||||
|
#define NET_STAT_SOCKET 1
|
||||||
|
#define NET_STAT_PROTOCOL 2
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct net_stat {
|
||||||
|
int family;
|
||||||
|
int type;
|
||||||
|
int protocol;
|
||||||
|
char state[B_OS_NAME_LENGTH];
|
||||||
|
team_id owner;
|
||||||
|
struct sockaddr_storage address;
|
||||||
|
struct sockaddr_storage peer;
|
||||||
|
} net_stat;
|
||||||
|
|
||||||
|
#endif // NET_STAT_H
|
@ -262,6 +262,20 @@ net_stack_control(void *_cookie, uint32 op, void *data, size_t length)
|
|||||||
// of the file descriptor to use for the new accepted socket
|
// of the file descriptor to use for the new accepted socket
|
||||||
return user_memcpy(data, cookie, sizeof(void *));
|
return user_memcpy(data, cookie, sizeof(void *));
|
||||||
|
|
||||||
|
case NET_STACK_GET_NEXT_STAT:
|
||||||
|
{
|
||||||
|
get_next_stat_args args;
|
||||||
|
status = check_args(args, data, length);
|
||||||
|
if (status < B_OK)
|
||||||
|
return status;
|
||||||
|
|
||||||
|
status = sSocket->get_next_stat(&args.cookie, args.family, &args.stat);
|
||||||
|
if (status < B_OK)
|
||||||
|
return status;
|
||||||
|
|
||||||
|
return user_memcpy(data, &args, sizeof(get_next_stat_args));
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return B_BAD_VALUE;
|
return B_BAD_VALUE;
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
#include "TCPEndpoint.h"
|
#include "TCPEndpoint.h"
|
||||||
|
|
||||||
#include <net_protocol.h>
|
#include <net_protocol.h>
|
||||||
|
#include <net_stat.h>
|
||||||
|
|
||||||
#include <KernelExport.h>
|
#include <KernelExport.h>
|
||||||
#include <util/list.h>
|
#include <util/list.h>
|
||||||
@ -259,6 +260,43 @@ reply_with_reset(tcp_segment_header &segment, net_buffer *buffer)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static const char *
|
||||||
|
name_for_state(tcp_state state)
|
||||||
|
{
|
||||||
|
switch (state) {
|
||||||
|
case CLOSED:
|
||||||
|
return "closed";
|
||||||
|
case LISTEN:
|
||||||
|
return "listen";
|
||||||
|
case SYNCHRONIZE_SENT:
|
||||||
|
return "syn-sent";
|
||||||
|
case SYNCHRONIZE_RECEIVED:
|
||||||
|
return "syn-received";
|
||||||
|
case ESTABLISHED:
|
||||||
|
return "established";
|
||||||
|
|
||||||
|
// peer closes the connection
|
||||||
|
case FINISH_RECEIVED:
|
||||||
|
return "close-wait";
|
||||||
|
case WAIT_FOR_FINISH_ACKNOWLEDGE:
|
||||||
|
return "last-ack";
|
||||||
|
|
||||||
|
// we close the connection
|
||||||
|
case FINISH_SENT:
|
||||||
|
return "fin-wait1";
|
||||||
|
case FINISH_ACKNOWLEDGED:
|
||||||
|
return "fin-wait2";
|
||||||
|
case CLOSING:
|
||||||
|
return "closing";
|
||||||
|
|
||||||
|
case TIME_WAIT:
|
||||||
|
return "time-wait";
|
||||||
|
}
|
||||||
|
|
||||||
|
return "-";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// #pragma mark - protocol API
|
// #pragma mark - protocol API
|
||||||
|
|
||||||
|
|
||||||
@ -328,11 +366,29 @@ tcp_accept(net_protocol *protocol, struct net_socket **_acceptedSocket)
|
|||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
tcp_control(net_protocol *protocol, int level, int option, void *value,
|
tcp_control(net_protocol *_protocol, int level, int option, void *value,
|
||||||
size_t *_length)
|
size_t *_length)
|
||||||
{
|
{
|
||||||
return protocol->next->module->control(protocol->next, level, option,
|
TCPEndpoint *protocol = (TCPEndpoint *)_protocol;
|
||||||
value, _length);
|
|
||||||
|
switch (level & LEVEL_MASK) {
|
||||||
|
case IPPROTO_TCP:
|
||||||
|
if (option == NET_STAT_SOCKET) {
|
||||||
|
net_stat *stat = (net_stat *)value;
|
||||||
|
strlcpy(stat->state, name_for_state(protocol->State()),
|
||||||
|
sizeof(stat->state));
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SOL_SOCKET:
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return protocol->next->module->control(protocol->next, level, option,
|
||||||
|
value, _length);
|
||||||
|
}
|
||||||
|
|
||||||
|
return B_BAD_VALUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
#include <net_protocol.h>
|
#include <net_protocol.h>
|
||||||
#include <net_stack.h>
|
#include <net_stack.h>
|
||||||
|
#include <net_stat.h>
|
||||||
|
|
||||||
#include <KernelExport.h>
|
#include <KernelExport.h>
|
||||||
#include <util/AutoLock.h>
|
#include <util/AutoLock.h>
|
||||||
@ -26,6 +27,9 @@
|
|||||||
void socket_delete(net_socket *socket);
|
void socket_delete(net_socket *socket);
|
||||||
int socket_bind(net_socket *socket, const struct sockaddr *address, socklen_t addressLength);
|
int socket_bind(net_socket *socket, const struct sockaddr *address, socklen_t addressLength);
|
||||||
|
|
||||||
|
struct list sSocketList;
|
||||||
|
benaphore sSocketLock;
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
static status_t
|
||||||
create_socket(int family, int type, int protocol, net_socket **_socket)
|
create_socket(int family, int type, int protocol, net_socket **_socket)
|
||||||
@ -86,6 +90,10 @@ socket_open(int family, int type, int protocol, net_socket **_socket)
|
|||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
benaphore_lock(&sSocketLock);
|
||||||
|
list_add_item(&sSocketList, socket);
|
||||||
|
benaphore_unlock(&sSocketLock);
|
||||||
|
|
||||||
*_socket = socket;
|
*_socket = socket;
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
@ -209,6 +217,45 @@ socket_receive_data(net_socket *socket, size_t length, uint32 flags,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
socket_get_next_stat(uint32 *_cookie, int family, struct net_stat *stat)
|
||||||
|
{
|
||||||
|
BenaphoreLocker locker(sSocketLock);
|
||||||
|
|
||||||
|
net_socket *socket = NULL;
|
||||||
|
uint32 cookie = *_cookie;
|
||||||
|
uint32 count = 0;
|
||||||
|
while ((socket = (net_socket *)list_get_next_item(&sSocketList, socket)) != NULL) {
|
||||||
|
if (count == cookie)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (family == -1 || family == socket->family)
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (socket == NULL)
|
||||||
|
return B_ENTRY_NOT_FOUND;
|
||||||
|
|
||||||
|
*_cookie = count + 1;
|
||||||
|
|
||||||
|
stat->family = socket->family;
|
||||||
|
stat->type = socket->type;
|
||||||
|
stat->protocol = socket->protocol;
|
||||||
|
stat->owner = -1;
|
||||||
|
|
||||||
|
stat->state[0] = '\0';
|
||||||
|
memcpy(&stat->address, &socket->address, sizeof(struct sockaddr_storage));
|
||||||
|
memcpy(&stat->peer, &socket->peer, sizeof(struct sockaddr_storage));
|
||||||
|
|
||||||
|
// fill in protocol specific data (if supported by the protocol)
|
||||||
|
size_t length = sizeof(net_stat);
|
||||||
|
socket->first_info->control(socket->first_protocol, socket->protocol,
|
||||||
|
NET_STAT_SOCKET, stat, &length);
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// #pragma mark - connections
|
// #pragma mark - connections
|
||||||
|
|
||||||
|
|
||||||
@ -252,6 +299,10 @@ socket_delete(net_socket *socket)
|
|||||||
if (socket->parent != NULL)
|
if (socket->parent != NULL)
|
||||||
panic("socket still has a parent!");
|
panic("socket still has a parent!");
|
||||||
|
|
||||||
|
benaphore_lock(&sSocketLock);
|
||||||
|
list_remove_item(&sSocketList, socket);
|
||||||
|
benaphore_unlock(&sSocketLock);
|
||||||
|
|
||||||
put_domain_protocols(socket);
|
put_domain_protocols(socket);
|
||||||
benaphore_destroy(&socket->lock);
|
benaphore_destroy(&socket->lock);
|
||||||
delete_select_sync_pool(socket->select_pool);
|
delete_select_sync_pool(socket->select_pool);
|
||||||
@ -272,7 +323,15 @@ socket_dequeue_connected(net_socket *parent, net_socket **_socket)
|
|||||||
}
|
}
|
||||||
|
|
||||||
benaphore_unlock(&parent->lock);
|
benaphore_unlock(&parent->lock);
|
||||||
return socket != NULL ? B_OK : B_ENTRY_NOT_FOUND;
|
|
||||||
|
if (socket == NULL)
|
||||||
|
return B_ENTRY_NOT_FOUND;
|
||||||
|
|
||||||
|
benaphore_lock(&sSocketLock);
|
||||||
|
list_add_item(&sSocketList, socket);
|
||||||
|
benaphore_unlock(&sSocketLock);
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -924,9 +983,12 @@ socket_std_ops(int32 op, ...)
|
|||||||
// initialize the main stack if not done so already
|
// initialize the main stack if not done so already
|
||||||
//module_info *module;
|
//module_info *module;
|
||||||
//return get_module(NET_STARTER_MODULE_NAME, &module);
|
//return get_module(NET_STARTER_MODULE_NAME, &module);
|
||||||
|
list_init_etc(&sSocketList, offsetof(net_socket, link));
|
||||||
|
return benaphore_init(&sSocketLock, "socket list");
|
||||||
}
|
}
|
||||||
case B_MODULE_UNINIT:
|
case B_MODULE_UNINIT:
|
||||||
//return put_module(NET_STARTER_MODULE_NAME);
|
//return put_module(NET_STARTER_MODULE_NAME);
|
||||||
|
benaphore_destroy(&sSocketLock);
|
||||||
return B_OK;
|
return B_OK;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -955,6 +1017,8 @@ net_socket_module_info gNetSocketModule = {
|
|||||||
socket_send_data,
|
socket_send_data,
|
||||||
socket_receive_data,
|
socket_receive_data,
|
||||||
|
|
||||||
|
socket_get_next_stat,
|
||||||
|
|
||||||
// connections
|
// connections
|
||||||
socket_spawn_pending,
|
socket_spawn_pending,
|
||||||
socket_delete,
|
socket_delete,
|
||||||
|
@ -3,6 +3,7 @@ SubDir HAIKU_TOP src bin network ;
|
|||||||
SubInclude HAIKU_TOP src bin network arp ;
|
SubInclude HAIKU_TOP src bin network arp ;
|
||||||
SubInclude HAIKU_TOP src bin network ftp ;
|
SubInclude HAIKU_TOP src bin network ftp ;
|
||||||
SubInclude HAIKU_TOP src bin network ifconfig ;
|
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 pppconfig ;
|
||||||
#SubInclude HAIKU_TOP src bin network ppp_up ;
|
#SubInclude HAIKU_TOP src bin network ppp_up ;
|
||||||
SubInclude HAIKU_TOP src bin network ping ;
|
SubInclude HAIKU_TOP src bin network ping ;
|
||||||
|
8
src/bin/network/netstat/Jamfile
Normal file
8
src/bin/network/netstat/Jamfile
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
SubDir HAIKU_TOP src bin network netstat ;
|
||||||
|
|
||||||
|
UsePrivateHeaders net ;
|
||||||
|
|
||||||
|
BinCommand netstat :
|
||||||
|
netstat.cpp
|
||||||
|
: libnetwork.so
|
||||||
|
;
|
182
src/bin/network/netstat/netstat.cpp
Normal file
182
src/bin/network/netstat/netstat.cpp
Normal file
@ -0,0 +1,182 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2006, Haiku, Inc. All Rights Reserved.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Axel Dörfler, axeld@pinc-software.de
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user