char * conf_add_server(struct conf *cf, struct command *cmd, void *conf) { rstatus_t status; struct array *a; struct string *value; struct conf_server *field; uint8_t *p, *q, *start; uint8_t *name, *port, *weight; uint32_t k, namelen, portlen, weightlen; p = conf; a = (struct array *)(p + cmd->offset); field = array_push(a); if (field == NULL) { return CONF_ERROR; } conf_server_init(field); value = array_top(&cf->arg); status = string_duplicate(&field->pname, value); if (status != NC_OK) { array_pop(a); return CONF_ERROR; } /* parse "hostname:port:weight" from the end */ p = value->data + value->len - 1; start = value->data; name = NULL; namelen = 0; weight = NULL; weightlen = 0; port = NULL; portlen = 0; for (k = 0; k < 2; k++) { q = nc_strrchr(p, start, ':'); if (q == NULL) { break; } switch (k) { case 0: weight = q + 1; weightlen = (uint32_t)(p - weight + 1); break; case 1: port = q + 1; portlen = (uint32_t)(p - port + 1); break; default: NOT_REACHED(); } p = q - 1; } if (k != 2) { return "has an invalid \"hostname:port:weight\" format string"; } name = start; namelen = (uint32_t)(p - start + 1); field->weight = nc_atoi(weight, weightlen); if (field->weight < 0) { return "has an invalid weight in \"hostname:port:weight\" format string"; } field->port = nc_atoi(port, portlen); if (field->port < 0 || !nc_valid_port(field->port)) { return "has an invalid port in \"hostname:port:weight\" format string"; } status = string_copy(&field->name, name, namelen); if (status != NC_OK) { return CONF_ERROR; } status = nc_resolve(&field->name, field->port, &field->info); if (status != NC_OK) { return CONF_ERROR; } field->valid = 1; return CONF_OK; }
char * conf_set_listen(struct conf *cf, struct command *cmd, void *conf) { rstatus_t status; struct string *value; struct conf_listen *field; uint8_t *p, *name; uint32_t namelen; p = conf; field = (struct conf_listen *)(p + cmd->offset); if (field->valid == 1) { return "is a duplicate"; } value = array_top(&cf->arg); status = string_duplicate(&field->pname, value); if (status != NC_OK) { return CONF_ERROR; } if (value->data[0] == '/') { name = value->data; namelen = value->len; } else { uint8_t *q, *start, *port; uint32_t portlen; /* parse "hostname:port" from the end */ p = value->data + value->len - 1; start = value->data; q = nc_strrchr(p, start, ':'); if (q == NULL) { return "has an invalid \"hostname:port\" format string"; } port = q + 1; portlen = (uint32_t)(p - port + 1); p = q - 1; name = start; namelen = (uint32_t)(p - start + 1); field->port = nc_atoi(port, portlen); if (field->port < 0 || !nc_valid_port(field->port)) { return "has an invalid port in \"hostname:port\" format string"; } } status = string_copy(&field->name, name, namelen); if (status != NC_OK) { return CONF_ERROR; } status = nc_resolve(&field->name, field->port, &field->info); if (status != NC_OK) { return CONF_ERROR; } field->valid = 1; return CONF_OK; }
char * conf_set_listen(struct conf *cf, struct command *cmd, void *conf) { rstatus_t status; struct string *value; struct conf_listen *field; uint8_t *p, *name; uint32_t namelen; p = conf; field = (struct conf_listen *)(p + cmd->offset); if (field->valid == 1) { return "is a duplicate"; } value = array_top(&cf->arg); status = string_duplicate(&field->pname, value); if (status != NC_OK) { return CONF_ERROR; } if (value->data[0] == '/') { uint8_t *q, *start, *perm; uint32_t permlen; /* parse "socket_path permissions" from the end */ p = value->data + value->len -1; start = value->data; q = nc_strrchr(p, start, ' '); if (q == NULL) { /* no permissions field, so use defaults */ name = value->data; namelen = value->len; } else { perm = q + 1; permlen = (uint32_t)(p - perm + 1); p = q - 1; name = start; namelen = (uint32_t)(p - start + 1); errno = 0; field->perm = (mode_t)strtol((char *)perm, NULL, 8); if (errno || field->perm > 0777) { return "has an invalid file permission in \"socket_path permission\" format string"; } } } else { uint8_t *q, *start, *port; uint32_t portlen; /* parse "hostname:port" from the end */ p = value->data + value->len - 1; start = value->data; q = nc_strrchr(p, start, ':'); if (q == NULL) { return "has an invalid \"hostname:port\" format string"; } port = q + 1; portlen = (uint32_t)(p - port + 1); p = q - 1; name = start; namelen = (uint32_t)(p - start + 1); field->port = nc_atoi(port, portlen); if (field->port < 0 || !nc_valid_port(field->port)) { return "has an invalid port in \"hostname:port\" format string"; } } status = string_copy(&field->name, name, namelen); if (status != NC_OK) { return CONF_ERROR; } status = nc_resolve(&field->name, field->port, &field->info); if (status != NC_OK) { return CONF_ERROR; } field->valid = 1; return CONF_OK; }
char * conf_add_server(struct conf *cf, struct command *cmd, void *conf) { rstatus_t status; struct array *a; struct string *value; struct conf_server *field; uint8_t *p, *q, *start; uint8_t *pname, *addr, *port, *weight, *name; uint32_t k, delimlen, pnamelen, addrlen, portlen, weightlen, namelen; char delim[] = " ::"; p = conf; a = (struct array *)(p + cmd->offset); field = array_push(a); if (field == NULL) { return CONF_ERROR; } conf_server_init(field); value = array_top(&cf->arg); /* parse "hostname:port:weight [name]" or "/path/unix_socket:weight [name]" from the end */ p = value->data + value->len - 1; start = value->data; addr = NULL; addrlen = 0; weight = NULL; weightlen = 0; port = NULL; portlen = 0; name = NULL; namelen = 0; delimlen = value->data[0] == '/' ? 2 : 3; for (k = 0; k < sizeof(delim); k++) { q = nc_strrchr(p, start, delim[k]); if (q == NULL) { if (k == 0) { /* * name in "hostname:port:weight [name]" format string is * optional */ continue; } break; } switch (k) { case 0: name = q + 1; namelen = (uint32_t)(p - name + 1); break; case 1: weight = q + 1; weightlen = (uint32_t)(p - weight + 1); break; case 2: port = q + 1; portlen = (uint32_t)(p - port + 1); break; default: NOT_REACHED(); } p = q - 1; } if (k != delimlen) { return "has an invalid \"hostname:port:weight [name]\"or \"/path/unix_socket:weight [name]\" format string"; } pname = value->data; pnamelen = namelen > 0 ? value->len - (namelen + 1) : value->len; status = string_copy(&field->pname, pname, pnamelen); if (status != NC_OK) { array_pop(a); return CONF_ERROR; } addr = start; addrlen = (uint32_t)(p - start + 1); field->weight = nc_atoi(weight, weightlen); if (field->weight < 0) { return "has an invalid weight in \"hostname:port:weight [name]\" format string"; } else if (field->weight == 0) { return "has a zero weight in \"hostname:port:weight [name]\" format string"; } if (value->data[0] != '/') { field->port = nc_atoi(port, portlen); if (field->port < 0 || !nc_valid_port(field->port)) { return "has an invalid port in \"hostname:port:weight [name]\" format string"; } } if (name == NULL) { /* * To maintain backward compatibility with libmemcached, we don't * include the port as the part of the input string to the consistent * hashing algorithm, when it is equal to 11211. */ if (field->port == CONF_DEFAULT_KETAMA_PORT) { name = addr; namelen = addrlen; } else { name = addr; namelen = addrlen + 1 + portlen; } } status = string_copy(&field->name, name, namelen); if (status != NC_OK) { return CONF_ERROR; } status = string_copy(&field->addrstr, (uint8_t *)addr, addrlen); if (status != NC_OK) { return CONF_ERROR; } /* * The address resolution of the backend server hostname is lazy. * The resolution occurs when a new connection to the server is * created, which could either be the first time or every time * the server gets re-added to the pool after an auto ejection */ field->valid = 1; return CONF_OK; }
char * conf_add_server(struct conf *cf, struct command *cmd, void *conf) { rstatus_t status; struct array *a; struct string *value; struct conf_server *field; uint8_t *p, *q, *start; uint8_t *pname, *addr, *port, *weight, *name; uint32_t k, pnamelen, addrlen, portlen, weightlen, namelen; struct string address; char delim[] = " ::"; string_init(&address); p = conf; a = (struct array *)(p + cmd->offset); field = array_push(a); if (field == NULL) { return CONF_ERROR; } conf_server_init(field); value = array_top(&cf->arg); /* parse "hostname:port:weight [name]" from the end */ p = value->data + value->len - 1; start = value->data; addr = NULL; addrlen = 0; weight = NULL; weightlen = 0; port = NULL; portlen = 0; name = NULL; namelen = 0; for (k = 0; k < sizeof(delim); k++) { q = nc_strrchr(p, start, delim[k]); if (q == NULL) { if (k == 0) { /* * name in "hostname:port:weight [name]" format string is * optional */ continue; } break; } switch (k) { case 0: name = q + 1; namelen = (uint32_t)(p - name + 1); break; case 1: weight = q + 1; weightlen = (uint32_t)(p - weight + 1); break; case 2: port = q + 1; portlen = (uint32_t)(p - port + 1); break; default: NOT_REACHED(); } p = q - 1; } if (k != 3) { return "has an invalid \"hostname:port:weight [name]\" format string"; } pname = value->data; pnamelen = namelen > 0 ? value->len - (namelen + 1) : value->len; status = string_copy(&field->pname, pname, pnamelen); if (status != NC_OK) { array_pop(a); return CONF_ERROR; } addr = start; addrlen = (uint32_t)(p - start + 1); field->weight = nc_atoi(weight, weightlen); if (field->weight < 0) { return "has an invalid weight in \"hostname:port:weight [name]\" format string"; } field->port = nc_atoi(port, portlen); if (field->port < 0 || !nc_valid_port(field->port)) { return "has an invalid port in \"hostname:port:weight [name]\" format string"; } if (name == NULL) { /* * To maintain backward compatibility with libmemcached, we don't * include the port as the part of the input string to the consistent * hashing algorithm, when it is equal to 11211. */ if (field->port == CONF_DEFAULT_KETAMA_PORT) { name = addr; namelen = addrlen; } else { name = addr; namelen = addrlen + 1 + portlen; } } status = string_copy(&field->name, name, namelen); if (status != NC_OK) { return CONF_ERROR; } status = string_copy(&address, addr, addrlen); if (status != NC_OK) { return CONF_ERROR; } status = nc_resolve(&address, field->port, &field->info); if (status != NC_OK) { string_deinit(&address); return CONF_ERROR; } string_deinit(&address); field->valid = 1; return CONF_OK; }