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