summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile4
-rw-r--r--gopher.c113
-rw-r--r--gopher_client/client.c89
-rw-r--r--gph.c288
-rw-r--r--index.gph4
-rw-r--r--log.c2
-rw-r--r--main.c33
7 files changed, 492 insertions, 41 deletions
diff --git a/Makefile b/Makefile
index 9debc82..2a54323 100644
--- a/Makefile
+++ b/Makefile
@@ -1,11 +1,11 @@
.POSIX:
CC=cc
-CFLAGS=-ansi -Wall -Wextra -pedantic
+CFLAGS=-ansi -D_POSIX_C_SOURCE=200809L -Wall -Wextra -pedantic
all: gopherd
-SRC=main.c log.c gopher.c
+SRC=main.c log.c gopher.c gph.c
OBJ=$(SRC:.c=.o)
gopherd: $(OBJ)
diff --git a/gopher.c b/gopher.c
index c1cb2eb..32f1513 100644
--- a/gopher.c
+++ b/gopher.c
@@ -1,23 +1,18 @@
-#define _POSIX_C_SOURCE 200112L
-
#include <sys/socket.h>
+#include <sys/types.h>
+#include <dirent.h>
#include <stdio.h>
#include <string.h>
+#include <stdlib.h>
#include "log.h"
-static char *res = "1Entry 1 /entry1 localhost 3000\r\n\
-1Entry 2 /entry2 localhost 3000\r\n\
-1Entry 3 /entry3 localhost 3000\r\n\
-.";
-
-static char *res1 = "0SubEntry 1 /entry1 localhost 3000\r\n\
-0SubEntry 2 /entry2 localhost 3000\r\n\
-0SubEntry 3 /entry3 localhost 3000\r\n\
-.";
+#define GOPHERROOT "/tmp/gopherroot"
+#define GOPHERHOST "localhost"
+#define GOPHERPORT "70"
-static int
+static int
sendall(int fd, const char *buf, size_t len)
{
size_t sent = 0;
@@ -35,22 +30,100 @@ sendall(int fd, const char *buf, size_t len)
return 0;
}
-int
+static int
+print_indexfile(int fd, const char *path)
+{
+ FILE *f;
+ char buf[512];
+
+ f = fopen(path, "r");
+ if (f == NULL) {
+ perror("fopen");
+ return -1;
+ }
+ while (!feof(f)) {
+ if (fgets(buf, sizeof(buf), f) == NULL)
+ continue;
+ if (sendall(fd, buf, strlen(buf)) == -1) {
+ logmsg(LOG_INFO, "failed to send data");
+ return -1;
+ fclose(f);
+ }
+ }
+
+ fclose(f);
+ return 0;
+}
+
+static int
+print_dir(int fd, const char *path)
+{
+ DIR *root;
+ struct dirent *node;
+ char *buf;
+ int type;
+ size_t buflen;
+
+ root = opendir(path);
+ if (root == NULL) {
+ perror("opendir");
+ return -1;
+ }
+ while ((node = readdir(root)) != NULL) {
+ buflen = sizeof(type) + strlen(node->d_name) +
+ strlen(GOPHERROOT) + strlen(GOPHERHOST) +
+ strlen(GOPHERPORT) + 6;
+ if ((buf = malloc(buflen)) == NULL) {
+ perror("malloc");
+ return -1;
+ }
+
+ switch (node->d_type) {
+ case 4:
+ type = 1;
+ break;
+ case 8:
+ type = 0;
+ break;
+ }
+
+ sprintf(buf, "%d%s %s %s %s\r\n",
+ type, node->d_name, GOPHERROOT, "localhost", "3000");
+ if (sendall(fd, buf, buflen) == -1) {
+ logmsg(LOG_INFO, "failed to send data");
+ free(buf);
+ return -1;
+ }
+ free(buf);
+ }
+
+ closedir(root);
+
+ return 0;
+}
+
+int
handle_path(int fd, const char *path)
{
const char *data;
if (strcmp(path, "") == 0 || strcmp(path, "/") == 0) {
- data = res;
- } else if (strcmp(path, "/entry1") == 0) {
- data = res1;
+ if (print_indexfile(fd, "index.gph") == -1) {
+ logmsg(LOG_INFO, "failed to send data");
+ return -1;
+ }
+ } else if (strcmp(path, "/list") == 0) {
+ if (print_dir(fd, GOPHERROOT) == -1) {
+ logmsg(LOG_INFO, "failed to send data");
+ return -1;
+ }
} else {
data = "";
+ if (sendall(fd, data, strlen(data)) == -1) {
+ logmsg(LOG_INFO, "failed to send data");
+ return -1;
+ }
}
- if (sendall(fd, data, strlen(data)) == -1) {
- logmsg(LOG_INFO, "failed to send data");
- return -1;
- }
return 0;
}
diff --git a/gopher_client/client.c b/gopher_client/client.c
new file mode 100644
index 0000000..5f6c23c
--- /dev/null
+++ b/gopher_client/client.c
@@ -0,0 +1,89 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <netdb.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+
+#include <arpa/inet.h>
+
+#define PORT "3000" // the port client will be connecting to
+
+#define MAXDATASIZE 100 // max number of bytes we can get at once
+
+// get sockaddr, IPv4 or IPv6:
+void *get_in_addr(struct sockaddr *sa)
+{
+ if (sa->sa_family == AF_INET) {
+ return &(((struct sockaddr_in*)sa)->sin_addr);
+ }
+
+ return &(((struct sockaddr_in6*)sa)->sin6_addr);
+}
+
+int main(int argc, char *argv[])
+{
+ int sockfd, numbytes;
+ char buf[MAXDATASIZE];
+ struct addrinfo hints, *servinfo, *p;
+ int rv;
+ char s[INET6_ADDRSTRLEN];
+
+ if (argc != 2) {
+ fprintf(stderr,"usage: client hostname\n");
+ exit(1);
+ }
+
+ memset(&hints, 0, sizeof hints);
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+
+ if ((rv = getaddrinfo(argv[1], PORT, &hints, &servinfo)) != 0) {
+ fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
+ return 1;
+ }
+
+ // loop through all the results and connect to the first we can
+ for(p = servinfo; p != NULL; p = p->ai_next) {
+ if ((sockfd = socket(p->ai_family, p->ai_socktype,
+ p->ai_protocol)) == -1) {
+ perror("client: socket");
+ continue;
+ }
+
+ if (connect(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
+ close(sockfd);
+ perror("client: connect");
+ continue;
+ }
+
+ break;
+ }
+
+ if (p == NULL) {
+ fprintf(stderr, "client: failed to connect\n");
+ return 2;
+ }
+
+ inet_ntop(p->ai_family, get_in_addr((struct sockaddr *)p->ai_addr),
+ s, sizeof s);
+ printf("client: connecting to %s\n", s);
+
+ freeaddrinfo(servinfo); // all done with this structure
+
+ if ((numbytes = recv(sockfd, buf, MAXDATASIZE-1, 0)) == -1) {
+ perror("recv");
+ exit(1);
+ }
+
+ buf[numbytes] = '\0';
+
+ printf("client: received '%s'\n",buf);
+
+ close(sockfd);
+
+ return 0;
+}
diff --git a/gph.c b/gph.c
new file mode 100644
index 0000000..6d29be0
--- /dev/null
+++ b/gph.c
@@ -0,0 +1,288 @@
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+typedef struct Elems Elems;
+struct Elems {
+ char **e;
+ int num;
+};
+
+typedef struct Indexs Indexs;
+struct Indexs {
+ Elems **n;
+ int num;
+};
+
+
+void *
+xcalloc(size_t nmemb, size_t size)
+{
+ void *p;
+
+ if (!(p = calloc(nmemb, size))) {
+ perror("calloc");
+ exit(1);
+ }
+
+ return p;
+}
+
+void *
+xmalloc(size_t size)
+{
+ void *p;
+
+ if (!(p = malloc(size))) {
+ perror("malloc");
+ exit(1);
+ }
+
+ return p;
+}
+
+void *
+xrealloc(void *ptr, size_t size)
+{
+ if (!(ptr = realloc(ptr, size))) {
+ perror("realloc");
+ exit(1);
+ }
+
+ return ptr;
+}
+
+char *
+xstrdup(const char *str)
+{
+ char *ret;
+
+ if (!(ret = strdup(str))) {
+ perror("strdup");
+ exit(1);
+ }
+
+ return ret;
+}
+
+void
+freeelem(Elems *e)
+{
+ if (e != NULL) {
+ if (e->e != NULL) {
+ for (;e->num > 0; e->num--)
+ if (e->e[e->num - 1] != NULL)
+ free(e->e[e->num - 1]);
+ free(e->e);
+ }
+ free(e);
+ }
+ return;
+}
+
+void
+freeindex(Indexs *i)
+{
+ if (i != NULL) {
+ if (i->n != NULL) {
+ for (;i->num > 0; i->num--)
+ freeelem(i->n[i->num - 1]);
+ free(i->n);
+ }
+ free(i);
+ }
+
+ return;
+}
+
+void
+addelem(Elems *e, char *s)
+{
+ e->num++;
+ e->e = xrealloc(e->e, sizeof(char *) * e->num);
+ e->e[e->num - 1] = xstrdup(s);
+
+ return;
+}
+
+Elems *
+getadv(char *str)
+{
+ char *b, *e, *o, *bo;
+ Elems *ret;
+
+ ret = xcalloc(1, sizeof(Elems));
+
+ if (strchr(str, '\t')) {
+ addelem(ret, "i");
+ addelem(ret, "Happy helping ☃ here: You tried to "
+ "output a spurious tab character. This will "
+ "break gopher. Please review your scripts. "
+ "Have a nice day!");
+ addelem(ret, "Err");
+ addelem(ret, "server");
+ addelem(ret, "port");
+
+ return ret;
+ }
+
+ if (str[0] == '[') {
+ o = xstrdup(str);
+ b = o + 1;
+ bo = b;
+ while ((e = strchr(bo, '|')) != NULL) {
+ if (e != bo && e[-1] == '\\') {
+ memmove(&e[-1], e, strlen(e));
+ bo = e;
+ continue;
+ }
+ *e = '\0';
+ e++;
+ addelem(ret, b);
+ b = e;
+ bo = b;
+ }
+
+ e = strchr(b, ']');
+ if (e != NULL) {
+ *e = '\0';
+ addelem(ret, b);
+ }
+ free(o);
+
+ if (ret->e != NULL && ret->e[0] != NULL && ret->e[0][0] == '\0') {
+ freeelem(ret);
+ ret = xcalloc(1, sizeof(Elems));
+
+ addelem(ret, "i");
+ addelem(ret, "Happy helping ☃ here: You did not "
+ "specify an item type on this line. Please "
+ "review your scripts. "
+ "Have a nice day!");
+ addelem(ret, "Err");
+ addelem(ret, "server");
+ addelem(ret, "port");
+
+ return ret;
+ }
+
+ if (ret->e != NULL && ret->num == 5)
+ return ret;
+
+ /* Invalid entry: Give back the whole line. */
+ freeelem(ret);
+ ret = xcalloc(1, sizeof(Elems));
+ }
+
+ b = str;
+ if (*str == 't')
+ b++;
+ addelem(ret, "i");
+ addelem(ret, b);
+ addelem(ret, "Err");
+ addelem(ret, "server");
+ addelem(ret, "port");
+
+ return ret;
+}
+
+void
+addindexs(Indexs *idx, Elems *el)
+{
+ idx->num++;
+ idx->n = xrealloc(idx->n, sizeof(Elems) * idx->num);
+ idx->n[idx->num - 1] = el;
+
+ return;
+}
+
+Indexs *
+scanfile(char *fname)
+{
+ char *ln = NULL;
+ size_t linesiz = 0;
+ ssize_t n;
+ FILE *fp;
+ Indexs *ret;
+ Elems *el;
+
+ if (!(fp = fopen(fname, "r")))
+ return NULL;
+
+ ret = xcalloc(1, sizeof(Indexs));
+
+ while ((n = getline(&ln, &linesiz, fp)) > 0) {
+ if (ln[n - 1] == '\n')
+ ln[--n] = '\0';
+ el = getadv(ln);
+ if(el == NULL)
+ continue;
+
+ addindexs(ret, el);
+ }
+ if (ferror(fp))
+ perror("getline");
+ free(ln);
+ fclose(fp);
+
+ if (ret->n == NULL) {
+ free(ret);
+ return NULL;
+ }
+
+ return ret;
+}
+
+int
+printelem(int fd, Elems *el, char *file, char *base, char *addr, char *port)
+{
+ char *path, *p, buf[PATH_MAX+1];
+ int len;
+
+ if (!strcmp(el->e[3], "server")) {
+ free(el->e[3]);
+ el->e[3] = xstrdup(addr);
+ }
+ if (!strcmp(el->e[4], "port")) {
+ free(el->e[4]);
+ el->e[4] = xstrdup(port);
+ }
+
+ /*
+ * Ignore if the path is from base, if it might be some h type with
+ * some URL and ignore various types that have different semantics but
+ * to point to some file or directory.
+ */
+ if ((el->e[2][0] != '\0'
+ && el->e[2][0] != '/'
+ && el->e[0][0] != 'i'
+ && el->e[0][0] != '2'
+ && el->e[0][0] != '3'
+ && el->e[0][0] != '8'
+ && el->e[0][0] != 'w'
+ && el->e[0][0] != 'T') &&
+ !(el->e[0][0] == 'h' && !strncmp(el->e[2], "URL:", 4))) {
+ path = file + strlen(base);
+ if ((p = strrchr(path, '/')))
+ len = p - path;
+ else
+ len = strlen(path);
+ snprintf(buf, sizeof(buf), "%s%.*s/%s", base, len, path, el->e[2]);
+
+ if ((path = realpath(buf, NULL)) &&
+ !strncmp(base, path, strlen(base))) {
+ p = path + strlen(base);
+ free(el->e[2]);
+ el->e[2] = xstrdup(p[0]? p : "/");
+ }
+ free(path);
+ }
+
+ if (dprintf(fd, "%.1s%s\t%s\t%s\t%s\r\n", el->e[0], el->e[1], el->e[2],
+ el->e[3], el->e[4]) < 0) {
+ perror("printelem: dprintf");
+ return -1;
+ }
+ return 0;
+}
diff --git a/index.gph b/index.gph
new file mode 100644
index 0000000..5942955
--- /dev/null
+++ b/index.gph
@@ -0,0 +1,4 @@
+0SubEntry 1 /entry1 localhost 3000
+0SubEntry 2 /entry2 localhost 3000
+0SubEntry 3 /entry3 localhost 3000
+.
diff --git a/log.c b/log.c
index eab204c..ef0f40e 100644
--- a/log.c
+++ b/log.c
@@ -1,5 +1,3 @@
-#define _POSIX_C_SOURCE 200112L
-
#include <time.h>
#include <errno.h>
#include <stdio.h>
diff --git a/main.c b/main.c
index 0d45d46..9a58508 100644
--- a/main.c
+++ b/main.c
@@ -1,5 +1,3 @@
-#define _POSIX_C_SOURCE 200112L
-
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/types.h>
@@ -41,6 +39,7 @@ create_server(const char *port)
perror("getaddrinfo");
return -1;
}
+
for (p = res; p != NULL; p = p->ai_next) {
if ((fd = socket(p->ai_family, p->ai_socktype, p->ai_protocol))
== -1) {
@@ -94,9 +93,9 @@ accept_connection(int s_fd)
struct sockaddr_storage sa;
socklen_t salen;
char host[HOSTMAX];
- int c_fd;
+ int cfd;
- if ((c_fd = accept(s_fd, (struct sockaddr *) & sa, &salen)) == -1) {
+ if ((cfd = accept(s_fd, (struct sockaddr *) & sa, &salen)) == -1) {
if (errno != EWOULDBLOCK || errno != EAGAIN) {
perror("accept");
exit(1);
@@ -110,17 +109,17 @@ accept_connection(int s_fd)
}
logmsg(LOG_INFO, "connection accepted from %s", host);
- return c_fd;
+ return cfd;
}
static void
-handle_client(int c_fd)
+handle_client(int cfd)
{
int n;
char buf[BUFSIZE];
char *lf;
- n = recv(c_fd, &buf, BUFSIZE - 1, 0);
+ n = recv(cfd, &buf, BUFSIZE - 1, 0);
switch (n) {
case -1:
if (errno != EWOULDBLOCK || errno != EAGAIN) {
@@ -139,20 +138,20 @@ handle_client(int c_fd)
*lf = '\0';
logmsg(LOG_INFO, "path: %s", buf);
- handle_path(c_fd, buf);
+ handle_path(cfd, buf);
}
- close(c_fd);
+ close(cfd);
}
static void
-main_loop(int s_fd)
+main_loop(int sfd)
{
int i, rc, end_server = 0;
- int c_fd, nfds = 1, curr_size = 0;
+ int cfd, nfds = 1, curr_size = 0;
struct pollfd pfds[OPEN_MAX];
memset(pfds, 0, sizeof(pfds));
- pfds[0].fd = s_fd;
+ pfds[0].fd = sfd;
pfds[0].events = POLLIN;
do {
@@ -175,15 +174,15 @@ main_loop(int s_fd)
end_server = 1;
break;
}
- if (pfds[i].fd == s_fd) {
+ if (pfds[i].fd == sfd) {
do {
- c_fd = accept_connection(s_fd);
- if (c_fd != -1) {
- pfds[nfds].fd = c_fd;
+ cfd = accept_connection(sfd);
+ if (cfd != -1) {
+ pfds[nfds].fd = cfd;
pfds[nfds].events = POLLIN;
nfds++;
}
- } while (c_fd != -1);
+ } while (cfd != -1);
} else {
handle_client(pfds[i].fd);
pfds[i].fd = -1;