/* This file is part of GNU Pies Copyright (C) 2009, 2010, 2013, 2015 Sergey Poznyakoff GNU Pies is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNU Pies is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Pies. If not, see . */ #ifdef HAVE_CONFIG_H # include #endif #include "libpies.h" #include #include #include #include #include #include #include int str2port (char *str) { struct servent *serv; char *p; int port; /* First try to read it from /etc/services */ serv = getservbyname (str, "tcp"); if (serv != NULL) port = ntohs (serv->s_port); else { unsigned long l; /* Not in services, maybe a number? */ l = strtoul (str, &p, 0); if (*p || l < 0 || l > USHRT_MAX) return -1; port = l; } return port; } static size_t _my_stpcpy (char **pbuf, size_t *psize, const char *src) { size_t slen = strlen (src); if (pbuf == NULL || *pbuf == NULL) return slen; else { char *buf = *pbuf; size_t size = *psize; if (size > slen) size = slen; memcpy (buf, src, size); *psize -= size; *pbuf += size; if (*psize) **pbuf = 0; else (*pbuf)[-1] = 0; return size; } } #define S_UN_NAME(sa, salen) \ ((salen <= offsetof (struct sockaddr_un,sun_path)) ? "" : (sa)->sun_path) static size_t format_uint (char **bufptr, size_t *buflen, unsigned n) { char *buf = *bufptr; size_t len = *buflen; size_t i; if (buf && len == 0) return 0; for (i = 0;;) { unsigned x = n % 10; if (buf) { if (len == 1) break; *buf++ = x + '0'; --len; } n /= 10; ++i; if (n == 0) break; } if (buf) { char *p = *bufptr; *bufptr = buf; *buf = 0; while (--buf > p) { char c = *p; *p++ = *buf; *buf = c; } } return i; } void sockaddr_to_str (const struct sockaddr *sa, int salen, char *bufptr, size_t buflen, size_t *plen) { size_t len = 0; switch (sa->sa_family) { case AF_INET: { struct sockaddr_in s_in = *(struct sockaddr_in *)sa; len += _my_stpcpy (&bufptr, &buflen, inet_ntoa (s_in.sin_addr)); len += _my_stpcpy (&bufptr, &buflen, ":"); len += format_uint (&bufptr, &buflen, ntohs (s_in.sin_port)); break; } case AF_UNIX: { struct sockaddr_un *s_un = (struct sockaddr_un *)sa; if (S_UN_NAME (s_un, salen)[0] == 0) len += _my_stpcpy (&bufptr, &buflen, "somebody"); else { len += _my_stpcpy (&bufptr, &buflen, "socket "); len += _my_stpcpy (&bufptr, &buflen, s_un->sun_path); } break; } default: len += _my_stpcpy (&bufptr, &buflen, "{Unsupported family: "); len += format_uint (&bufptr, &buflen, sa->sa_family); len += _my_stpcpy (&bufptr, &buflen, "}"); } if (plen) *plen = len + 1; } char * sockaddr_to_astr (const struct sockaddr *sa, int salen) { size_t size; char *p; sockaddr_to_str (sa, salen, NULL, 0, &size); p = malloc (size); if (!p) grecs_alloc_die (); sockaddr_to_str (sa, salen, p, size, NULL); return p; }