From: Tim Clem tclem@codeweavers.com
--- dlls/nsiproxy.sys/udp.c | 230 +++++++--------------------------------- server/protocol.def | 32 ++++++ server/sock.c | 67 ++++++++++++ server/trace.c | 31 ++++++ tools/make_requests | 1 + 5 files changed, 172 insertions(+), 189 deletions(-)
diff --git a/dlls/nsiproxy.sys/udp.c b/dlls/nsiproxy.sys/udp.c index 7f59693bf78..1d790484d8f 100644 --- a/dlls/nsiproxy.sys/udp.c +++ b/dlls/nsiproxy.sys/udp.c @@ -203,231 +203,83 @@ static NTSTATUS udp_stats_get_all_parameters( const void *key, UINT key_size, vo return STATUS_NOT_SUPPORTED; }
-#ifdef __APPLE__ -static int pcblist_mib[CTL_MAXNAME]; -static size_t pcblist_mib_len = CTL_MAXNAME; - -static void init_pcblist64_mib( void ) -{ - sysctlnametomib( "net.inet.udp.pcblist64", pcblist_mib, &pcblist_mib_len ); -} -#endif - static NTSTATUS udp_endpoint_enumerate_all( void *key_data, UINT key_size, void *rw_data, UINT rw_size, void *dynamic_data, UINT dynamic_size, void *static_data, UINT static_size, UINT_PTR *count ) { - UINT num = 0; - NTSTATUS status = STATUS_SUCCESS; BOOL want_data = key_size || rw_size || dynamic_size || static_size; struct nsi_udp_endpoint_key key, *key_out = key_data; struct nsi_udp_endpoint_static stat, *stat_out = static_data; struct ipv6_addr_scope *addr_scopes = NULL; - unsigned int addr_scopes_size = 0, pid_map_size = 0; - struct pid_map *pid_map = NULL; + unsigned int addr_scopes_size = 0; + NTSTATUS ret = STATUS_SUCCESS; + udp_endpoint *endpoints = NULL;
TRACE( "%p %d %p %d %p %d %p %d %p\n", key_data, key_size, rw_data, rw_size, dynamic_data, dynamic_size, static_data, static_size, count );
-#ifdef __linux__ + if (want_data) { - FILE *fp; - char buf[512], *ptr; - int inode; - UINT addr; - - if (!(fp = fopen( "/proc/net/udp", "r" ))) return ERROR_NOT_SUPPORTED; - - memset( &key, 0, sizeof(key) ); - memset( &stat, 0, sizeof(stat) ); - if (stat_out) pid_map = get_pid_map( &pid_map_size ); + endpoints = malloc( sizeof(*endpoints) * (*count) ); + if (!endpoints) return STATUS_NO_MEMORY; + }
- /* skip header line */ - ptr = fgets( buf, sizeof(buf), fp ); - while ((ptr = fgets( buf, sizeof(buf), fp ))) + SERVER_START_REQ( get_udp_endpoints ) + { + wine_server_set_reply( req, endpoints, want_data ? (sizeof(*endpoints) * (*count)) : 0 ); + if (!(ret = wine_server_call( req ))) + *count = reply->count; + else if (ret == STATUS_BUFFER_TOO_SMALL) { - if (sscanf( ptr, "%*u: %x:%hx %*s %*s %*s %*s %*s %*s %*s %d", - &addr, &key.local.Ipv4.sin_port, &inode ) != 3) - continue; - - key.local.Ipv4.sin_family = WS_AF_INET; - key.local.Ipv4.sin_addr.WS_s_addr = addr; - key.local.Ipv4.sin_port = htons( key.local.Ipv4.sin_port ); - - if (stat_out) - { - stat.pid = find_owning_pid( pid_map, pid_map_size, inode ); - stat.create_time = 0; /* FIXME */ - stat.flags = 0; /* FIXME */ - stat.mod_info = 0; /* FIXME */ - } - - if (num < *count) + *count = reply->count; + if (want_data) { - if (key_out) *key_out++ = key; - if (stat_out) *stat_out++ = stat; + free( endpoints ); + return STATUS_BUFFER_OVERFLOW; } - num++; - } - fclose( fp ); - - if ((fp = fopen( "/proc/net/udp6", "r" ))) - { - memset( &key, 0, sizeof(key) ); - memset( &stat, 0, sizeof(stat) ); - - addr_scopes = get_ipv6_addr_scope_table( &addr_scopes_size ); - - /* skip header line */ - ptr = fgets( buf, sizeof(buf), fp ); - while ((ptr = fgets( buf, sizeof(buf), fp ))) - { - UINT *local_addr = (UINT *)&key.local.Ipv6.sin6_addr; - - if (sscanf( ptr, "%*u: %8x%8x%8x%8x:%hx %*s %*s %*s %*s %*s %*s %*s %d", - local_addr, local_addr + 1, local_addr + 2, local_addr + 3, - &key.local.Ipv6.sin6_port, &inode ) != 6) - continue; - key.local.Ipv6.sin6_family = WS_AF_INET6; - key.local.Ipv6.sin6_port = htons( key.local.Ipv6.sin6_port ); - key.local.Ipv6.sin6_scope_id = find_ipv6_addr_scope( &key.local.Ipv6.sin6_addr, addr_scopes, - addr_scopes_size ); - - if (stat_out) - { - stat.pid = find_owning_pid( pid_map, pid_map_size, inode ); - stat.create_time = 0; /* FIXME */ - stat.flags = 0; /* FIXME */ - stat.mod_info = 0; /* FIXME */ - } - - if (num < *count) - { - if (key_out) *key_out++ = key; - if (stat_out) *stat_out++ = stat; - } - num++; - } - fclose( fp ); + else return STATUS_SUCCESS; } } -#elif defined(HAVE_SYS_SYSCTL_H) && defined(UDPCTL_PCBLIST) && defined(HAVE_STRUCT_XINPGEN) - { - size_t len = 0; - char *buf = NULL; - struct xinpgen *xig, *orig_xig; - -#ifdef __APPLE__ - static pthread_once_t mib_init_once = PTHREAD_ONCE_INIT; - pthread_once( &mib_init_once, init_pcblist64_mib ); -#else - int pcblist_mib[] = { CTL_NET, PF_INET, IPPROTO_UDP, UDPCTL_PCBLIST }; - size_t pcblist_mib_len = ARRAY_SIZE(pcblist_mib); -#endif - - if (sysctl( pcblist_mib, pcblist_mib_len, NULL, &len, NULL, 0 ) < 0) - { - ERR( "Failure to read net.inet.udp.pcblist via sysctl!\n" ); - status = STATUS_NOT_SUPPORTED; - goto err; - } - - buf = malloc( len ); - if (!buf) - { - status = STATUS_NO_MEMORY; - goto err; - } - - if (sysctl( pcblist_mib, pcblist_mib_len, buf, &len, NULL, 0 ) < 0) - { - ERR( "Failure to read net.inet.udp.pcblist via sysctl!\n" ); - status = STATUS_NOT_SUPPORTED; - goto err; - } + SERVER_END_REQ;
- /* Might be nothing here; first entry is just a header it seems */ - if (len <= sizeof(struct xinpgen)) goto err; + addr_scopes = get_ipv6_addr_scope_table( &addr_scopes_size );
- addr_scopes = get_ipv6_addr_scope_table( &addr_scopes_size ); - if (stat_out) pid_map = get_pid_map( &pid_map_size ); - - orig_xig = (struct xinpgen *)buf; - xig = orig_xig; + for (unsigned int i = 0; i < *count; i++) + { + udp_endpoint *endpt = &endpoints[i];
- for (xig = (struct xinpgen *)((char *)xig + xig->xig_len); - xig->xig_len > sizeof (struct xinpgen); - xig = (struct xinpgen *)((char *)xig + xig->xig_len)) + if (key_out) { -#ifdef __APPLE__ - struct xinpcb64 *in = (struct xinpcb64 *)xig; - struct xsocket64 *sock = &in->xi_socket; -#elif __FreeBSD_version >= 1200026 - struct xinpcb *in = (struct xinpcb *)xig; - struct xsocket *sock = &in->xi_socket; -#else - struct inpcb *in = &((struct xinpcb *)xig)->xi_inp; - struct xsocket *sock = &((struct xinpcb *)xig)->xi_socket; -#endif - static const struct in6_addr zero; - - /* Ignore sockets for other protocols */ - if (sock->xso_protocol != IPPROTO_UDP) continue; - - /* Ignore PCBs that were freed while generating the data */ - if (in->inp_gencnt > orig_xig->xig_gen) continue; - - /* we're only interested in IPv4 and IPv6 addresses */ - if (!(in->inp_vflag & (INP_IPV4 | INP_IPV6))) continue; - - /* If all 0's, skip it */ - if (in->inp_vflag & INP_IPV4 && !in->inp_laddr.s_addr) continue; - if (in->inp_vflag & INP_IPV6 && !memcmp( &in->in6p_laddr, &zero, sizeof(zero) ) && !in->inp_lport) continue; - - if (in->inp_vflag & INP_IPV4) + memset( &key, 0, sizeof(key) ); + if (endpt->common.family == WS_AF_INET) { key.local.Ipv4.sin_family = WS_AF_INET; - key.local.Ipv4.sin_addr.WS_s_addr = in->inp_laddr.s_addr; - key.local.Ipv4.sin_port = in->inp_lport; + key.local.Ipv4.sin_addr.WS_s_addr = endpt->ipv4.addr; + key.local.Ipv4.sin_port = endpt->ipv4.port; } else { key.local.Ipv6.sin6_family = WS_AF_INET6; - memcpy( &key.local.Ipv6.sin6_addr, &in->in6p_laddr, sizeof(in->in6p_laddr) ); - key.local.Ipv6.sin6_port = in->inp_lport; + memcpy( &key.local.Ipv6.sin6_addr, &endpt->ipv6.addr, 16 ); + key.local.Ipv6.sin6_port = endpt->ipv6.port; key.local.Ipv6.sin6_scope_id = find_ipv6_addr_scope( &key.local.Ipv6.sin6_addr, addr_scopes, addr_scopes_size ); } + *key_out++ = key; + }
- if (stat_out) - { - stat.pid = find_owning_pid( pid_map, pid_map_size, (UINT_PTR)sock->so_pcb ); - stat.create_time = 0; /* FIXME */ - stat.flags = !(in->inp_flags & INP_ANONPORT); - stat.mod_info = 0; /* FIXME */ - } - - if (num < *count) - { - if (key_out) *key_out++ = key; - if (stat_out) *stat_out++ = stat; - } - num++; + if (stat_out) + { + memset( &stat, 0, sizeof(stat) ); + stat.pid = endpt->common.owner; + stat.create_time = 0; /* FIXME */ + stat.mod_info = 0; /* FIXME */ + *stat_out++ = stat; } - err: - free( buf ); } -#else - FIXME( "not implemented\n" ); - return STATUS_NOT_IMPLEMENTED; -#endif - - if (!want_data || num <= *count) *count = num; - else status = STATUS_BUFFER_OVERFLOW;
- free( pid_map ); - free( addr_scopes ); - return status; + free( endpoints ); + return STATUS_SUCCESS; }
static struct module_table udp_tables[] = diff --git a/server/protocol.def b/server/protocol.def index 10186946f3f..ba8f9dda0e0 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -3470,6 +3470,38 @@ typedef union @END
+typedef union +{ + struct + { + unsigned int family; + process_id_t owner; + } common; + struct + { + unsigned int family; + process_id_t owner; + unsigned int addr; + unsigned int port; + } ipv4; + struct + { + unsigned int family; + process_id_t owner; + unsigned char addr[16]; + unsigned int scope_id; + unsigned int port; + } ipv6; +} udp_endpoint; + +/* Retrieve a list of all processes' UDP endpoints. */ +@REQ(get_udp_endpoints) +@REPLY + unsigned int count; + VARARG(endpoints,udp_endpoints); +@END + + /* Create a mailslot */ @REQ(create_mailslot) unsigned int access; /* wanted access rights */ diff --git a/server/sock.c b/server/sock.c index fe2ef269e6d..f80f833c302 100644 --- a/server/sock.c +++ b/server/sock.c @@ -4269,3 +4269,70 @@ DECL_HANDLER(get_tcp_connections) enum_handles_of_type( &sock_ops, enum_tcp_connections, &info ); } } + +struct enum_udp_endpoint_info +{ + unsigned int count; + udp_endpoint *endpt; +}; + +static int enum_udp_endpoints( struct process *process, struct object *obj, void *user ) +{ + struct sock *sock = (struct sock *)obj; + struct enum_udp_endpoint_info *info = user; + udp_endpoint *endpt; + + assert( obj->ops == &sock_ops ); + + if (sock->type != WS_SOCK_DGRAM || !(sock->family == WS_AF_INET || sock->family == WS_AF_INET6)) + return 0; + + if (!info->endpt) + { + info->count++; + return 0; + } + + assert( info->count ); + endpt = info->endpt++; + memset( endpt, 0, sizeof(*endpt) ); + + endpt->common.family = sock->family; + endpt->common.owner = process->id; + + if (sock->family == WS_AF_INET) + { + endpt->ipv4.addr = sock->addr.in.sin_addr.WS_s_addr; + endpt->ipv4.port = sock->addr.in.sin_port; + } + else + { + memcpy( &endpt->ipv6.addr, &sock->addr.in6.sin6_addr, 16 ); + endpt->ipv6.scope_id = sock->addr.in6.sin6_scope_id; + endpt->ipv6.port = sock->addr.in6.sin6_port; + } + + info->count--; + + return 0; +} + +DECL_HANDLER(get_udp_endpoints) +{ + struct enum_udp_endpoint_info info; + udp_endpoint *endpt; + data_size_t max_endpts = get_reply_max_size() / sizeof(*endpt); + + info.endpt = NULL; + info.count = 0; + enum_handles_of_type( &sock_ops, enum_udp_endpoints, &info ); + reply->count = info.count; + + if (max_endpts < info.count) + set_error( STATUS_BUFFER_TOO_SMALL ); + else if ((endpt = set_reply_data_size( info.count * sizeof(*endpt) ))) + { + info.endpt = endpt; + enum_handles_of_type( &sock_ops, enum_udp_endpoints, &info ); + } +} diff --git a/server/trace.c b/server/trace.c index cf3768f5a65..08179b60852 100644 --- a/server/trace.c +++ b/server/trace.c @@ -1447,6 +1447,37 @@ static void dump_varargs_tcp_connections( const char *prefix, data_size_t size ) fputc( '}', stderr ); }
+static void dump_varargs_udp_endpoints( const char *prefix, data_size_t size ) +{ + const udp_endpoint *endpt; + + fprintf( stderr, "%s{", prefix ); + while (size >= sizeof(*endpt)) + { + endpt = cur_data; + + if (endpt->common.family == WS_AF_INET) + { + char addr_str[INET_ADDRSTRLEN] = { 0 }; + inet_ntop( AF_INET, (struct in_addr *)&endpt->ipv4.addr, addr_str, INET_ADDRSTRLEN ); + fprintf( stderr, "{family=AF_INET,owner=%04x,addr=%s:%d}", + endpt->ipv4.owner, addr_str, endpt->ipv4.port ); + } + else + { + char addr_str[INET6_ADDRSTRLEN]; + inet_ntop( AF_INET6, (struct in6_addr *)&endpt->ipv6.addr, addr_str, INET6_ADDRSTRLEN ); + fprintf( stderr, "{family=AF_INET6,owner=%04x,addr=[%s%%%d]:%d}", + endpt->ipv6.owner, addr_str, endpt->ipv6.scope_id, endpt->ipv6.port ); + } + + size -= sizeof(*endpt); + remove_data( sizeof(*endpt) ); + if (size) fputc( ',', stderr ); + } + fputc( '}', stderr ); +} + static void dump_varargs_directory_entries( const char *prefix, data_size_t size ) { fprintf( stderr, "%s{", prefix ); diff --git a/tools/make_requests b/tools/make_requests index 65ddcd0ffb8..831e121b287 100755 --- a/tools/make_requests +++ b/tools/make_requests @@ -65,6 +65,7 @@ my %formats = "select_op_t" => [ 264, 8 ], "startup_info_t" => [ 96, 4 ], "tcp_connection" => [ 60, 4 ], + "udp_endpoint" => [ 32, 4 ], "user_apc_t" => [ 40, 8 ], "struct filesystem_event" => [ 12, 4 ], "struct handle_info" => [ 20, 4 ],