diff options
author | Christopher Faylor <me@cgf.cx> | 2003-09-01 02:02:15 +0400 |
---|---|---|
committer | Christopher Faylor <me@cgf.cx> | 2003-09-01 02:02:15 +0400 |
commit | edf16a29fc6841a30c5cf69bacd7a1e6add77163 (patch) | |
tree | 8d9cf3d8bd154673d028747dbfee7da55e3a283a /winsup/cygwin/net.cc | |
parent | f8e2f358c498417f044e17a5977cc796159bba95 (diff) |
* net.cc (free_char_list): Delete.
(dup_addr_list): Delete.
(dup_char_list): Delete.
(free_hostent_ptr): Delete.
(free_protoent_ptr): Delete.
(free_servent_ptr): Delete.
(DWORD_round): New function.
(strlen_round): New function. Returns strlen rounded up to word size.
(dup_ent): New, generic function to duplicate a {host,proto,serv}ent structure.
(gen_ent): New macro. Generates a generic dup_{host,proto,serv}ent_ptr
function.
(cygwin_getservbyname): Remove call to free_servent_ptr, pass servent_buf to
dup_servent_ptr.
(cygwin_getservbyport): Ditto.
(cygwin_gethostbyname): Ditto for hostent.
(cygwin_gethostbyaddr): Ditto.
(cygwin_getprotobyname): Ditto for protoent.
(cygwin_getprotobynumber): Ditto.
Diffstat (limited to 'winsup/cygwin/net.cc')
-rw-r--r-- | winsup/cygwin/net.cc | 383 |
1 files changed, 192 insertions, 191 deletions
diff --git a/winsup/cygwin/net.cc b/winsup/cygwin/net.cc index 36463c3b4..84f438096 100644 --- a/winsup/cygwin/net.cc +++ b/winsup/cygwin/net.cc @@ -25,6 +25,7 @@ details. */ #include <netdb.h> #define USE_SYS_TYPES_FD_SET #include <winsock2.h> +#include <assert.h> #include "cygerrno.h" #include "security.h" #include "fhandler.h" @@ -381,97 +382,212 @@ set_host_errno () h_errno = NETDB_INTERNAL; } -static void -free_char_list (char **clist) +inline int +DWORD_round (int n) { - if (clist) - { - for (char **cl = clist; *cl; ++cl) - free (*cl); - free (clist); - } + return sizeof (DWORD) * (((n + sizeof (DWORD) - 1)) / sizeof (DWORD)); } -static char ** -dup_char_list (char **src) +inline int +strlen_round (const char *s) { - char **dst; - int cnt = 0; - - for (char **cl = src; *cl; ++cl) - ++cnt; - if (!(dst = (char **) calloc (cnt + 1, sizeof *dst))) - return NULL; - while (cnt-- > 0) - if (!(dst[cnt] = strdup (src[cnt]))) - return NULL; - return dst; + if (!s) + return 0; + return DWORD_round (strlen (s) + 1); } -#define free_addr_list(addr_list) free_char_list (addr_list) +enum struct_type +{ + is_protoent, is_servent, is_hostent +}; -static char ** -dup_addr_list (char **src, unsigned int size) +#pragma pack(push,2) +struct pservent { - char **dst; - int cnt = 0; + char *s_name; + char **s_aliases; + short s_port; + char *s_proto; +}; +#pragma pack(pop) - for (char **cl = src; *cl; ++cl) - ++cnt; - if (!(dst = (char **) calloc (cnt + 1, sizeof *dst))) - return NULL; - while (cnt-- > 0) - { - if (!(dst[cnt] = (char *) malloc (size))) - return NULL; - memcpy (dst[cnt], src[cnt], size); - } - return dst; -} +struct unionent +{ + char *name; + char **list; + short port_proto_addrtype; + short h_len; + union + { + char *s_proto; + char **h_addr_list; + }; +}; -static void -free_protoent_ptr (struct protoent *&p) +/* Generic "dup a {host,proto,serv}ent structure" function. + This is complicated because we need to be able to free the + structure at any point and we can't rely on the pointer contents + being untouched by callers. So, we allocate a chunk of memory + large enough to hold the structure and all of the stuff it points + to then we copy the source into this new block of memory. + The 'unionent' struct is a union of all of the currently used + *ent structure. */ + +#ifdef DEBUGGING +static void * +#else +static inline void * +#endif +dup_ent (void *src0, struct_type type) { - if (p) - { - debug_printf ("protoent: %s", p->p_name); + unionent *src = (unionent *) src0; - if (p->p_name) - free (p->p_name); - free_char_list (p->p_aliases); - free ((void *) p); - p = NULL; + /* Find the size of the raw structure minus any character strings, etc. */ + int sz, struct_sz; + switch (type) + { + case is_protoent: + struct_sz = sizeof (protoent); + break; + case is_servent: + struct_sz = sizeof (servent); + break; + case is_hostent: + struct_sz = sizeof (hostent); + break; + default: + api_fatal ("called with invalid value %d", type); + break; } -} -static struct protoent * -dup_protoent_ptr (struct protoent *src) -{ - if (!src) - return NULL; + /* Every *ent begins with a name. Calculate it's length. */ + int namelen = strlen_round (src->name); + sz = struct_sz + namelen; - struct protoent *dst = (struct protoent *) calloc (1, sizeof *dst); + char **av; + /* The next field in every *ent is an argv list of "something". + Calculate the number of components and how much space the + character strings will take. */ + int list_len = 0; + for (av = src->list; av && *av; av++) + { + list_len++; + sz += sizeof (char **) + strlen_round (*av); + } - if (!dst) - return NULL; + /* NULL terminate if there actually was a list */ + if (av) + { + sz += sizeof (char **); + list_len++; + } - debug_printf ("protoent: %s", src->p_name); + /* Do servent/hostent specific processing */ + int protolen = 0; + int addr_list_len = 0; + if (type == is_servent) + sz += (protolen = strlen_round (src->s_proto)); + else if (type == is_hostent) + { + /* Calculate the length and storage used for h_addr_list */ + for (av = src->h_addr_list; av && *av; av++) + { + addr_list_len++; + sz += sizeof (char **) + DWORD_round (src->h_len); + } + if (av) + { + sz += sizeof (char **); + addr_list_len++; + } + } - dst->p_proto = src->p_proto; - if (src->p_name && !(dst->p_name = strdup (src->p_name))) - goto out; - if (src->p_aliases && !(dst->p_aliases = dup_char_list (src->p_aliases))) - goto out; + /* Allocate the storage needed */ + unionent *dst = (unionent *) calloc (1, sz); - debug_printf ("protoent: copied %s", dst->p_name); + /* Hopefully, this worked. */ + if (dst) + { + /* This field is common to all *ent structures but named differently + in each, of course. */ + dst->port_proto_addrtype = src->port_proto_addrtype; + + /* Copy the name field to dst, using space just beyond the end of + the dst structure. */ + char *dp = ((char *) dst) + struct_sz; + strcpy (dst->name = dp, src->name); + dp += namelen; + + /* Copy the 'list' type to dst, using space beyond end of structure + + storage for name. */ + if (src->list) + { + char **dav = dst->list = (char **) dp; + dp += sizeof (char **) * list_len; + for (av = src->list; av && *av; av++) + { + int len = strlen (*av) + 1; + memcpy (*dav++ = dp, *av, len); + dp += DWORD_round (len); + } + } + /* Do servent/hostent specific processing. */ + if (type == is_servent) + { + if (src->s_proto) + { + char *s_proto; + /* Windows 95 idiocy. Structure is misaligned on Windows 95. + Kludge around this by trying a different pointer alignment. */ + if (IsBadReadPtr (src->s_proto, sizeof (src->s_proto)) + && !IsBadReadPtr (((pservent *) src)->s_proto, sizeof (src->s_proto))) + s_proto = ((pservent *) src)->s_proto; + else + s_proto = src->s_proto; + strcpy (dst->s_proto = dp, s_proto); + dp += protolen; + } + } + else if (type == is_hostent) + { + /* Transfer h_len and duplicate contents of h_addr_list, using + memory after 'list' allocation. */ + dst->h_len = src->h_len; + char **dav = dst->h_addr_list = (char **) dp; + dp += sizeof (char **) * addr_list_len; + for (av = src->h_addr_list; av && *av; av++) + { + memcpy (*dav++ = dp, *av, src->h_len); + dp += DWORD_round (src->h_len); + } + } + /* Sanity check that we did our bookkeeping correctly. */ + assert ((dp - (char *) dst) == sz); + } return dst; - -out: - free_protoent_ptr (dst); - return NULL; } +/* Generic macro to build a dup_{host,proto,serv}ent_ptr function. + The *ent buffers are allocated by dup_ent as contiguous storage. + Frees any previously exiting `old' storage, as well. */ +#define gen_ent(x, p) \ +static x * \ +dup_##x##_ptr (x *old, x *src) \ +{ \ + if (old) \ + { \ + debug_printf ("freeing %s", old->p##_name); \ + free (old); \ + } \ + debug_printf ("%s", src ? "<null!>" : src->p##_name); \ + x *dst = (x *) dup_ent (src, is_##x); \ + debug_printf ("copied %s", dst ? "<null!>" : dst->p##_name); \ + return dst; \ +} \ + +gen_ent (protoent, p) + #ifdef _MT_SAFE #define protoent_buf _reent_winsup ()->_protoent_buf #else @@ -484,8 +600,7 @@ cygwin_getprotobyname (const char *p) { if (check_null_str_errno (p)) return NULL; - free_protoent_ptr (protoent_buf); - protoent_buf = dup_protoent_ptr (getprotobyname (p)); + protoent_buf = dup_protoent_ptr (protoent_buf, getprotobyname (p)); if (!protoent_buf) set_winsock_errno (); @@ -497,8 +612,7 @@ cygwin_getprotobyname (const char *p) extern "C" struct protoent * cygwin_getprotobynumber (int number) { - free_protoent_ptr (protoent_buf); - protoent_buf = dup_protoent_ptr (getprotobynumber (number)); + protoent_buf = dup_protoent_ptr (protoent_buf, getprotobynumber (number)); if (!protoent_buf) set_winsock_errno (); @@ -828,70 +942,7 @@ cygwin_connect (int fd, const struct sockaddr *name, int namelen) return res; } -static void -free_servent_ptr (struct servent *&p) -{ - if (p) - { - debug_printf ("servent: %s", p->s_name); - - if (p->s_name) - free (p->s_name); - if (p->s_proto) - free (p->s_proto); - free_char_list (p->s_aliases); - free ((void *) p); - p = NULL; - } -} - -#pragma pack(push,2) -struct pservent -{ - char *s_name; - char **s_aliases; - short s_port; - char *s_proto; -}; - -#pragma pack(pop) -static struct servent * -dup_servent_ptr (struct servent *src) -{ - if (!src) - return NULL; - - struct servent *dst = (struct servent *) calloc (1, sizeof *dst); - - if (!dst) - return NULL; - - debug_printf ("servent: %s", src->s_name); - - dst->s_port = src->s_port; - if (src->s_name && !(dst->s_name = strdup (src->s_name))) - goto out; - if (src->s_aliases && !(dst->s_aliases = dup_char_list (src->s_aliases))) - goto out; - char *s_proto; - - if (IsBadReadPtr (src->s_proto, sizeof (src->s_proto)) - && !IsBadReadPtr (((pservent *) src)->s_proto, sizeof (src->s_proto))) - s_proto = ((pservent *) src)->s_proto; - else - s_proto = src->s_proto; - - if (s_proto && !(dst->s_proto = strdup (s_proto))) - goto out; - - debug_printf ("servent: copied %s", dst->s_name); - - return dst; - -out: - free_servent_ptr (dst); - return NULL; -} +gen_ent (servent, s) #ifdef _MT_SAFE #define servent_buf _reent_winsup ()->_servent_buf @@ -909,8 +960,7 @@ cygwin_getservbyname (const char *name, const char *proto) || (proto != NULL && check_null_str_errno (proto))) return NULL; - free_servent_ptr (servent_buf); - servent_buf = dup_servent_ptr (getservbyname (name, proto)); + servent_buf = dup_servent_ptr (servent_buf, getservbyname (name, proto)); if (!servent_buf) set_winsock_errno (); @@ -927,8 +977,7 @@ cygwin_getservbyport (int port, const char *proto) if (proto != NULL && check_null_str_errno (proto)) return NULL; - free_servent_ptr (servent_buf); - servent_buf = dup_servent_ptr (getservbyport (port, proto)); + servent_buf = dup_servent_ptr (servent_buf, getservbyport (port, proto)); if (!servent_buf) set_winsock_errno (); @@ -959,53 +1008,7 @@ cygwin_gethostname (char *name, size_t len) return 0; } -static void -free_hostent_ptr (struct hostent *&p) -{ - if (p) - { - debug_printf ("hostent: %s", p->h_name); - - if (p->h_name) - free ((void *) p->h_name); - free_char_list (p->h_aliases); - free_addr_list (p->h_addr_list); - free ((void *) p); - p = NULL; - } -} - -static struct hostent * -dup_hostent_ptr (struct hostent *src) -{ - if (!src) - return NULL; - - struct hostent *dst = (struct hostent *) calloc (1, sizeof *dst); - - if (!dst) - return NULL; - - debug_printf ("hostent: %s", src->h_name); - - dst->h_addrtype = src->h_addrtype; - dst->h_length = src->h_length; - if (src->h_name && !(dst->h_name = strdup (src->h_name))) - goto out; - if (src->h_aliases && !(dst->h_aliases = dup_char_list (src->h_aliases))) - goto out; - if (src->h_addr_list - && !(dst->h_addr_list = dup_addr_list (src->h_addr_list, src->h_length))) - goto out; - - debug_printf ("hostent: copied %s", dst->h_name); - - return dst; - -out: - free_hostent_ptr (dst); - return NULL; -} +gen_ent (hostent, h) #ifdef _MT_SAFE #define hostent_buf _reent_winsup ()->_hostent_buf @@ -1045,8 +1048,7 @@ cygwin_gethostbyname (const char *name) return &tmp; } - free_hostent_ptr (hostent_buf); - hostent_buf = dup_hostent_ptr (gethostbyname (name)); + hostent_buf = dup_hostent_ptr (hostent_buf, gethostbyname (name)); if (!hostent_buf) { set_winsock_errno (); @@ -1069,8 +1071,7 @@ cygwin_gethostbyaddr (const char *addr, int len, int type) if (__check_invalid_read_ptr_errno (addr, len)) return NULL; - free_hostent_ptr (hostent_buf); - hostent_buf = dup_hostent_ptr (gethostbyaddr (addr, len, type)); + hostent_buf = dup_hostent_ptr (hostent_buf, gethostbyaddr (addr, len, type)); if (!hostent_buf) { set_winsock_errno (); |