/* ** Example code for the autoconf macro: AC_raf_FUNC_WHICH_GETSERVBYNAME_R ** ** The net_getservbyname() function presented below is extracted from ** libslack (version 0.5 and above) which is not yet available from ** http://libslack.org/ ** ** To compile this code without autoconf, fiddle with the macros below and: ** ** gcc -o net_getservbyname net_getservbyname.c ** ** 20010803 raf */ #include #include #include #include #define TEST #define HAVE_FUNC_GETSERVBYNAME_R_6 1 #undef HAVE_FUNC_GETSERVBYNAME_R_5 #undef HAVE_FUNC_GETSERVBYNAME_R_4 #define xor(a, b) (!(a) ^ !(b)) #define set_errnull(errnum) ((void *)((void *)(errno = (errnum)), NULL)) #define mem_resize(mem, size) mem_resize_fn((void **)(mem), (size) * sizeof(*(mem))) #ifndef HAVE_ISOC_REALLOC static void *isoc_realloc(void *ptr, size_t size) { void *p; if (size) { if (!(p = (ptr) ? realloc(ptr, size) : malloc(size))) errno = ENOMEM; /* Not required by ISO C */ } else { free(ptr); p = NULL; } return p; } #else #define isoc_realloc realloc #endif void *mem_resize_fn(void **mem, size_t size) { void *ptr; if (!mem) return set_errnull(EINVAL); ptr = isoc_realloc(*mem, size); if (size && !ptr) return NULL; return *mem = ptr; } /* =item C A portable, reentrant I that handles it's own memory allocation requirements. Looks up the service C and C. On success, returns C with any extra data in C<*buf>. I<*len> is the length of I<*buf> on entry and is updated to reflect the length on exit if a larger buffer was required to perform the lookup. On error, returns C with C set appropriately. It is the caller's responsibility to deallocate C<*buf> using I when the lookup failed or when the results of the name lookup are no longer required. Note: If your system has any version of I, it will be used. Otherwise, I will be used. Even this might be threadsafe if your system uses thread specific data to make it so. struct servent servbuf[1], *servent; void *buf = NULL; size_t len = 0; if ((servent = net_getservbyname("service", "proto", servbuf, &buf, &len))) { // use servent ... } free(buf); =cut */ struct servent *net_getservbyname(const char *name, const char *proto, struct servent *servbuf, void **buf, size_t *len) { if (!name || !servbuf || !buf || !len || xor(*buf, *len)) return set_errnull(EINVAL); #if HAVE_FUNC_GETSERVBYNAME_R_6 { struct servent *ret; int err; if (*len == 0 && !(*buf = malloc(*len = 128))) return NULL; while ((err = getservbyname_r(name, proto, servbuf, *buf, *len, &ret)) && errno == ERANGE) if (!mem_resize(buf, *len <<= 1)) return NULL; return (err) ? NULL : ret; } #elif HAVE_FUNC_GETSERVBYNAME_R_5 { struct servent *ret; if (*len == 0 && !(*buf = malloc(*len = 128))) return NULL while (!(ret = getservbyname_r(name, proto, servbuf, *buf, *len)) && errno == ERANGE) if (!mem_resize(buf, *len <<= 1)) return NULL; return ret; } #elif HAVE_FUNC_GETSERVBYNAME_R_4 { if (*len == 0) { if (!(*buf = calloc(1, *len = sizeof(struct servent_data)))) return NULL; } else if (*len < sizeof(struct servent_data)) { size_t oldlen = *len; if (!mem_resize(*buf, *len = sizeof(struct servent_data))) return NULL; memset(*buf + olden, 0, *len - oldlen); } if (getservbyname_r(name, proto, servbuf, (struct servent_data *)*buf) == -1) return NULL; return servbuf; } #else /* ** Some systems use thread specific data. Even if this isn't one of ** them, we have to return something, even if it isn't threadsafe. ** If we're here and it's not threadsafe, this system probably doesn't ** support threads anyway. Of course, that's no consolation if some ** function further up the stack is in the middle of a getservent() ** loop. */ return getservbyname(name, proto); #endif } #ifdef TEST int main(int ac, char **av) { int a; if (ac == 1) { fprintf(stderr, "usage: %s service...\n", *av); exit(EXIT_FAILURE); } for (a = 1; a < ac; ++a) { struct servent servbuf[1], *servent; void *buf = NULL; size_t len = 0; if ((servent = net_getservbyname(av[a], NULL, servbuf, &buf, &len))) { char **alias; printf("official name = %s\n", servent->s_name); for (alias = servent->s_aliases; *alias; ++alias) printf("alias[%d] = %s\n", alias - servent->s_aliases, *alias); printf("port = %d\n", ntohs(servent->s_port)); printf("protocol = %s\n", servent->s_proto); printf("\n"); } else fprintf(stderr, "net_getservbyname(%s) failed (%s)\n", av[a], strerror(errno)); free(buf); } return EXIT_SUCCESS; } #endif /* vi:set ts=4 sw=4: */