config.c
changeset 26 6d615203d963
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/config.c	Sun Jul 06 23:33:24 2008 +0300
@@ -0,0 +1,153 @@
+#include <stdio.h>
+#include <ctype.h>
+
+#include "config.h"
+#include "common.h"
+
+void endpoint_init (struct config_endpoint *endpoint, unsigned short default_port) {
+    // snprintf the default port as a string
+    snprintf(endpoint->_data.default_port, PORT_TEXT_LEN, "%hu", default_port);
+
+    // set up defaults
+    endpoint->family = PF_INET;
+    endpoint->af.inet.addr = NULL;
+    endpoint->af.inet.port = endpoint->_data.default_port;
+}
+
+/*
+ * Parse an endpoint address in human-readable format into the given endpoint. You can then use the socket_*
+ * functions to work with endpoints and sockets.
+ *
+ * Formats supported:
+ *  =foo.sock, =/quux/bar.sock
+ *  hostname, 12.34.56.78, [::1]
+ *  hostname:port, 12.34.56.78:port, [::1]:port
+ */
+int endpoint_parse (struct config_endpoint *endpoint, const char *addr_spec) {
+    // for empty addr specs, just return
+    if (!addr_spec || *addr_spec == '\0')
+        return 1;
+
+    if (sscanf(addr_spec, "=%" PATH_TEXT_LEN_STR "s", endpoint->_data.path) == 1) {
+        // local unix socket
+        endpoint->family = PF_LOCAL;
+        endpoint->af.local.path =  endpoint->_data.path;
+
+    } else if (
+            sscanf(addr_spec, "[%" ADDR_TEXT_LEN_STR "[^]] ]:%" PORT_TEXT_LEN_STR "s", endpoint->_data.addr, endpoint->_data.port) == 2
+        ||  sscanf(addr_spec, "%" ADDR_TEXT_LEN_STR "[^:] :%" PORT_TEXT_LEN_STR "s", endpoint->_data.addr, endpoint->_data.port) == 2
+    ) {
+        endpoint->family = PF_INET;
+        endpoint->af.inet.addr = endpoint->_data.addr;
+        endpoint->af.inet.port = endpoint->_data.port;
+
+    } else if (
+            sscanf(addr_spec, "[%" ADDR_TEXT_LEN_STR "[^]] ]", endpoint->_data.addr) == 1
+        ||  sscanf(addr_spec, "%" ADDR_TEXT_LEN_STR "[^:]", endpoint->_data.addr) == 1
+    ) {
+        endpoint->family = PF_INET;
+        endpoint->af.inet.addr = endpoint->_data.addr;
+
+    } else {
+        // unknown foramt
+        ERROR("unkown address format: %s", addr_spec);
+    }
+
+    return 0;
+
+error:
+    return -1;
+}
+
+int parse_hostport (char *hostport, char **host, char **port) {
+    char *c;
+
+    int brace = 0, colon = 0;
+    *host = *port = NULL;
+
+    for (c = hostport; *c != '\0'; c++) {
+        if (isspace(*c))
+            continue;
+
+        switch (*c) {
+            case '[':
+                if (c > hostport) {
+                    error("parse_hostport: %c must be first char, if any: %s", *c, hostport);
+                    return -1;
+                }
+                
+                brace = *c;
+                break;
+
+            case ']':
+                if (!brace) {
+                    error("parse_hostport: %c without matching brace: %s", *c, hostport);
+                    return -1;
+                }
+
+                if (!*host) {
+                    error("parse_hostport: empty hostname: %s", hostport);
+                    return -1;
+                }
+
+                brace = 0;
+                break;
+            
+            case ':':
+                if (brace) {
+                    // colons inside braces are left as-is
+                    continue;
+                }
+
+                if (!*host) {
+                    error("parse_hostport: colon before hostname: %s", hostport);
+                    return -1;
+                }
+
+                if (*port) {
+                    error("parse_hostport: colon after port: %s", hostport);
+                    return -1;
+                }
+
+                if (colon) {
+                    error("parse_hostport: too many colons: %s", hostport);
+                    return -1;
+                };
+
+                // finished parsing the host part, move on to the port part
+                colon = ':';
+                *c = '\0';
+                break;
+
+            default:
+                if (!*host) {
+                    // first char of the host
+                    *host = c;
+
+                } else if (colon && !*port) {
+                    // first char of the port
+                    *port = c;
+
+                } // else a part of either, don't care about it
+
+                break;
+        }
+    }
+
+    if (!*host) {
+        error("parse_hostport: missing hostname: %s", hostport);
+        return -1;
+    }
+
+    if (brace) {
+        error("parse_hostport: missing close-brace for %c: %s", brace, hostport);
+        return -1;
+    }
+
+    if (colon && !*port) {
+        error("parse_hostport: missing port: %s", hostport);
+        return -1;
+    }
+
+    return 0;
+}