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