summaryrefslogtreecommitdiff
path: root/gopher.c
diff options
context:
space:
mode:
Diffstat (limited to 'gopher.c')
-rw-r--r--gopher.c203
1 files changed, 104 insertions, 99 deletions
diff --git a/gopher.c b/gopher.c
index a112150ea..28caab032 100644
--- a/gopher.c
+++ b/gopher.c
@@ -23,6 +23,7 @@
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
+#include <arpa/inet.h>
#include <netdb.h>
#include <stdlib.h>
#include <unistd.h>
@@ -33,70 +34,82 @@
#include <hurd/hurd_types.h>
#include <hurd/netfs.h>
-/* do a DNS lookup for NAME and store result in *ENT */
+/* do a DNS lookup for NAME:PORT and store results in ENT and error in H_ERR */
error_t
-lookup_host (char *name, struct hostent **ent)
+lookup_host (char *name, unsigned short port, struct addrinfo **ai)
{
+ /* XXX: cache host lookups. */
+ struct addrinfo hints;
+ char *service;
error_t err;
- struct hostent hentbuf;
- int herr = 0;
- char *tmpbuf;
- size_t tmpbuflen = 512;
- tmpbuf = (char *) malloc (tmpbuflen);
- if (!tmpbuf)
+ memset (&hints, 0, sizeof(hints));
+ hints.ai_family = PF_INET;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_protocol = IPPROTO_IP;
+ hints.ai_flags = AI_NUMERICSERV;
+
+ err = asprintf (&service, "%hu", port);
+ if (err == -1)
return ENOMEM;
- /* XXX: use getaddrinfo */
- while ((err = gethostbyname_r (name, &hentbuf, tmpbuf,
- tmpbuflen, ent, &herr)) == ERANGE)
- {
- tmpbuflen *= 2;
- tmpbuf = (char *) realloc (tmpbuf, tmpbuflen);
- if (!tmpbuf)
- return ENOMEM;
- }
- free (tmpbuf);
+ err = getaddrinfo (name, service, &hints, ai);
- if (!herr)
- return EINVAL;
+ free (service);
- return 0;
+ return err;
}
-/* store the remote socket in *FD after writing a gopher selector
- to it */
+/* open ENTRY and store the remote socket in *FD */
error_t
-open_selector (struct netnode * node, int *fd)
+gopher_open (struct gopher_entry *entry, int *fd)
{
+ struct addrinfo *addr;
error_t err;
- struct hostent *server_ent;
- struct sockaddr_in server;
ssize_t written;
size_t towrite;
+
+ *fd = socket (PF_INET, SOCK_STREAM, 0);
+ if (*fd < 0)
+ {
+ debug ("failed to open socket (errno: %s)", strerror(errno));
+ return errno;
+ }
- err = lookup_host (node->server, &server_ent);
- if (!err)
- return err;
- if (debug_flag)
- fprintf (stderr, "trying to open %s:%d/%s\n", node->server,
- node->port, node->selector);
+ err = lookup_host (entry->server, entry->port, &addr);
+ if (err)
+ {
+ debug ("looking up host failed: %s", gai_strerror(err));
+ return err;
+ }
- server.sin_family = AF_INET;
- server.sin_port = htons (node->port);
- server.sin_addr = *(struct in_addr *) server_ent->h_addr;
+ /* XXX: cache host lookups. */
+ do
+ {
+ debug ("connecting to %s:%hu...",
+ inet_ntoa(((struct sockaddr_in *)addr->ai_addr)->sin_addr),
+ ntohs(((struct sockaddr_in *)addr->ai_addr)->sin_port));
- *fd = socket (PF_INET, SOCK_STREAM, 0);
- if (*fd == -1)
- return errno;
+ err = connect (*fd, (struct sockaddr_in *) addr->ai_addr, addr->ai_addrlen);
+ if (err)
+ debug ("connect() failed! errno: %s", strerror(errno));
- err = connect (*fd, (struct sockaddr *) &server, sizeof (server));
- if (err == -1)
- return errno;
+ addr = addr->ai_next;
+ }
+ while (addr && err);
- towrite = strlen (node->selector);
+ freeaddrinfo(addr);
+ if (err)
+ {
+ close (*fd);
+ return errno;
+ }
+
+ /* Write selector to *FD. */
+
+ towrite = strlen (entry->selector);
/* guard against EINTR failures */
- written = TEMP_FAILURE_RETRY (write (*fd, node->selector, towrite));
+ written = TEMP_FAILURE_RETRY (write (*fd, entry->selector, towrite));
written += TEMP_FAILURE_RETRY (write (*fd, "\r\n", 2));
if (written == -1 || written < (towrite + 2))
return errno;
@@ -104,76 +117,68 @@ open_selector (struct netnode * node, int *fd)
return 0;
}
-/* fetch a directory node from the gopher server
- DIR should already be locked */
+/* List all entries from ENTRY and store them in *MAP. */
error_t
-fill_dirnode (struct netnode * dir)
+gopher_list_entries (struct gopher_entry *entry, struct gopher_entry **map)
{
- error_t err = 0;
FILE *sel;
- int sel_fd;
- char *line;
- size_t line_len;
- struct node *nd, **prevp;
-
- err = open_selector (dir, &sel_fd);
- if (err)
- return err;
- if (debug_flag)
- fprintf (stderr, "filling out dir %s\n", dir->name);
- errno = 0;
- sel = fdopen (sel_fd, "r");
- if (!sel)
- {
- close (sel_fd);
- return errno;
- }
+ char *line = NULL;
+ size_t line_len = 0;
+ struct gopher_entry *prev = NULL;
+ error_t err = 0;
- dir->noents = TRUE;
- dir->num_ents = 0;
- prevp = &dir->ents;
- line = NULL;
- line_len = 0;
+ {
+ int fd;
+ err = gopher_open (entry, &fd);
+ if (err)
+ return err;
+
+ sel = fdopen (fd, "r");
+ if (!sel)
+ {
+ close (fd);
+ return errno;
+ }
+ }
+
while (getline (&line, &line_len, sel) >= 0)
{
- char type, *name, *selector, *server;
- unsigned short port;
- char *tok, *endtok;
+ /* Parse gopher entry. */
+ struct gopher_entry *cur;
+ char *tmp;
+
+ debug ("%s", line);
- if (debug_flag)
- fprintf (stderr, "%s\n", line);
if (*line == '.' || err)
break;
- /* parse the gopher node description */
- type = *line;
- endtok = line + 1;
- name = strsep (&endtok, "\t");
- selector = strsep (&endtok, "\t");
- server = strsep (&endtok, "\t");
- port = (unsigned short) atoi (strsep (&endtok, "\t"));
-
- nd = gopherfs_make_node (type, name, selector, server, port);
- if (!nd)
+ cur = malloc (sizeof (struct gopher_entry));
+ if (!cur)
{
- err = ENOMEM;
- break;
+ err = ENOMEM;
+ break;
}
- *prevp = nd;
- nd->prevp = prevp;
- prevp = &nd->next;
- dir->num_ents++;
- if (dir->noents)
- dir->noents = FALSE;
+ cur->type = line[0];
+ tmp = line + 1;
+ cur->name = strdup(strsep (&tmp, "\t"));
+ cur->selector = strdup(strsep (&tmp, "\t"));
+ cur->server = strdup(strsep (&tmp, "\t"));
+ cur->port = (unsigned short) atoi (strsep (&tmp, "\t"));
+
+ if (!*map)
+ /* First item. */
+ *map = cur;
+ else
+ prev->next = cur;
+
+ cur->prev = prev;
+ cur->next = NULL;
+ prev = cur;
}
- free (line);
- if (err)
- {
- fclose (sel);
- return err;
- }
+ free (line);
+ fclose (sel);
- return 0;
+ return err;
}