summaryrefslogtreecommitdiff
path: root/opentracker.c
diff options
context:
space:
mode:
Diffstat (limited to 'opentracker.c')
-rw-r--r--opentracker.c143
1 files changed, 4 insertions, 139 deletions
diff --git a/opentracker.c b/opentracker.c
index b47759e..2eaf988 100644
--- a/opentracker.c
+++ b/opentracker.c
@@ -35,6 +35,7 @@
35#include "ot_fdstate.h" 35#include "ot_fdstate.h"
36#include "ot_socket.h" 36#include "ot_socket.h"
37#include "ot_stats.h" 37#include "ot_stats.h"
38#include "ot_tcp.h"
38#include "ot_udp.h" 39#include "ot_udp.h"
39#include "trackerlogic.h" 40#include "trackerlogic.h"
40 41
@@ -96,142 +97,6 @@ static void install_signal_handlers(void) {
96} 97}
97 98
98 99
99static ssize_t header_complete(char *request, ssize_t byte_count) {
100 ssize_t i = 0, state = 0;
101
102 for (i = 1; i < byte_count; i += 2)
103 if (request[i] <= 13) {
104 i--;
105 for (state = 0; i < byte_count; ++i) {
106 char c = request[i];
107 if (c == '\r' || c == '\n')
108 state = (state >> 2) | ((c << 6) & 0xc0);
109 else
110 break;
111 if (state >= 0xa0 || state == 0x99)
112 return i + 1;
113 }
114 }
115 return 0;
116}
117
118static void handle_read(const int64_t sock, struct ot_workstruct *ws) {
119 struct http_data *cookie = fdstate_cookie(sock);
120 ssize_t byte_count = read((int)sock, ws->inbuf, G_INBUF_SIZE);
121
122 if (byte_count == 0 || (byte_count == -1 && errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR)) {
123 http_close(sock);
124 return;
125 }
126
127 if (byte_count == -1)
128 return;
129
130 ws->request = NULL;
131 ws->request_size = 0;
132 ws->header_size = 0;
133 ws->keep_alive = 0;
134
135 /* If we get the whole request in one packet, handle it without copying */
136 if (!cookie->request.data) {
137 if ((ws->header_size = header_complete(ws->inbuf, byte_count))) {
138 ws->request = ws->inbuf;
139 ws->request_size = byte_count;
140 http_handle_request(sock, ws);
141 } else if (buf_cat(&cookie->request, ws->inbuf, (size_t)byte_count))
142 http_close(sock);
143 return;
144 }
145
146 if (buf_cat(&cookie->request, ws->inbuf, (size_t)byte_count) || cookie->request.size > G_INBUF_SIZE) {
147 http_issue_error(sock, ws, CODE_HTTPERROR_500);
148 return;
149 }
150
151 while ((ws->header_size = header_complete(cookie->request.data, (ssize_t)cookie->request.size))) {
152 ws->request = cookie->request.data;
153 ws->request_size = (ssize_t)cookie->request.size;
154 http_handle_request(sock, ws);
155#ifdef WANT_KEEPALIVE
156 if (!ws->keep_alive)
157#endif
158 return;
159 }
160}
161
162static void handle_write(const int64_t sock) {
163 struct http_data *cookie = fdstate_cookie(sock);
164 int chunked = 0;
165 int keep_alive = 0;
166
167 if (cookie) {
168 chunked = (cookie->flag & STRUCT_HTTP_FLAG_CHUNKED_IN_TRANSFER) != 0;
169 keep_alive = (cookie->flag & STRUCT_HTTP_FLAG_KEEPALIVE) != 0;
170
171 if (cookie->batch) {
172 if (batch_send(sock, cookie->batch) == BATCH_FAILED) {
173 http_close(sock);
174 return;
175 }
176 if (batch_pending(cookie->batch))
177 return;
178 }
179 }
180
181 /* In a chunked transfer, wait for the next piece once everything queued has gone out */
182 if (chunked)
183 http_interest_set(sock, cookie, 0);
184 else if (keep_alive) {
185 /* The reply is out and the client asked to keep the connection, so go
186 back to waiting for the next request */
187 http_interest_set(sock, cookie, EVENT_IN);
188 fdstate_set_expiry(sock, time_future_seconds(OT_CLIENT_TIMEOUT));
189 } else
190 http_close(sock);
191}
192
193/* The fast path, assuming that the complete request has usually arrived by the time a
194 connection is accepted, so it is answered here outside the event loop. The more load
195 a tracker has, the more likely it is that by the time it accepts, the roundtrip to
196 the peer has completed.
197 If the request could not be completely handled, the stack cookie is promoted to heap
198 and the connection handed over to the event loop to finish */
199static void handle_accept(const int64_t serversocket, struct ot_workstruct *ws) {
200 int64_t sock;
201 ot_ip6 ip;
202 uint16_t port;
203
204 while ((sock = socket_accept(serversocket, ip, &port)) != -1) {
205 struct http_data cookie;
206 uint32_t generation;
207
208 memset(&cookie, 0, sizeof(cookie));
209 memcpy(cookie.ip, ip, sizeof(ot_ip6));
210 cookie.interest = EVENT_IN;
211 cookie.flag = STRUCT_HTTP_FLAG_ONSTACK;
212
213 generation = fdstate_open(sock, &cookie, time_future_seconds(OT_CLIENT_TIMEOUT));
214 if (!fdstate_claim((int)sock, generation)) {
215 fdstate_close(sock);
216 event_close((int)sock);
217 continue;
218 }
219
220 stats_issue_event(ws, EVENT_ACCEPT, FLAG_TCP, (uintptr_t)ip);
221
222 handle_read(sock, ws);
223
224 /* Gone already if it was answered and closed inline */
225 if (fdstate_generation((int)sock) != generation)
226 continue;
227
228 if (http_adopt(sock, &cookie) == -1)
229 http_close(sock);
230 else
231 fdstate_release((int)sock);
232 }
233}
234
235/* How many ready descriptors one wait hands back at a time */ 100/* How many ready descriptors one wait hands back at a time */
236#define OT_EVENT_BATCH 512 101#define OT_EVENT_BATCH 512
237 102
@@ -277,7 +142,7 @@ static void *server_mainloop(void *args) {
277 cookie = fdstate_cookie((int)sock); 142 cookie = fdstate_cookie((int)sock);
278 143
279 if ((intptr_t)cookie == FLAG_TCP) 144 if ((intptr_t)cookie == FLAG_TCP)
280 handle_accept(sock, &ws); 145 tcp_accept(sock, &ws);
281 else if ((intptr_t)cookie == FLAG_UDP) 146 else if ((intptr_t)cookie == FLAG_UDP)
282 handle_udp6(sock, &ws); 147 handle_udp6(sock, &ws);
283 else if ((intptr_t)cookie == FLAG_SELFPIPE) 148 else if ((intptr_t)cookie == FLAG_SELFPIPE)
@@ -285,10 +150,10 @@ static void *server_mainloop(void *args) {
285 ; 150 ;
286 else { 151 else {
287 if (ready[i].what & EVENT_IN) 152 if (ready[i].what & EVENT_IN)
288 handle_read(sock, &ws); 153 tcp_read(sock, &ws);
289 /* The read may have closed it, so look again before writing */ 154 /* The read may have closed it, so look again before writing */
290 if ((ready[i].what & EVENT_OUT) && fdstate_generation((int)sock) == ready[i].generation) 155 if ((ready[i].what & EVENT_OUT) && fdstate_generation((int)sock) == ready[i].generation)
291 handle_write(sock); 156 tcp_write(sock);
292 } 157 }
293 } 158 }
294 159