suckless-quark/sock.c
Laslo Hunhold ccdb51b96d Refactor the single source file into multiple modules
And many other things, too many to list here. For example, it now
properly logs uds instead of erroring out.
Separating concerns in many places definitely improves the readability.
2018-02-04 21:27:33 +01:00

152 lines
2.9 KiB
C

/* See LICENSE file for copyright and license details. */
#include <arpa/inet.h>
#include <netdb.h>
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/un.h>
#include <unistd.h>
#include "sock.h"
#include "util.h"
int
sock_get_ips(const char *host, const char* port)
{
struct addrinfo hints, *ai, *p;
int ret, insock = 0, yes;
memset(&hints, 0, sizeof(hints));
hints.ai_flags = AI_NUMERICSERV;
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
if ((ret = getaddrinfo(host, port, &hints, &ai))) {
die("getaddrinfo: %s", gai_strerror(ret));
}
for (yes = 1, p = ai; p; p = p->ai_next) {
if ((insock = socket(p->ai_family, p->ai_socktype,
p->ai_protocol)) < 0) {
continue;
}
if (setsockopt(insock, SOL_SOCKET, SO_REUSEADDR, &yes,
sizeof(int)) < 0) {
die("setsockopt:");
}
if (bind(insock, p->ai_addr, p->ai_addrlen) < 0) {
if (close(insock) < 0) {
die("close:");
}
continue;
}
break;
}
freeaddrinfo(ai);
if (!p) {
die("bind:");
}
if (listen(insock, SOMAXCONN) < 0) {
die("listen:");
}
return insock;
}
void
sock_rem_uds(const char *udsname)
{
if (unlink(udsname) < 0) {
die("unlink:");
}
}
int
sock_get_uds(const char *udsname, uid_t uid, gid_t gid)
{
struct sockaddr_un addr;
size_t udsnamelen;
int insock, sockmode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH;
if ((insock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
die("socket:");
}
memset(&addr, 0, sizeof(addr));
addr.sun_family = AF_UNIX;
if ((udsnamelen = strlen(udsname)) > sizeof(addr.sun_path) - 1) {
die("UNIX-domain socket name truncated");
}
memcpy(addr.sun_path, udsname, udsnamelen + 1);
if (bind(insock, (const struct sockaddr *)&addr, sizeof(addr)) < 0) {
die("bind %s:", udsname);
}
if (listen(insock, SOMAXCONN) < 0) {
sock_rem_uds(udsname);
die("listen:");
}
if (chmod(udsname, sockmode) < 0) {
sock_rem_uds(udsname);
die("chmod:");
}
if (chown(udsname, uid, gid) < 0) {
sock_rem_uds(udsname);
die("chown:");
}
return insock;
}
int
sock_set_timeout(int fd, int sec)
{
struct timeval tv;
tv.tv_sec = sec;
tv.tv_usec = 0;
if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0 ||
setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)) < 0) {
warn("setsockopt:");
return 1;
}
return 0;
}
int
sock_get_inaddr_str(struct sockaddr_storage *in_sa, char *str, size_t len)
{
switch (in_sa->ss_family) {
case AF_INET:
if (!inet_ntop(AF_INET,
&(((struct sockaddr_in *)in_sa)->sin_addr),
str, len)) {
warn("inet_ntop:");
return 1;
}
break;
case AF_INET6:
if (!inet_ntop(AF_INET6,
&(((struct sockaddr_in6 *)in_sa)->sin6_addr),
str, len)) {
warn("inet_ntop:");
return 1;
}
break;
default:
snprintf(str, len, "uds");
}
return 0;
}