HTTP客户端(libcurl) & HTTP服务端(libevent)

来源:互联网 发布:开淘宝店邮费 编辑:程序博客网 时间:2024/04/30 05:37
#include <ctype.h>#include <stdio.h>#include <stdlib.h>#include <errno.h>#include <string.h>#include <stdint.h>#include <stdbool.h>#include <libgen.h>#include <sys/types.h>#include <sys/time.h>#include <signal.h>#include <unistd.h>#include <fcntl.h>#include <jansson.h>#include <curl/curl.h>#include "log.h"#ifndef likely#define likely(x) __builtin_expect(!!(x), 1)#endif#ifndef unlikely#define unlikely(x) __builtin_expect(!!(x), 0)#endiftypedef struct data_t{    unsigned char *value;    unsigned int length;}data_t;static volatile sig_atomic_t isterm = 0;   // 结束信号static volatile sig_atomic_t isalarm = 0;  // 时钟信号// 中断后的信号处理函数static void signals_handler(int sig, siginfo_t *si, void *context){static siginfo_t empty_siginfo;if(!si) si = &empty_siginfo;switch(sig){case SIGINT: case SIGTERM:isterm = sig;break;case SIGPIPE:break;case SIGALRM: isalarm = sig;break;default:break;}}// 注册信号中断static void signals_register(){struct sigaction act;struct itimerval interval;sigfillset(&act.sa_mask);sigdelset(&act.sa_mask, SIGINT);sigdelset(&act.sa_mask, SIGTERM);sigdelset(&act.sa_mask, SIGPIPE);sigdelset(&act.sa_mask, SIGALRM);sigprocmask(SIG_SETMASK, &act.sa_mask, NULL);act.sa_flags = SA_SIGINFO;act.sa_sigaction = signals_handler;interval.it_interval.tv_sec = 1;interval.it_interval.tv_usec = 0;interval.it_value.tv_sec = 1;interval.it_value.tv_usec = 0;sigaction(SIGINT, &act, NULL);sigaction(SIGTERM, &act, NULL);sigaction(SIGPIPE, &act, NULL);sigaction(SIGALRM, &act, NULL);setitimer(ITIMER_REAL, &interval, NULL);}static size_t recv_head_callback(char *ptr, size_t size, size_t nmemb, void *userdata){    data_t *recv_head = (data_t*)userdata;    unsigned int append = size*nmemb;    recv_head->value = (unsigned char*)realloc(recv_head->value, recv_head->length+append+1);    if(!recv_head->value)        return -1;    memcpy(recv_head->value+recv_head->length, ptr, append);    recv_head->length += append;    recv_head->value[recv_head->length] = 0;    log_debug("recv http response head: %s", recv_head->value);    return size*nmemb;}static size_t recv_body_callback(char *ptr, size_t size, size_t nmemb, void *userdata){    data_t *recv_body = (data_t*)userdata;unsigned int append = size*nmemb;    recv_body->value = (unsigned char*)realloc(recv_body->value, recv_body->length+append+1);    if(!recv_body->value)        return -1;    memcpy(recv_body->value+recv_body->length, ptr, append);    recv_body->length += append;recv_body->value[recv_body->length] = 0;    log_debug("recv http response body: %s", recv_body->value);    return size*nmemb;}static int jsonrpc_request_url(char *url){    CURL *curl = NULL;    CURLcode rcode;    struct curl_slist *headers = NULL;    json_t *json_req = NULL;    json_t *json_res = NULL;    data_t send_body, recv_head, recv_body;    memset(&send_body, 0, sizeof(data_t));    memset(&recv_head, 0, sizeof(data_t));    memset(&recv_body, 0, sizeof(data_t));    rcode = curl_global_init(CURL_GLOBAL_ALL);    if(rcode != CURLE_OK)    {        log_error("curl global init failed: %s", curl_easy_strerror(rcode));        return -1;    }    curl = curl_easy_init();    if(!curl)    {        log_error("curl easy init failed: %s", curl_easy_strerror(rcode));        goto ErrP;    }    json_req = json_pack("{ s:s, s:s, s:s }", "jsonrpc", "2.0", "method", "jsonrpc", "id", "1");    if(json_req == NULL)    {        log_error("json pack http request body failed");        goto ErrP;    }    send_body.value = (unsigned char *)json_dumps(json_req, 0);    send_body.length = strlen((const char *)send_body.value);    curl_easy_setopt(curl, CURLOPT_URL, url);    curl_easy_setopt(curl, CURLOPT_POST, 1L);    curl_easy_setopt(curl, CURLOPT_POSTFIELDS, send_body.value);    curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, send_body.length);    curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_DIGEST|CURLAUTH_BASIC);    curl_easy_setopt(curl, CURLOPT_USERPWD, "admin:111111");    curl_easy_setopt(curl, CURLOPT_COOKIE, "tool=curl; fun=yes;");    curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);    curl_easy_setopt(curl, CURLOPT_TIMEOUT, 3L);    curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1L);    curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);    headers = curl_slist_append(headers, "Accept: text/json");    headers = curl_slist_append(headers, "Content-Type: text/json; charset=UTF-8");    headers = curl_slist_append(headers, "Connection: keep-alive");    curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);    curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, recv_head_callback);    curl_easy_setopt(curl, CURLOPT_HEADERDATA, &recv_head);    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, recv_body_callback);    curl_easy_setopt(curl, CURLOPT_WRITEDATA, &recv_body);    rcode = curl_easy_perform(curl);    if(rcode != CURLE_OK)    {        log_error("curl easy perform failed: %s", curl_easy_strerror(rcode));        goto ErrP;    }    unsigned int code = 200;    rcode = curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &code);    if(rcode != CURLE_OK || code != 200)    {        log_error("Response-Code: %d", code);        goto ErrP;    }    unsigned char *ct;    rcode = curl_easy_getinfo(curl, CURLINFO_CONTENT_TYPE, &ct);    if(rcode == CURLE_OK)    {        log_debug("Content-Type: %s", ct);    }    json_res = json_loadb((const char *)(recv_body.value), recv_body.length, 0, NULL);    if(json_res == NULL)    {        log_error("json unpack http response body failed");        goto ErrP;    }    json_t *json_result = json_object_get(json_res, "result");    char *buf_result = (char*)json_string_value(json_result);    if(!json_result || !buf_result || strncasecmp(buf_result, "succeed", 7))    {        log_error("jsonrpc request url result failed");        goto ErrP;    }    log_info("jsonrpc request url result succeed");        if(send_body.value) free(send_body.value);    if(json_req) json_decref(json_req);    if(recv_head.value) free(recv_head.value);    if(recv_body.value) free(recv_body.value);    if(json_res) json_decref(json_res);    if(headers) curl_slist_free_all(headers);    if(curl) curl_easy_cleanup(curl);    curl_global_cleanup();    return 0;ErrP:    if(send_body.value) free(send_body.value);    if(json_req) json_decref(json_req);    if(recv_head.value) free(recv_head.value);    if(recv_body.value) free(recv_body.value);    if(json_res) json_decref(json_res);    if(headers) curl_slist_free_all(headers);    if(curl) curl_easy_cleanup(curl);    curl_global_cleanup();    return -1;}int main(int argc, char *argv[]){int ret = 0;    log_open(basename(argv[0]), 1);#if 0if(argc != 2){log_error("Usage: %s URL", argv[0]);return -1;}#endifsignals_register();while(!isterm){if(unlikely(isterm)){log_info("term signal: %d", isterm);isterm = 0;}if(likely(isalarm)){log_info("alarm signal: %d", isalarm);isalarm = 0;        ret = jsonrpc_request_url(argv[1] ? argv[1] : "http://127.0.0.1:1990/jsonrpc.php");        if(ret != 0)        {        log_error("jsonrpc request url failed: %d", ret);        break;        }            }sleep(-1);}log_close();return ret;}

#include <sys/wait.h>#include <sys/types.h>#include <unistd.h>#include <stdio.h>#include <stdlib.h>#include <errno.h>#include <string.h>#include <stdint.h>#include <stdbool.h>#include <libgen.h>#include <signal.h>#include <event.h>#include <evhttp.h>#include <event2/event.h>#include <event2/thread.h>#include <event2/buffer.h>#include <event2/bufferevent.h>#include <event2/util.h>#include <event2/dns.h>#include <event2/http.h>#include <event2/rpc.h>#include <jansson.h>#include "log.h"static void jsonrpc_request_cb(struct evhttp_request *req, void *arg){struct evkeyvalq *headers = NULL;struct evkeyval *header = NULL;struct evbuffer *req_evb = NULL;struct evbuffer *res_evb = NULL;int ret = 0;int req_len = 0;char *req_buf = NULL;char *res_buf = NULL;json_t *req_json = NULL;json_t *res_json = NULL;if(evhttp_request_get_command(req) != EVHTTP_REQ_POST){log_error("jsonrpc_request_cb EVHTTP_REQ_POST failed");goto EndP;}headers = evhttp_request_get_input_headers(req);for (header = headers->tqh_first; header; header = header->next.tqe_next)log_debug("%s: %s", header->key, header->value);req_evb = evhttp_request_get_input_buffer(req);req_len = evbuffer_get_length(req_evb);req_buf = (char*)malloc(req_len+1);if(!req_buf){log_error("malloc failed");goto EndP;}memset(req_buf, 0, req_len+1);ret = evbuffer_remove(req_evb, req_buf, req_len);if(ret != req_len){log_error("evbuffer_copyout failed");goto EndP;}req_buf[req_len] = 0;log_info("Request: %s", req_buf);req_json = json_loadb((const char *)req_buf, req_len, 0, NULL);    if(!req_json)    {        log_error("jsonrpc_request_cb json_loadb failed: %s", strerror(errno));        goto EndP;    }    json_t *method_json = json_object_get(req_json, "method");    char *method_buf = (char*)json_string_value(method_json);    if(!method_json || !method_buf || strncasecmp(method_buf, "jsonrpc", 7))    {    log_error("jsonrpc_request_cb method failed");        goto EndP;    }evhttp_add_header(evhttp_request_get_output_headers(req), "Content-Type", "text/json; charset=UTF-8");evhttp_add_header(evhttp_request_get_output_headers(req), "Connection", "keep-alive");res_json = json_pack("{ s:s, s:s, s:s }", "jsonrpc", "2.0", "result", "succeed", "id", "1");if(!res_json){log_error("jsonrpc_request_cb json_pack failed: %s", strerror(errno));goto EndP;}res_buf = json_dumps(res_json, 0);if(!res_buf){log_error("jsonrpc_request_cb json_dunmps failed: %s", strerror(errno));goto EndP;}res_evb = evbuffer_new();if(!res_evb){log_error("jsonrpc_request_cb evbuffer_new failed: %s", strerror(errno));goto EndP;}evbuffer_add_printf(res_evb, "%s", res_buf);log_info("Response: %s", res_buf);evhttp_send_reply(req, HTTP_OK, "OK", res_evb);if(res_evb) evbuffer_free(res_evb);if(res_buf) free(res_buf);if(res_json) json_decref(res_json);if(req_json) json_decref(req_json);if(req_buf) free(req_buf);return;EndP:evhttp_send_error(req, HTTP_BADMETHOD, "BAD METHOD");if(res_evb) evbuffer_free(res_evb);if(res_buf) free(res_buf);if(res_json) json_decref(res_json);if(req_json) json_decref(req_json);if(req_buf) free(req_buf);return;}static void default_request_cb(struct evhttp_request *req, void *arg){evhttp_add_header(evhttp_request_get_output_headers(req), "Content-Type", "text/plain; charset=UTF-8");evhttp_add_header(evhttp_request_get_output_headers(req), "Connection", "close");evhttp_send_error(req, HTTP_NOTFOUND, "NOT FOUND");}static void term_evsignal_cb(evutil_socket_t fd, short event, void *arg){struct event_base *base = arg;struct timeval tv = { 1, 0 };log_info("term signal: %d", SIGINT);event_base_loopexit(base, &tv);}static void alrm_evsignal_cb(evutil_socket_t fd, short event, void *arg){//struct event *signal_alrm = arg;log_info("alrm signal: %d", SIGALRM);//event_del(signal_alrm);}static void cycle_timout_cb(evutil_socket_t fd, short event, void *arg){struct timeval tv = {1, 0};log_info("cycle timeout callback");event_add(*(struct event**)arg, &tv);}int main(int argc, char *argv[]){int ret = 0;char *server_ip = "0.0.0.0";unsigned short server_port = 1990;struct event_base *base = NULL;struct evhttp *http = NULL;struct evhttp_bound_socket *handle = NULL;evutil_socket_t server_fd = -1;struct event *timeout = NULL;struct event *signal_int = NULL;struct event signal_alrm;log_open(basename(argv[0]), 1);base = event_base_new();if(!base){log_error("event_base_new failed: %s", strerror(errno));goto ErrP;}struct timeval tv = {1, 0};timeout = event_new(base, -1, 0, cycle_timout_cb, (void*)&timeout);if(!timeout){log_error("evtimer_new failed: %s", strerror(errno));goto ErrP;}event_add(timeout, &tv);signal_int = event_new(base, SIGINT, EV_SIGNAL|EV_PERSIST, term_evsignal_cb, (void *)base);if(!signal_int){log_error("evsignal_new failed: %s", strerror(errno));goto ErrP;}event_add(signal_int, NULL);ret = event_assign(&signal_alrm, base, SIGALRM, EV_SIGNAL|EV_PERSIST, alrm_evsignal_cb, (void *)&signal_alrm);if(ret != 0){log_error("evsignal_assign failed: %s", strerror(errno));goto ErrP;}event_add(&signal_alrm, NULL);http = evhttp_new(base);if(!http){log_error("evhttp_new failed: %s", strerror(errno));goto ErrP;}handle = evhttp_bind_socket_with_handle(http, server_ip, server_port);if(!handle){log_error("evhttp_bind_socket_with_handle failed: %s", strerror(errno));goto ErrP;}server_fd = evhttp_bound_socket_get_fd(handle);log_info("evhttp_bind_socket_with_handle succeed: %d", server_fd);evhttp_set_timeout(http, 120);evhttp_set_cb(http, "/jsonrpc.php", jsonrpc_request_cb, &base);evhttp_set_gencb(http, default_request_cb, &base);event_base_dispatch(base);if(http) evhttp_free(http);if(signal_int) event_free(signal_int);if(timeout) event_free(timeout);if(base) event_base_free(base);log_close();return 0;ErrP:if(http) evhttp_free(http);if(signal_int) event_free(signal_int);if(timeout) event_free(timeout);if(base) event_base_free(base);log_close();return -1;}

0 0