quark

quark web server
git clone git://git.suckless.org/quark
Log | Files | Refs | LICENSE

sock.c (4395B)


      1 /* See LICENSE file for copyright and license details. */
      2 #include <arpa/inet.h>
      3 #include <errno.h>
      4 #include <fcntl.h>
      5 #include <netdb.h>
      6 #include <netinet/in.h>
      7 #include <stddef.h>
      8 #include <stdio.h>
      9 #include <string.h>
     10 #include <sys/types.h>
     11 #include <sys/socket.h>
     12 #include <sys/stat.h>
     13 #include <sys/time.h>
     14 #include <sys/un.h>
     15 #include <unistd.h>
     16 
     17 #include "sock.h"
     18 #include "util.h"
     19 
     20 int
     21 sock_get_ips(const char *host, const char* port)
     22 {
     23 	struct addrinfo hints = {
     24 		.ai_flags    = AI_NUMERICSERV,
     25 		.ai_family   = AF_UNSPEC,
     26 		.ai_socktype = SOCK_STREAM,
     27 	};
     28 	struct addrinfo *ai, *p;
     29 	int ret, insock = 0;
     30 
     31 	if ((ret = getaddrinfo(host, port, &hints, &ai))) {
     32 		die("getaddrinfo: %s", gai_strerror(ret));
     33 	}
     34 
     35 	for (p = ai; p; p = p->ai_next) {
     36 		if ((insock = socket(p->ai_family, p->ai_socktype,
     37 		                     p->ai_protocol)) < 0) {
     38 			continue;
     39 		}
     40 		if (setsockopt(insock, SOL_SOCKET, SO_REUSEADDR,
     41 		               &(int){1}, sizeof(int)) < 0) {
     42 			die("setsockopt:");
     43 		}
     44 		if (bind(insock, p->ai_addr, p->ai_addrlen) < 0) {
     45 			/* bind failed, close the insock and retry */
     46 			if (close(insock) < 0) {
     47 				die("close:");
     48 			}
     49 			continue;
     50 		}
     51 		break;
     52 	}
     53 	freeaddrinfo(ai);
     54 	if (!p) {
     55 		/* we exhaustet the addrinfo-list and found no connection */
     56 		if (errno == EACCES) {
     57 			die("You need to run as root or have "
     58 			    "CAP_NET_BIND_SERVICE set to bind to "
     59 			    "privileged ports");
     60 		} else {
     61 			die("bind:");
     62 		}
     63 	}
     64 
     65 	if (listen(insock, SOMAXCONN) < 0) {
     66 		die("listen:");
     67 	}
     68 
     69 	return insock;
     70 }
     71 
     72 int
     73 sock_get_uds(const char *udsname, uid_t uid, gid_t gid)
     74 {
     75 	struct sockaddr_un addr = {
     76 		.sun_family = AF_UNIX,
     77 	};
     78 	size_t udsnamelen;
     79 	int insock, sockmode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP |
     80 	                       S_IROTH | S_IWOTH;
     81 
     82 	if ((insock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
     83 		die("socket:");
     84 	}
     85 
     86 	if ((udsnamelen = strlen(udsname)) > sizeof(addr.sun_path) - 1) {
     87 		die("UNIX-domain socket name truncated");
     88 	}
     89 	memcpy(addr.sun_path, udsname, udsnamelen + 1);
     90 
     91 	if (bind(insock, (const struct sockaddr *)&addr, sizeof(addr)) < 0) {
     92 		die("bind '%s':", udsname);
     93 	}
     94 
     95 	if (listen(insock, SOMAXCONN) < 0) {
     96 		sock_rem_uds(udsname);
     97 		die("listen:");
     98 	}
     99 
    100 	if (chmod(udsname, sockmode) < 0) {
    101 		sock_rem_uds(udsname);
    102 		die("chmod '%s':", udsname);
    103 	}
    104 
    105 	if (chown(udsname, uid, gid) < 0) {
    106 		sock_rem_uds(udsname);
    107 		die("chown '%s':", udsname);
    108 	}
    109 
    110 	return insock;
    111 }
    112 
    113 void
    114 sock_rem_uds(const char *udsname)
    115 {
    116 	if (unlink(udsname) < 0) {
    117 		die("unlink '%s':", udsname);
    118 	}
    119 }
    120 
    121 int
    122 sock_set_timeout(int fd, int sec)
    123 {
    124 	struct timeval tv;
    125 
    126 	tv.tv_sec = sec;
    127 	tv.tv_usec = 0;
    128 
    129 	if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0 ||
    130 	    setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)) < 0) {
    131 		warn("setsockopt:");
    132 		return 1;
    133 	}
    134 
    135 	return 0;
    136 }
    137 
    138 int
    139 sock_set_nonblocking(int fd)
    140 {
    141 	int flags;
    142 
    143 	if ((flags = fcntl(fd, F_GETFL, 0)) < 0) {
    144 		warn("fcntl:");
    145 		return 1;
    146 	}
    147 
    148 	flags |= O_NONBLOCK;
    149 
    150 	if (fcntl(fd, F_SETFL, flags) < 0) {
    151 		warn("fcntl:");
    152 		return 1;
    153 	}
    154 
    155 	return 0;
    156 }
    157 
    158 int
    159 sock_get_inaddr_str(const struct sockaddr_storage *in_sa, char *str,
    160                     size_t len)
    161 {
    162 	switch (in_sa->ss_family) {
    163 	case AF_INET:
    164 		if (!inet_ntop(AF_INET,
    165 		               &(((struct sockaddr_in *)in_sa)->sin_addr),
    166 		               str, len)) {
    167 			warn("inet_ntop:");
    168 			return 1;
    169 		}
    170 		break;
    171 	case AF_INET6:
    172 		if (!inet_ntop(AF_INET6,
    173 		               &(((struct sockaddr_in6 *)in_sa)->sin6_addr),
    174 		               str, len)) {
    175 			warn("inet_ntop:");
    176 			return 1;
    177 		}
    178 		break;
    179 	case AF_UNIX:
    180 		snprintf(str, len, "uds");
    181 		break;
    182 	default:
    183 		snprintf(str, len, "-");
    184 	}
    185 
    186 	return 0;
    187 }
    188 
    189 int
    190 sock_same_addr(const struct sockaddr_storage *sa1, const struct sockaddr_storage *sa2)
    191 {
    192 	/* return early if address-families don't match */
    193 	if (sa1->ss_family != sa2->ss_family) {
    194 		return 0;
    195 	}
    196 
    197 	switch (sa1->ss_family) {
    198 	case AF_INET6:
    199 		return memcmp(((struct sockaddr_in6 *)sa1)->sin6_addr.s6_addr,
    200 		              ((struct sockaddr_in6 *)sa2)->sin6_addr.s6_addr,
    201 		              sizeof(((struct sockaddr_in6 *)sa1)->sin6_addr.s6_addr));
    202 	case AF_INET:
    203 		return ntohl(((struct sockaddr_in *)sa1)->sin_addr.s_addr) ==
    204 		       ntohl(((struct sockaddr_in *)sa2)->sin_addr.s_addr);
    205 	default: /* AF_UNIX */
    206 		return strcmp(((struct sockaddr_un *)sa1)->sun_path,
    207 		              ((struct sockaddr_un *)sa2)->sun_path) == 0;
    208 	}
    209 }