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

Attachment: pgpzMdhcODqZc.pgp
Description: PGP signature

------------------------------------------------------------------------------
What NetFlow Analyzer can do for you? Monitors network bandwidth and traffic
patterns at an interface-level. Reveals which users, apps, and protocols are 
consuming the most bandwidth. Provides multi-vendor support for NetFlow, 
J-Flow, sFlow and other flows. Make informed decisions using capacity 
planning reports. https://ad.doubleclick.net/ddm/clk/305295220;132659582;e
_______________________________________________
Strace-devel mailing list
Strace-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/strace-devel

Reply via email to