diff --git a/README.md b/README.md index c4d4398..75664cc 100644 --- a/README.md +++ b/README.md @@ -3,5 +3,3 @@ A small gopher server for POSIX systems, written in C99. To build: `make` - -At the moment it only serves on `::1` at port 7070. diff --git a/main.c b/main.c index 6835e5a..6ada7e5 100644 --- a/main.c +++ b/main.c @@ -18,12 +18,14 @@ #define _POSIX_SOURCE +#include #include #include #include #include #include #include +#include #include #include #include @@ -36,8 +38,8 @@ int pledge(const char *, const char *); int unveil(const char *, const char *); #endif -#define HOST "::1" -#define PORT 7070 +#define DEFAULT_ADDRSTR "::1" +#define DEFAULT_PORT 70 #define RESP_TERM ".\r\n" #define RESP_TERM_LEN 3 /* strlen(".\r\n") */ @@ -83,6 +85,12 @@ static int append_selector_part(const char *part, size_t partlen, char *buf, return partlen + 1; } +static void usage(const char *name) +{ + fprintf(stderr, "Usage: %s [-a ipv6addr] [-p portnum] srvroot\n", name); + exit(EXIT_FAILURE); +} + int main(int argc, char *argv[]) { (void)argc; @@ -100,24 +108,68 @@ int main(int argc, char *argv[]) #endif /* - * Get srvroot path from arguments and copy into pbuf. + * Extract arguments. + */ + const char *srvroot = NULL, *addrstr = NULL, *portstr = NULL; + if (argc < 2) + usage(argv[0]); + for (int i = 1; i < argc; ++i) { + if (argv[i][0] == '-') { + if (i + 1 >= argc || strlen(argv[i]) != 2) + usage(argv[0]); + switch (argv[i][1]) { + case 'a': + addrstr = argv[++i]; + break; + case 'p': + portstr = argv[++i]; + break; + default: + usage(argv[0]); + break; + } + } else { + srvroot = argv[i]; + } + } + if (!srvroot) + usage(argv[0]); + if (!addrstr) + addrstr = DEFAULT_ADDRSTR; + + /* + * Parse address and port. + */ + struct in6_addr addr; + if (inet_pton(AF_INET6, addrstr, &addr) != 1) + usage(argv[0]); + if (portstr[0] == '-') + usage(argv[0]); + uint16_t port; + { + char *end; + unsigned long res = strtoul(portstr, &end, 10); + if (*end != '\0' || res > UINT16_MAX) + usage(argv[0]); + else + port = res; + } + + /* + * Copy srvroot into pbuf. * * The srvroot being at the start of pbuf should be maintained * through the whole application. Any trailing '/' is removed if * present. */ - if (argc < 2) { - fprintf(stderr, "Usage: %s srvroot\n", argv[0]); - return EXIT_FAILURE; - } - size_t srvroot_len = strlen(argv[1]); - if (argv[1][srvroot_len - 1] == '/') + size_t srvroot_len = strlen(srvroot); + if (srvroot[srvroot_len - 1] == '/') --srvroot_len; if (srvroot_len > PBUF_SIZE) { fprintf(stderr, "srvroot path is too long\n"); return EXIT_FAILURE; } - memcpy(pbuf, argv[1], srvroot_len); + memcpy(pbuf, srvroot, srvroot_len); #ifdef __OpenBSD__ /* @@ -169,8 +221,8 @@ int main(int argc, char *argv[]) } const struct sockaddr_in6 haddr = { .sin6_family = AF_INET6, - .sin6_port = htons(PORT), - .sin6_addr = in6addr_loopback, + .sin6_port = htons(port), + .sin6_addr = addr, }; if (bind(sfd, (const struct sockaddr *)&haddr, sizeof(haddr)) == -1) { fprintf(stderr, "Error binding socket to address\n"); @@ -407,7 +459,7 @@ int main(int argc, char *argv[]) */ n = snprintf(&rbuf[rlen], RBUF_SIZE - rlen, "%1u%s\t%s\t%s\t%u\r\n", type, ent->d_name, - &pbuf[srvroot_len], HOST, PORT); + &pbuf[srvroot_len], addrstr, port); if (n >= RBUF_SIZE - rlen) { fprintf(stderr, "Response buffer was too small\n"); goto send_response;