/
daemon.c
148 lines (120 loc) · 3.11 KB
/
daemon.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
#include <string.h>
#include <stdint.h>
#include <stdlib.h>
#include <re.h>
#include "app.h"
#ifdef DSTUD_VERSION
static char *version = DSTUD_VERSION;
#else
static char *version = NULL;
#endif
struct httpd {
struct http_sock *hsp;
};
static void signal_handler(int sig)
{
re_printf("terminating on signal %d...\n", sig);
re_cancel();
}
static unsigned int str_ver(char *version) {
int shift = 24;
unsigned int ret = 0;
struct pl ver;
char *part = version;
while(*version) {
if(*version == '.') {
ver.p = part;
ver.l = version - part;
ret |= pl_u32(&ver) << shift;
shift -= 8;
part = version+1;
}
version ++;
}
ver.p = part;
ver.l = version - part;
ret |= pl_u32(&ver) << shift;
part = version+1;
return ret;
};
int version_cmp(char *have, const struct pl *want_pl) {
char *hdr = NULL, *want = NULL;
unsigned int uhave, uwant;
if(pl_strdup(&hdr, want_pl)) {
return -1;
}
if(strncmp(hdr, "Version=", sizeof("Version=")-1)) {
return -1;
}
want = hdr + sizeof("Version=")-1;
uhave = str_ver(have);
uwant = str_ver(want);
out:
mem_deref(hdr);
return uhave - uwant;
};
void http_request_h(struct http_conn *conn, const struct http_msg *msg, void *arg)
{
int err;
enum app_cmd cmd;
const struct http_hdr * expect_hdr;
struct mbuf *mb = msg->mb;
uint8_t *ret_buf;
size_t ret_len;
if(pl_strcmp(&msg->met, "POST")) {
http_creply(conn, 405, "Method not allowed", "text/plain", "EMET");
return;
}
expect_hdr = http_msg_hdr(msg, HTTP_HDR_EXPECT);
if(expect_hdr != NULL && version_cmp(version, &expect_hdr->val) < 0) {
http_creply(conn, 417, "Expectation Failed", "text/plain", "%s", version);
return;
}
cmd = (enum app_cmd)(hash_joaat_ci(msg->path.p, msg->path.l) & 0xfff);
err = app_handle(cmd, mbuf_buf(mb), mbuf_get_left(mb), &ret_buf, &ret_len);
if(err < 0) {
http_creply(conn, 500, "Internal Server Error", "text/plain", "EINT");
return;
}
if(err > 200) {
http_creply(conn, err, "Error", "text/plain", "NO", 2);
return;
}
if(err == 0) {
http_creply(conn, 200, "OK", "text/plain; charset=utf-8", "%b", ret_buf, ret_len);
} else {
http_creply(conn, 403, "Forbidden", "text/plain", "%b", ret_buf, ret_len);
}
free(ret_buf);
}
int prepare(struct httpd *httpd, const char *to_bind) {
int err;
struct sa local_addr;
err = sa_decode(&local_addr, to_bind, strlen(to_bind));
if(err != 0)
return err;
err = http_listen(&httpd->hsp, &local_addr, http_request_h, httpd);
return err;
}
int main(int argc, char *argv[])
{
int err;
struct httpd httpd;
char *bind;
err = libre_init();
if(err != 0) {
goto out;
}
if(argc == 1) {
bind = "127.0.0.1:8013";
} else {
bind = argv[1];
}
err = prepare(&httpd, bind);
err = app_init();
if(err != 0)
goto out;
err = re_main(signal_handler);
out:
return err;
}