#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 fork_parent_process(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 fork_child_process(struct evhttp_request *req, void *arg)
{
if(evhttp_request_get_command(req) != EVHTTP_REQ_POST)
{
log_error("jsonrpc_request_cb EVHTTP_REQ_POST failed");
goto EndP;
}
exit(EXIT_SUCCESS);
EndP:
exit(EXIT_FAILURE);
}
static void jsonrpc_request_cb(struct evhttp_request *req, void *arg)
{
pid_t pid = fork();
switch(pid)
{
case -1:
log_error("fork child pid failed: %s", strerror(errno));
break;
case 0:
log_info("fork child pid succeed: %d", getpid());
fork_child_process(req, arg);
break;
default:
log_info("fork parent pid succeed: %d", getpid());
fork_parent_process(req, arg);
break;
}
}
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 chld_evsignal_cb(evutil_socket_t fd, short event, void *arg)
{
int status = -1;
pid_t pid = -1;
log_info("chld signal: %d", SIGCHLD);
do{
pid = waitpid(-1, &status, WNOHANG);
switch(pid)
{
case -1:
if(errno == EINTR)
continue;
if(errno != ECHILD)
log_error("wait child failed \"%d: %s\"", errno, strerror(errno));
break;
case 0:
log_info("child still running");
break;
default:
log_info("wait child succeed: \"%d\"", pid);
break;
}
}while(pid >= 0);
}
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_chld;
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_chld, base, SIGCHLD, EV_SIGNAL|EV_PERSIST, chld_evsignal_cb, (void *)&signal_chld);
if(ret != 0)
{
log_error("evsignal_assign failed: %s", strerror(errno));
goto ErrP;
}
event_add(&signal_chld, 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", 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;
}
关于libevent+http服务端的一个样例
最新推荐文章于 2024-07-20 09:04:42 发布