/* This file is part of GNU Pies
Copyright (C) 2009-2010, 2013, 2015, 2017 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
#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;
}