sock.c - quark - quark web server
 (HTM) git clone git://git.suckless.org/quark
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) LICENSE
       ---
       sock.c (4386B)
       ---
            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)) == 0;
          202         case AF_INET:
          203                 return ((struct sockaddr_in *)sa1)->sin_addr.s_addr ==
          204                        ((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 }