void cetcd_client_init(cetcd_client *cli, cetcd_array *addresses) { curl_global_init(CURL_GLOBAL_ALL); srand(time(0)); cli->keys_space = "v2/keys"; cli->stat_space = "v2/stat"; cli->member_space = "v2/members"; cli->curl = curl_easy_init(); cli->addresses = cetcd_array_shuffle(addresses); cli->picked = rand() % (cetcd_array_size(cli->addresses)); cli->settings.verbose = 0; cli->settings.connect_timeout = 1; cli->settings.read_timeout = 1; /*not used now*/ cli->settings.write_timeout = 1; /*not used now*/ cetcd_array_init(&cli->watchers, 10); #if LIBCURL_VERSION_NUM >= 0x071900 curl_easy_setopt(cli->curl, CURLOPT_TCP_KEEPALIVE, 1L); curl_easy_setopt(cli->curl, CURLOPT_TCP_KEEPINTVL, 1L); /*the same as go-etcd*/ #endif curl_easy_setopt(cli->curl, CURLOPT_USERAGENT, "cetcd"); curl_easy_setopt(cli->curl, CURLOPT_POSTREDIR, 3L); /*post after redirecting*/ }
int main(int argc, char *argv[]) { cetcd_client cli; cetcd_response *resp; cetcd_array addrs; cetcd_array_init(&addrs, 3); cetcd_array_append(&addrs, "http://127.0.0.1:2379"); cetcd_client_init(&cli, &addrs); resp = cetcd_get(&cli, "/radar/service"); if(resp->err) { printf("error :%d, %s (%s)\n", resp->err->ecode, resp->err->message, resp->err->cause); } cetcd_response_print(resp); cetcd_response_release(resp); cetcd_array_destroy(&addrs); cetcd_client_destroy(&cli); return 0; }
void cetcd_client_init(cetcd_client *cli, cetcd_array *addresses) { size_t i; cetcd_array *addrs; curl_global_init(CURL_GLOBAL_ALL); srand(time(0)); cli->keys_space = "v2/keys"; cli->stat_space = "v2/stat"; cli->member_space = "v2/members"; cli->curl = curl_easy_init(); addrs = cetcd_array_create(cetcd_array_size(addresses)); for (i=0; i<cetcd_array_size(addresses); ++i) { cetcd_array_append(addrs, sdsnew(cetcd_array_get(addresses, i))); } cli->addresses = cetcd_array_shuffle(addrs); cli->picked = rand() % (cetcd_array_size(cli->addresses)); cli->settings.verbose = 0; cli->settings.connect_timeout = 1; cli->settings.read_timeout = 1; /*not used now*/ cli->settings.write_timeout = 1; /*not used now*/ cetcd_array_init(&cli->watchers, 10); /* Set CURLOPT_NOSIGNAL to 1 to work around the libcurl bug: * http://stackoverflow.com/questions/9191668/error-longjmp-causes-uninitialized-stack-frame * http://curl.haxx.se/mail/lib-2008-09/0197.html * */ curl_easy_setopt(cli->curl, CURLOPT_NOSIGNAL, 1L); #if LIBCURL_VERSION_NUM >= 0x071900 curl_easy_setopt(cli->curl, CURLOPT_TCP_KEEPALIVE, 1L); curl_easy_setopt(cli->curl, CURLOPT_TCP_KEEPINTVL, 1L); /*the same as go-etcd*/ #endif curl_easy_setopt(cli->curl, CURLOPT_USERAGENT, "cetcd"); curl_easy_setopt(cli->curl, CURLOPT_POSTREDIR, 3L); /*post after redirecting*/ }
size_t cetcd_parse_response(char *ptr, size_t size, size_t nmemb, void *userdata) { int len, i; char *key, *val; cetcd_response *resp; cetcd_response_parser *parser; yajl_status status; enum resp_parser_st { request_line_start_st, request_line_end_st, request_line_http_status_start_st, request_line_http_status_st, request_line_http_status_end_st, header_key_start_st, header_key_st, header_key_end_st, header_val_start_st, header_val_st, header_val_end_st, blank_line_st, json_start_st, json_end_st, response_discard_st }; /* Headers we are interested in: * X-Etcd-Index: 14695 * X-Raft-Index: 672930 * X-Raft-Term: 12 * */ parser = userdata; resp = parser->resp; len = size * nmemb; for (i = 0; i < len; ++i) { if (parser->st == request_line_start_st) { if (ptr[i] == ' ') { parser->st = request_line_http_status_start_st; } continue; } if (parser->st == request_line_end_st) { if (ptr[i] == '\n') { parser->st = header_key_start_st; } continue; } if (parser->st == request_line_http_status_start_st) { parser->buf = sdscatlen(parser->buf, ptr+i, 1); parser->st = request_line_http_status_st; continue; } if (parser->st == request_line_http_status_st) { if (ptr[i] == ' ') { parser->st = request_line_http_status_end_st; } else { parser->buf = sdscatlen(parser->buf, ptr+i, 1); continue; } } if (parser->st == request_line_http_status_end_st) { val = parser->buf; parser->http_status = atoi(val); sdsclear(parser->buf); parser->st = request_line_end_st; continue; } if (parser->st == header_key_start_st) { if (ptr[i] == '\r') { ++i; } if (ptr[i] == '\n') { parser->st = blank_line_st; if (parser->http_status >= 300 && parser->http_status < 400) { /*this is a redirection, restart the state machine*/ parser->st = request_line_start_st; break; } continue; } parser->st = header_key_st; } if (parser->st == header_key_st) { parser->buf = sdscatlen(parser->buf, ptr+i, 1); if (ptr[i] == ':') { parser->st = header_key_end_st; } else { continue; } } if (parser->st == header_key_end_st) { parser->st = header_val_start_st; continue; } if (parser->st == header_val_start_st) { if (ptr[i] == ' ') { continue; } parser->st = header_val_st; } if (parser->st == header_val_st) { if (ptr[i] == '\r') { ++i; } if (ptr[i] == '\n') { parser->st = header_val_end_st; } else { parser->buf = sdscatlen(parser->buf, ptr+i, 1); continue; } } if (parser->st == header_val_end_st) { parser->st = header_key_start_st; int count = 0; sds *kvs = sdssplitlen(parser->buf, sdslen(parser->buf), ":", 1, &count); sdsclear(parser->buf); if (count < 2) { sdsfreesplitres(kvs, count); continue; } key = kvs[0]; val = kvs[1]; if (strncmp(key, "X-Etcd-Index", sizeof("X-Etcd-Index")-1) == 0) { resp->etcd_index = atoi(val); } else if (strncmp(key, "X-Raft-Index", sizeof("X-Raft-Index")-1) == 0) { resp->raft_index = atoi(val); } else if (strncmp(key, "X-Raft-Term", sizeof("X-Raft-Term")-1) == 0) { resp->raft_term = atoi(val); } sdsfreesplitres(kvs, count); continue; } if (parser->st == blank_line_st) { if (ptr[i] != '{') { /*not a json response, discard*/ parser->st = response_discard_st; if (resp->err == NULL) { resp->err = calloc(1, sizeof(cetcd_error)); resp->err->ecode = error_response_parsed_failed; resp->err->message = sdsnew("not a json response"); resp->err->cause = sdsnewlen(ptr, len); } continue; } parser->st = json_start_st; cetcd_array_init(&parser->ctx.keystack, 10); cetcd_array_init(&parser->ctx.nodestack, 10); if (parser->http_status != 200 && parser->http_status != 201) { resp->err = calloc(1, sizeof(cetcd_error)); parser->ctx.userdata = resp->err; parser->json = yajl_alloc(&error_callbacks, 0, &parser->ctx); } else { parser->ctx.userdata = resp; parser->json = yajl_alloc(&callbacks, 0, &parser->ctx); } } if (parser->st == json_start_st) { if (yajl_status_ok != yajl_parse(parser->json, (const unsigned char *)ptr + i, len - i)) { parser->st = json_end_st; } else { parser->st = response_discard_st; yajl_free(parser->json); cetcd_array_destory(&parser->ctx.keystack); cetcd_array_destory(&parser->ctx.nodestack); } } if (parser->st == json_end_st) { status = yajl_complete_parse(parser->json); yajl_free(parser->json); cetcd_array_destory(&parser->ctx.keystack); cetcd_array_destory(&parser->ctx.nodestack); /*parse failed, TODO set error message*/ if (status != yajl_status_ok) { if (resp->err == NULL) { resp->err = calloc(1, sizeof(cetcd_error)); resp->err->ecode = error_response_parsed_failed; resp->err->message = sdsnew("http response is invalid json format"); resp->err->cause = sdsnewlen(ptr, len); } return 0; } break; } if (parser->st == response_discard_st) { return len; } } return len; }