int slowlog_parse_option(char *options) { char *pos, *begin, *end; int value; if (options == NULL) return NC_ERROR; begin = options; end = options + strlen(options); pos = strstr(begin, ","); if (pos == NULL) return NC_ERROR; if (pos == begin) { slowlog_log_slower_than = SLOWLOG_LOG_SLOWER_THAN; } else { value = nc_atoi(begin,pos-begin); if (value < 0) return NC_ERROR; slowlog_log_slower_than = (long long)value; } begin = pos+1; if (begin > end) return NC_ERROR; pos = strstr(begin, ","); if (pos == NULL) return NC_ERROR; if (pos == begin) { statistics_period = SLOWLOG_STATISTICS_PERIOD; } else { value = nc_atoi(begin,pos-begin); if (value < 0) return NC_ERROR; if (value != 12 && value != 24 && value != 48 && value != 96) { return NC_ERROR; } statistics_period = value; } begin = pos+1; if (begin > end) { statistics_days = SLOWLOG_STATISTICS_DAYS; return NC_OK; } value = nc_atoi(begin,end-begin); if (value < 0) return NC_ERROR; statistics_days = value; return NC_OK; }
char * conf_set_num(struct conf *cf, struct command *cmd, void *conf) { uint8_t *p; int num, *np; struct string *value; p = conf; np = (int *)(p + cmd->offset); if (*np != CONF_UNSET_NUM) { return "is a duplicate"; } value = array_top(&cf->arg); num = nc_atoi(value->data, value->len); if (num < 0) { return "is not a number"; } *np = num; 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 *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; }
static rstatus_t nc_get_options(int argc, char **argv, struct instance *nci) { int c, value; opterr = 0; for (;;) { c = getopt_long(argc, argv, short_options, long_options, NULL); if (c == -1) { /* no more options */ break; } switch (c) { case 'h': show_version = 1; show_help = 1; break; case 'V': show_version = 1; break; case 't': test_conf = 1; break; case 'd': daemonize = 1; break; case 'D': describe_stats = 1; show_version = 1; break; case 'v': value = nc_atoi(optarg, strlen(optarg)); if (value < 0) { log_stderr("nutcracker: option -v requires a number"); return NC_ERROR; } nci->log_level = value; break; case 'o': nci->log_filename = optarg; break; case 'c': nci->conf_filename = optarg; break; case 's': value = nc_atoi(optarg, strlen(optarg)); if (value < 0) { log_stderr("nutcracker: option -s requires a number"); return NC_ERROR; } if (!nc_valid_port(value)) { log_stderr("nutcracker: option -s value %d is not a valid " "port", value); return NC_ERROR; } nci->stats_port = (uint16_t)value; break; case 'i': value = nc_atoi(optarg, strlen(optarg)); if (value < 0) { log_stderr("nutcracker: option -i requires a number"); return NC_ERROR; } nci->stats_interval = value; break; case 'a': nci->stats_addr = optarg; break; case 'p': nci->pid_filename = optarg; break; case 'm': value = nc_atoi(optarg, strlen(optarg)); if (value <= 0) { log_stderr("nutcracker: option -m requires a non-zero number"); return NC_ERROR; } if (value < NC_MBUF_MIN_SIZE || value > NC_MBUF_MAX_SIZE) { log_stderr("nutcracker: mbuf chunk size must be between %zu and" " %zu bytes", NC_MBUF_MIN_SIZE, NC_MBUF_MAX_SIZE); return NC_ERROR; } nci->mbuf_chunk_size = (size_t)value; break; case 'M': value = nc_atoi(optarg, strlen(optarg)); if (value < 0) { log_stderr("nutcracker: option -M requires a non-negative number"); return NC_ERROR; } nci->mbuf_pool_size = (unsigned)value; break; case '?': switch (optopt) { case 'o': case 'c': case 'p': log_stderr("nutcracker: option -%c requires a file name", optopt); break; case 'm': case 'M': case 'v': case 's': case 'i': log_stderr("nutcracker: option -%c requires a number", optopt); break; case 'a': log_stderr("nutcracker: option -%c requires a string", optopt); break; default: log_stderr("nutcracker: invalid option -- '%c'", optopt); break; } return NC_ERROR; default: log_stderr("nutcracker: invalid option -- '%c'", optopt); return NC_ERROR; } } return NC_OK; }
static rstatus_t sentinel_proc_pub(struct context *ctx, struct msg *msg) { rstatus_t status; struct string pool_name, server_name, server_ip, tmp_string, pub_titile, pub_event; struct mbuf *line_buf; int server_port; string_init(&tmp_string); string_init(&pool_name); string_init(&server_name); string_init(&server_ip); string_set_text(&pub_titile, "pmessage"); string_set_text(&pub_event, "+switch-master"); line_buf = mbuf_get(); if (line_buf == NULL) { goto error; } /* get line in line num 3 for pub titile */ msg_read_line(msg, line_buf, 3); if (mbuf_length(line_buf) == 0) { log_error("read line failed from sentinel pmessage when skip line not used."); goto error; } status = mbuf_read_string(line_buf, CR, &tmp_string); if (status != NC_OK || string_compare(&pub_titile, &tmp_string)) { log_error("pub title error(lineinfo %.*s)", tmp_string.len, tmp_string.data); goto error; } /* get line in line num 7 for pub event */ msg_read_line(msg, line_buf, 4); if (mbuf_length(line_buf) == 0) { log_error("read line failed from sentinel pmessage when skip line not used."); goto error; } status = mbuf_read_string(line_buf, CR, &tmp_string); if (status != NC_OK || string_compare(&pub_event, &tmp_string)) { log_error("pub channel error(lineinfo %.*s)", tmp_string.len, tmp_string.data); goto error; } /* get line in line num 9 for pub info */ msg_read_line(msg, line_buf, 2); if (mbuf_length(line_buf) == 0) { log_error("read line failed from sentinel pmessage when skip line not used."); goto error; } /* parse switch master info */ /* get pool name */ status = mbuf_read_string(line_buf, SENTINEL_SERVERNAME_SPLIT, &pool_name); if (status != NC_OK) { log_error("get pool name string failed."); goto error; } /* get server name */ status = mbuf_read_string(line_buf, ' ', &server_name); if (status != NC_OK) { log_error("get server name string failed."); goto error; } /* skip old ip and port string */ status = mbuf_read_string(line_buf, ' ', NULL); if (status != NC_OK) { log_error("skip old ip string failed."); goto error; } status = mbuf_read_string(line_buf, ' ', NULL); if (status != NC_OK) { log_error("skip old port string failed."); goto error; } /* get new server ip string */ status = mbuf_read_string(line_buf, ' ', &server_ip); if (status != NC_OK) { log_error("get new server ip string failed."); goto error; } /* get new server port */ status = mbuf_read_string(line_buf, CR, &tmp_string); if (status != NC_OK) { log_error("get new server port string failed."); goto error; } server_port = nc_atoi(tmp_string.data, tmp_string.len); if (server_port < 0) { log_error("tanslate server port string to int failed."); goto error; } status = server_switch(ctx, &pool_name, &server_name, &server_ip, server_port); if (status == NC_OK) { conf_rewrite(ctx); } status = NC_OK; done: if (line_buf != NULL) { mbuf_put(line_buf); } string_deinit(&tmp_string); string_deinit(&server_ip); string_deinit(&server_name); string_deinit(&pool_name); return status; error: status = NC_ERROR; goto done; }
rstatus_t slowlog_command_make_reply(struct context *ctx, struct conn *conn, struct msg *msg, struct msg *pmsg) { rstatus_t status; uint32_t nkeys; struct keypos *kp; char *contents; uint32_t subcmdlen; ASSERT(conn->client && !conn->proxy); ASSERT(msg->request); ASSERT(pmsg != NULL && !pmsg->request); ASSERT(msg->owner == conn); ASSERT(conn->owner == ctx->manager); nkeys = array_n(msg->keys); ASSERT(nkeys >= 1); kp = array_get(msg->keys, 0); subcmdlen = (uint32_t)(kp->end-kp->start); if (subcmdlen==strlen("reset")&&!memcmp(kp->start,"reset",subcmdlen)){ if (nkeys != 1) { goto format_error; } slowlog_reset(); status = msg_append_full(pmsg, (uint8_t*)"OK", 2); if (status != NC_OK) { conn->err = ENOMEM; return status; } goto done; } else if (subcmdlen==strlen("id")&&!memcmp(kp->start,"id",subcmdlen)){ int buf_len; uint8_t buf[30]; long long id; if (nkeys != 1) { goto format_error; } pthread_rwlock_rdlock(&rwlocker); id = slowlog_entry_id; pthread_rwlock_unlock(&rwlocker); buf_len = nc_scnprintf(buf,30,"%lld",id); status = msg_append_full(pmsg, buf, (size_t)buf_len); if (status != NC_OK) { conn->err = ENOMEM; return status; } goto done; } else if (subcmdlen==strlen("len")&&!memcmp(kp->start,"len",subcmdlen)){ int len, buf_len; uint8_t buf[20]; if (nkeys != 1) { goto format_error; } pthread_rwlock_rdlock(&rwlocker); len = slowlog_len; pthread_rwlock_unlock(&rwlocker); buf_len = nc_scnprintf(buf,20,"%d",len); status = msg_append_full(pmsg, buf, (size_t)buf_len); if (status != NC_OK) { conn->err = ENOMEM; return status; } goto done; } else if (subcmdlen==strlen("get")&&!memcmp(kp->start,"get",subcmdlen)){ int count, sent = 0, buf_len; uint8_t buf[50]; slowlog_entry *se; struct string *str; if (nkeys == 1) { count = 10; } else if (nkeys == 2) { kp = array_get(msg->keys, 1); count = nc_atoi(kp->start, (kp->end-kp->start)); if (count < 0) { goto format_error; } } else { goto format_error; } pthread_rwlock_rdlock(&rwlocker); se = STAILQ_FIRST(&slowlog); while(count-- && se != NULL) { int nfield; uint32_t j; sent++; buf_len = nc_scnprintf(buf,50,"%d) 1) %lld\r\n",sent, se->id); status = msg_append_full(pmsg, buf, (size_t)buf_len); if (status != NC_OK) { pthread_rwlock_unlock(&rwlocker); conn->err = ENOMEM; return status; } buf_len = nc_scnprintf(buf,50," 2) %lld\r\n",se->time); status = msg_append_full(pmsg, buf, (size_t)buf_len); if (status != NC_OK) { pthread_rwlock_unlock(&rwlocker); conn->err = ENOMEM; return status; } buf_len = nc_scnprintf(buf,50," 3) %lld\r\n",se->duration); status = msg_append_full(pmsg, buf, (size_t)buf_len); if (status != NC_OK) { pthread_rwlock_unlock(&rwlocker); conn->err = ENOMEM; return status; } str = msg_type_string(se->cmdtype); nfield = 1; buf_len = nc_scnprintf(buf,50," 4) %d) %s\r\n",nfield++,str->data); status = msg_append_full(pmsg, buf, (size_t)buf_len); if (status != NC_OK) { pthread_rwlock_unlock(&rwlocker); conn->err = ENOMEM; return status; } buf_len = nc_scnprintf(buf,50," %d) %d\r\n",nfield++,se->keys_count); status = msg_append_full(pmsg, buf, (size_t)buf_len); if (status != NC_OK) { pthread_rwlock_unlock(&rwlocker); conn->err = ENOMEM; return status; } if (se->keys != NULL) { for (j = 0; j < array_n(se->keys); j ++) { str = array_get(se->keys, j); buf_len = nc_scnprintf(buf,50," %d) ",nfield++); status = msg_append_full(pmsg, buf, (size_t)buf_len); if (status != NC_OK) { pthread_rwlock_unlock(&rwlocker); conn->err = ENOMEM; return status; } status = msg_append_full(pmsg, str->data, (size_t)str->len); if (status != NC_OK) { pthread_rwlock_unlock(&rwlocker); conn->err = ENOMEM; return status; } status = msg_append_full(pmsg, (uint8_t *)CRLF, CRLF_LEN); if (status != NC_OK) { pthread_rwlock_unlock(&rwlocker); conn->err = ENOMEM; return status; } } } se = STAILQ_NEXT(se, next); } pthread_rwlock_unlock(&rwlocker); if (msg_empty(pmsg)) { status = msg_append_full(pmsg, (uint8_t*)"END", 3); if (status != NC_OK) { conn->err = ENOMEM; return status; } goto done; } return NC_OK; } else if (subcmdlen==strlen("overview") && !memcmp(kp->start,"overview",subcmdlen)) { int count, buf_len; uint8_t buf[50]; int j, idx, id; struct statistics_oneday *so; if (nkeys == 1) { count = 10; } else if (nkeys == 2) { kp = array_get(msg->keys, 1); count = nc_atoi(kp->start, (kp->end-kp->start)); if (count < 0) { goto format_error; } } else { goto format_error; } if (slowlog_statistics == NULL) { status = msg_append_full(pmsg, (uint8_t*)"END", 3); if (status != NC_OK) { conn->err = ENOMEM; return status; } goto done; } if (count > statistics_days) count = statistics_days; pthread_mutex_lock(&statistics_locker); idx = today_idx; id = 1; while (count--) { so = &slowlog_statistics[idx]; if (so->year == 0) break; buf_len = nc_scnprintf(buf,50,"%d) %d-%d-%d ",id++,so->year+1900,so->mon+1,so->day); status = msg_append_full(pmsg, buf, (size_t)buf_len); if (status != NC_OK) { pthread_mutex_unlock(&statistics_locker); conn->err = ENOMEM; return status; } for (j = 0; j < statistics_period-1; j ++) { buf_len = nc_scnprintf(buf,50,"%lld ",so->periods[j]); status = msg_append_full(pmsg, buf, (size_t)buf_len); if (status != NC_OK) { pthread_mutex_unlock(&statistics_locker); conn->err = ENOMEM; return status; } } buf_len = nc_scnprintf(buf,50,"%lld\r\n",so->periods[statistics_period-1]); status = msg_append_full(pmsg, buf, (size_t)buf_len); if (status != NC_OK) { pthread_mutex_unlock(&statistics_locker); conn->err = ENOMEM; return status; } if (--idx < 0) { idx = statistics_days - 1; } } pthread_mutex_unlock(&statistics_locker); if (msg_empty(pmsg)) { status = msg_append_full(pmsg, (uint8_t*)"END", 3); if (status != NC_OK) { conn->err = ENOMEM; return status; } goto done; } return NC_OK; } else { goto format_error; } format_error: contents = "ERR: slowlog command format is error."; status = msg_append_full(pmsg, (uint8_t *)contents, strlen(contents)); if (status != NC_OK) { conn->err = ENOMEM; return status; } goto done; done: status = msg_append_full(pmsg, (uint8_t *)CRLF, CRLF_LEN); if (status != NC_OK) { conn->err = ENOMEM; return status; } return NC_OK; }
static rstatus_t sentinel_proc_sentinel_info(struct context *ctx, struct msg *msg) { rstatus_t status; int i, master_num, switch_num; struct string pool_name, server_name, server_ip, tmp_string, sentinel_masters_prefix, master_ok; struct mbuf *line_buf; int server_port; string_init(&tmp_string); string_init(&pool_name); string_init(&server_name); string_init(&server_ip); string_set_text(&sentinel_masters_prefix, "sentinel_masters"); string_set_text(&master_ok, "status=ok"); line_buf = mbuf_get(); if (line_buf == NULL) { goto error; } /* get sentinel master num at line 3 */ msg_read_line(msg, line_buf, 3); if (mbuf_length(line_buf) == 0) { log_error("read line failed from sentinel ack info when skip line not used."); goto error; } status = mbuf_read_string(line_buf, ':', &tmp_string); if (status != NC_OK || string_compare(&sentinel_masters_prefix, &tmp_string)) { goto error; } status = mbuf_read_string(line_buf, CR, &tmp_string); if (status != NC_OK) { goto error; } master_num = nc_atoi(tmp_string.data, tmp_string.len); if (master_num < 0) { log_error("parse master number from sentinel ack info failed."); goto error; } /* skip 3 line in ack info which is not used. */ msg_read_line(msg, line_buf, 3); if (mbuf_length(line_buf) == 0) { log_error("read line failed from sentinel ack info when skip line not used."); goto error; } /* parse master info from sentinel ack info */ switch_num = 0; for (i = 0; i < master_num; i++) { msg_read_line(msg, line_buf, 1); if (mbuf_length(line_buf) == 0) { log_error("read line failed from sentinel ack info when parse master item."); goto error; } log_debug(LOG_INFO, "master item line : %.*s", mbuf_length(line_buf), line_buf->pos); /* skip master item prefix */ status = mbuf_read_string(line_buf, ':', NULL); if (status != NC_OK) { log_error("skip master item prefix failed"); goto error; } /* skip master item server name prefix */ status = mbuf_read_string(line_buf, '=', NULL); if (status != NC_OK) { log_error("skip master item server name prefix failed."); goto error; } /* get server pool name */ status = mbuf_read_string(line_buf, SENTINEL_SERVERNAME_SPLIT, &pool_name); if (status != NC_OK) { log_error("get server pool name failed."); goto error; } /* get server name */ status = mbuf_read_string(line_buf, ',', &server_name); if (status != NC_OK) { log_error("get server name failed."); goto error; } /* get master status */ status = mbuf_read_string(line_buf, ',', &tmp_string); if (status != NC_OK) { log_error("get master status failed."); goto error; } if (string_compare(&master_ok, &tmp_string)) { log_error("master item status is not ok, use it anyway"); } /* skip ip string prefix name */ status = mbuf_read_string(line_buf, '=', NULL); if (status != NC_OK) { log_error("skip master item address prefix failed."); goto error; } /* get server ip string */ status = mbuf_read_string(line_buf, ':', &server_ip); if (status != NC_OK) { log_error("get server ip string failed."); goto error; } /* get server port */ status = mbuf_read_string(line_buf, ',', &tmp_string); if (status != NC_OK) { log_error("get server port string failed."); goto error; } server_port = nc_atoi(tmp_string.data, tmp_string.len); if (server_port < 0) { log_error("tanslate server port string to int failed."); goto error; } status = server_switch(ctx, &pool_name, &server_name, &server_ip, server_port); /* if server is switched, add switch number */ if (status == NC_OK) { switch_num++; } } if (switch_num > 0) { conf_rewrite(ctx); } status = NC_OK; done: if (line_buf != NULL) { mbuf_put(line_buf); } string_deinit(&tmp_string); string_deinit(&pool_name); string_deinit(&server_name); string_deinit(&server_ip); return status; error: status = NC_ERROR; goto done; }
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_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, 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; }
static rstatus_t nc_get_options(int argc, char **argv, struct env_master *env) { int c, value; int len; int cores; opterr = 0; //ASSERT(0); for (;;) { c = getopt_long(argc, argv, short_options, long_options, NULL); if (c == -1) { /* no more options */ break; } switch (c) { case 'h': show_version = 1; show_help = 1; break; case 'V': show_version = 1; break; case 't': test_conf = 1; break; case 'd': daemonize = 1; break; case 'D': describe_stats = 1; show_version = 1; break; case 'v': value = nc_atoi(optarg, strlen(optarg)); if (value < 0) { log_stderr("nutcracker: option -v requires a number"); return NC_ERROR; } env->log_level = value; break; case 'o': env->log_filename = optarg; len = nc_strlen(optarg) + 1; log_filename_global = malloc(len); if (log_filename_global == NULL) { return NC_ERROR; } nc_cpystrn((u_char *) log_filename_global, (u_char *) optarg, len); break; case 'c': env->conf_filename = optarg; len = nc_strlen(optarg) + 1; conf_filename_global = malloc(len); if (conf_filename_global == NULL) { return NC_ERROR; } nc_cpystrn((u_char *) conf_filename_global, (u_char *) optarg, len); break; case 's': value = nc_atoi(optarg, strlen(optarg)); if (value < 0) { log_stderr("nutcracker: option -s requires a number"); return NC_ERROR; } if (!nc_valid_port(value)) { log_stderr("nutcracker: option -s value %d is not a valid " "port", value); return NC_ERROR; } env->stats_port = (uint16_t)value; break; case 'i': value = nc_atoi(optarg, strlen(optarg)); if (value < 0) { log_stderr("nutcracker: option -i requires a number"); return NC_ERROR; } env->stats_interval = value; break; case 'a': env->stats_addr = optarg; break; case 'p': env->pid_filename = optarg; break; case 'm': value = nc_atoi(optarg, strlen(optarg)); if (value <= 0) { log_stderr("nutcracker: option -m requires a non-zero number"); return NC_ERROR; } if (value < NC_MBUF_MIN_SIZE || value > NC_MBUF_MAX_SIZE) { log_stderr("nutcracker: mbuf chunk size must be between %zu and" \ " %zu bytes", NC_MBUF_MIN_SIZE, NC_MBUF_MAX_SIZE); return NC_ERROR; } env->mbuf_chunk_size = (size_t)value; break; case 'n': value = nc_atoi(optarg, strlen(optarg)); if (value <= 0) { log_stderr("nutcracker: option -n requires a non-zero number"); return NC_ERROR; } cores = sysconf(_SC_NPROCESSORS_ONLN); if (value > cores || value < 1) { log_stderr("bilitw: bilitw worker process number should be between %d and" \ " %d", 1, cores); return NC_ERROR; } env->worker_processes= value; break; case 'M': value = nc_atoi(optarg, strlen(optarg)); if (value <= 0) { log_stderr("nutcracker: option -M requires a non-zero number"); return NC_ERROR; } cores = sysconf(_SC_NPROCESSORS_ONLN); cores = (1<<cores) -1; if (value > cores || value < 1) { log_stderr("bilitw: bilitw worker process cpu mask should be set between %d and" \ " %d", 1, cores); return NC_ERROR; } env->cpu_mask = value; break; case '?': switch (optopt) { case 'o': case 'c': case 'p': log_stderr("nutcracker: option -%c requires a file name", optopt); break; case 'm': case 'v': case 's': case 'i': case 'n': case 'M': log_stderr("nutcracker: option -%c requires a number", optopt); break; case 'a': log_stderr("nutcracker: option -%c requires a string", optopt); break; default: log_stderr("nutcracker: invalid option -- '%c'", optopt); break; } return NC_ERROR; default: log_stderr("nutcracker: invalid option -- '%c'", optopt); return NC_ERROR; } } return NC_OK; }