[PATCH v2 1/7] Make getfdproto returns integer instead of string
Dmitry V. Levin
ldv at altlinux.org
Tue Jun 14 11:54:14 UTC 2016
On Mon, Jun 13, 2016 at 02:37:21PM +0000, Fabien Siron wrote:
> This commit aims to avoid future string comparisons with getfdproto function
> in changing its return type. It also adapts the functions that use it.
>
> * defs.h (print_sockaddr_by_inode): Add.
> * socketutils.h (socket_protocols): New enum.
> * socketutils.c (print_sockaddr_by_inode): Move proto to int.
> * util.c (socket_protocol_strings): New global structure.
> (getfdproto): Return int instead of string.
> (printfd): Change type of proto.
> ---
> defs.h | 2 +-
> socketutils.c | 61 ++++++++++++++++++++++++++++++++++++++---------------------
> socketutils.h | 42 ++++++++++++++++++++++++++++++++++++++++
> util.c | 34 ++++++++++++++++++++++++---------
> 4 files changed, 107 insertions(+), 32 deletions(-)
> create mode 100644 socketutils.h
>
> diff --git a/defs.h b/defs.h
> index f7a85ca..594a292 100644
> --- a/defs.h
> +++ b/defs.h
> @@ -631,7 +631,7 @@ extern void printpathn(struct tcb *, long, unsigned int);
> #define TIMESPEC_TEXT_BUFSIZE \
> (sizeof(intmax_t)*3 * 2 + sizeof("{tv_sec=%jd, tv_nsec=%jd}"))
> extern void printfd(struct tcb *, int);
> -extern bool print_sockaddr_by_inode(const unsigned long, const char *);
> +extern bool print_sockaddr_by_inode(const unsigned long, const int);
As this new enum is going to be exposed this way to every user via defs.h,
let's define this enum in defs.h, too.
> extern bool print_sockaddr_by_inode_cached(const unsigned long);
> extern void print_dirfd(struct tcb *, int);
> extern void printsock(struct tcb *, long, int);
> diff --git a/socketutils.c b/socketutils.c
> index 5d8d3ed..0ac8463 100644
> --- a/socketutils.c
> +++ b/socketutils.c
> @@ -438,44 +438,61 @@ netlink_print(const int fd, const unsigned long inode)
> netlink_parse_response);
> }
>
> +#include "socketutils.h"
> /* Given an inode number of a socket, print out the details
> * of the ip address and port. */
> bool
> -print_sockaddr_by_inode(const unsigned long inode, const char *const proto_name)
> +print_sockaddr_by_inode(const unsigned long inode, const int proto)
> {
> - static const struct {
> - const char *const name;
> - bool (*const print)(int, unsigned long);
> - } protocols[] = {
> - { "TCP", tcp_v4_print },
> - { "UDP", udp_v4_print },
> - { "TCPv6", tcp_v6_print },
> - { "UDPv6", udp_v6_print },
> - { "UNIX", unix_print },
> - { "NETLINK", netlink_print }
> - };
> -
What's wrong with storing this kind of information in a table?
> const int fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_SOCK_DIAG);
> if (fd < 0)
> return false;
> bool r = false;
> unsigned int i;
>
> - if (proto_name) {
> - for (i = 0; i < ARRAY_SIZE(protocols); ++i) {
> - if (strcmp(proto_name, protocols[i].name) == 0) {
> - r = protocols[i].print(fd, inode);
> - break;
> - }
> + if (proto != -1) {
> + r = true;
> +
> + switch (proto) {
> + case TCP:
> + r = tcp_v4_print(fd, inode);
> + break;
> + case UDP:
> + r = udp_v4_print(fd, inode);
> + break;
> + case TCPv6:
> + r = tcp_v6_print(fd, inode);
> + break;
> + case UDPv6:
> + r = udp_v6_print(fd, inode);
> + break;
> + case UNIX:
> + r = unix_print(fd, inode);
> + break;
> + case NETLINK:
> + r = netlink_print(fd, inode);
> + break;
> + default:
> + r = false;
> }
Is this switch statement better than a table?
>
> if (!r) {
> - tprintf("%s:[%lu]", proto_name, inode);
> + tprintf("%s:[%lu]",
> + socket_protocol_strings[proto],
> + inode);
If proto is not one of these 6 enums, this would result to read out of array bounds.
> r = true;
> }
> } else {
> - for (i = 0; i < ARRAY_SIZE(protocols); ++i) {
> - if ((r = protocols[i].print(fd, inode)))
> +
> + bool (*const protocols_print[])(int, unsigned long) =
> + {
> + tcp_v4_print, udp_v4_print,
> + tcp_v6_print, udp_v6_print,
> + unix_print, netlink_print
> + };
If you've ended up with a table, why not just have a table?
For example,
/* defs.h */
enum sock_proto {
SOCK_PROTO_UNKNOWN,
SOCK_PROTO_UNIX,
SOCK_PROTO_TCP,
SOCK_PROTO_UDP,
SOCK_PROTO_TCPv6,
SOCK_PROTO_UDPv6,
SOCK_PROTO_NETLINK
};
extern bool print_sockaddr_by_inode(const unsigned long, const enum sock_proto);
/* socketutils.c */
static const struct {
const char *const name;
bool (*const print)(int, unsigned long);
} protocols[] = {
[SOCK_PROTO_UNIX] = { "UNIX", unix_print },
[SOCK_PROTO_TCP] = { "TCP", tcp_v4_print },
[SOCK_PROTO_UDP] = { "UDP", udp_v4_print },
[SOCK_PROTO_TCPv6] = { "TCPv6", tcp_v6_print },
[SOCK_PROTO_UDPv6] = { "UDPv6", udp_v6_print },
[SOCK_PROTO_NETLINK] = { "NETLINK", netlink_print }
};
print_sockaddr_by_inode(const unsigned long inode,
const enum sock_proto proto)
{
if ((unsigned int) proto >= ARRAY_SIZE(protocols) ||
(proto != SOCK_PROTO_UNKNOWN && !protocols[proto].print))
return false;
const int fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_SOCK_DIAG);
if (fd < 0)
return false;
bool r = false;
if (proto != SOCK_PROTO_UNKNOWN) {
r = protocols[proto].print(fd, inode);
if (!r) {
tprintf("%s:[%lu]", protocols[proto].name, inode);
r = true;
}
} else {
unsigned int i;
for (i = (unsigned int) SOCK_PROTO_UNKNOWN + 1;
i < ARRAY_SIZE(protocols); ++i) {
if (!protocols[i].print)
continue;
r = protocols[i].print(fd, inode);
if (r)
break;
}
}
close(fd);
return r;
}
> +#ifndef SOCKETUTILS_H
> +# define SOCKETUTILS_H
> +
> +enum {
> + NETLINK = 0,
> + TCP = 1,
> + TCPv6,
> + UDP,
> + UDPv6,
> + UNIX
These names are too short, let's use something that's less likely to collide.
> +} socket_protocols;
Here a variable is being created, which is probably not what you want.
> +extern const char *socket_protocol_strings[];
Since users of this array cannot ensure that out-of-bounds access doesn't
happen, I don't think exporing this internal array is a good idea.
Let's define a function that takes a string and returns the
corresponding enum value.
For example,
enum sock_proto
get_proto_by_name(const char *const name)
{
unsigned int i;
for (i = (unsigned int) SOCK_PROTO_UNKNOWN + 1;
i < ARRAY_SIZE(protocols); ++i) {
if (protocols[i].name && !strcmp(name, protocols[i].name))
return (enum sock_proto) i;
}
return SOCK_PROTO_UNKNOWN;
}
--
ldv
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 819 bytes
Desc: not available
URL: <http://lists.strace.io/pipermail/strace-devel/attachments/20160614/38ec5a3a/attachment.bin>
More information about the Strace-devel
mailing list