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

#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)
#endif

typedef 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 0
	if(argc != 2)
	{
		log_error("Usage: %s URL", argv[0]);
		return -1;
	}
#endif

	signals_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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值