Mercurial > libjeffpc
view sock.c @ 806:12a3139a2baf
sock: use atomic_cas_ptr correctly
This bug was caused by incorrect documentation (already fixed). It resulted
in us freeing the name on successful CAS and caching the freed pointer.
Signed-off-by: Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
author | Josef 'Jeff' Sipek <jeffpc@josefsipek.net> |
---|---|
date | Fri, 10 Apr 2020 12:27:10 -0400 |
parents | 32d261e8b47f |
children | de55ae9a8839 |
line wrap: on
line source
/* * Copyright (c) 2016-2020 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include <sys/socket.h> #include <netdb.h> #include <unistd.h> #include <jeffpc/sock.h> #include <jeffpc/atomic.h> #include <jeffpc/config.h> const char *xgethostname(void) { static const char *cached; char *name; ssize_t len; int ret; if (cached) return cached; #if defined(HOST_NAME_MAX) len = HOST_NAME_MAX; #elif defined(MAXHOSTNAMELEN) len = MAXHOSTNAMELEN; #else len = sysconf(_SC_HOST_NAME_MAX); if (len < 0) goto unknown; #endif len++; /* space for the trailing nul */ name = malloc(len); if (!name) goto unknown; ret = gethostname(name, len); if (ret) { free(name); goto unknown; } if (atomic_cas_ptr(&cached, NULL, name) != NULL) free(name); return cached; unknown: return "<unknown>"; } int connect_ip(const char *host, uint16_t port, bool v4, bool v6, enum ip_type type) { struct addrinfo hints, *res, *p; char strport[6]; int sock; if (!host || !port || (!v4 && !v6) || (type != IP_TCP)) return -EINVAL; memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_PASSIVE; snprintf(strport, sizeof(strport), "%hu", port); switch (getaddrinfo(host, strport, &hints, &res)) { case 0: /* success */ break; #ifdef JEFFPC_HAVE_EAI_ADDRFAMILY case EAI_ADDRFAMILY: #endif case EAI_FAMILY: case EAI_SERVICE: case EAI_SOCKTYPE: return -ENOTSUP; case EAI_AGAIN: return -EAGAIN; case EAI_BADFLAGS: return -EINVAL; case EAI_MEMORY: return -ENOMEM; #ifdef JEFFPC_HAVE_EAI_NODATA case EAI_NODATA: #endif case EAI_NONAME: return -ENOENT; case EAI_OVERFLOW: return -EOVERFLOW; case EAI_SYSTEM: return -errno; default: /* TODO: is this the best errno we can return? */ return -ENOENT; } sock = -ENOENT; for (p = res; p; p = p->ai_next) { switch (p->ai_family) { case AF_INET: if (!v4) continue; break; case AF_INET6: if (!v6) continue; break; default: continue; } sock = socket(p->ai_family, p->ai_socktype, p->ai_protocol); if (sock == -1) { sock = -errno; continue; } if (connect(sock, p->ai_addr, p->ai_addrlen) == -1) { close(sock); sock = -errno; continue; } /* success! */ break; } freeaddrinfo(res); return sock; }