BadVPN – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 /**
2 * @file NCDRequestClient.c
3 * @author Ambroz Bizjak <ambrop7@gmail.com>
4 *
5 * @section LICENSE
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of the author nor the
15 * names of its contributors may be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29  
30 #include <stdlib.h>
31 #include <stddef.h>
32 #include <stdint.h>
33 #include <limits.h>
34 #include <inttypes.h>
35 #include <string.h>
36  
37 #include <misc/byteorder.h>
38 #include <misc/expstring.h>
39 #include <misc/offset.h>
40 #include <misc/compare.h>
41 #include <protocol/packetproto.h>
42 #include <protocol/requestproto.h>
43 #include <base/BLog.h>
44  
45 #include "NCDRequestClient.h"
46  
47 #include <generated/blog_channel_NCDRequestClient.h>
48  
49 #define SEND_PAYLOAD_MTU 32768
50 #define RECV_PAYLOAD_MTU 32768
51  
52 #define SEND_MTU (SEND_PAYLOAD_MTU + sizeof(struct requestproto_header))
53 #define RECV_MTU (RECV_PAYLOAD_MTU + sizeof(struct requestproto_header))
54  
55 #define CSTATE_CONNECTING 1
56 #define CSTATE_CONNECTED 2
57  
58 #define RSTATE_SENDING_REQUEST 1
59 #define RSTATE_READY 2
60 #define RSTATE_SENDING_REQUEST_ABORT 3
61 #define RSTATE_SENDING_ABORT 4
62 #define RSTATE_WAITING_END 5
63 #define RSTATE_DEAD_SENDING 6
64  
65 static int uint32_comparator (void *unused, void *vv1, void *vv2);
66 static void report_error (NCDRequestClient *o);
67 static void request_report_finished (NCDRequestClientRequest *o, int is_error);
68 static void connector_handler (NCDRequestClient *o, int is_error);
69 static void connection_handler (NCDRequestClient *o, int event);
70 static void decoder_handler_error (NCDRequestClient *o);
71 static void recv_if_handler_send (NCDRequestClient *o, uint8_t *data, int data_len);
72 static struct NCDRequestClient_req * find_req (NCDRequestClient *o, uint32_t request_id);
73 static int get_free_request_id (NCDRequestClient *o, uint32_t *out);
74 static int build_requestproto_packet (uint32_t request_id, uint32_t type, NCDValRef payload_value, uint8_t **out_data, int *out_len);
75 static void build_nodata_packet (uint32_t request_id, uint32_t type, uint8_t *data, int *out_len);
76 static int req_is_aborted (struct NCDRequestClient_req *req);
77 static void req_abort (struct NCDRequestClient_req *req);
78 static void req_free (struct NCDRequestClient_req *req);
79 static void req_send_abort (struct NCDRequestClient_req *req);
80 static void req_qflow_send_iface_handler_done (struct NCDRequestClient_req *req);
81  
82 static int uint32_comparator (void *unused, void *vv1, void *vv2)
83 {
84 uint32_t *v1 = vv1;
85 uint32_t *v2 = vv2;
86 return B_COMPARE(*v1, *v2);
87 }
88  
89 static void report_error (NCDRequestClient *o)
90 {
91 ASSERT(!o->is_error)
92  
93 o->is_error = 1;
94 DEBUGERROR(&o->d_err, o->handler_error(o->user))
95 }
96  
97 static void request_report_finished (NCDRequestClientRequest *o, int is_error)
98 {
99 o->req = NULL;
100  
101 DEBUGERROR(&o->d_err, o->handler_finished(o->user, is_error))
102 }
103  
104 static void connector_handler (NCDRequestClient *o, int is_error)
105 {
106 DebugObject_Access(&o->d_obj);
107 DebugError_AssertNoError(&o->d_err);
108 ASSERT(o->state == CSTATE_CONNECTING)
109  
110 // check error
111 if (is_error) {
112 BLog(BLOG_ERROR, "failed to connect to socket");
113 goto fail0;
114 }
115  
116 BPendingGroup *pg = BReactor_PendingGroup(o->reactor);
117  
118 // init connection
119 if (!BConnection_Init(&o->con, BConnection_source_connector(&o->connector), o->reactor, o, (BConnection_handler)connection_handler)) {
120 BLog(BLOG_ERROR, "BConnection_Init failed");
121 goto fail0;
122 }
123  
124 // init connection interfaces
125 BConnection_SendAsync_Init(&o->con);
126 BConnection_RecvAsync_Init(&o->con);
127 StreamPassInterface *con_send_if = BConnection_SendAsync_GetIf(&o->con);
128 StreamRecvInterface *con_recv_if = BConnection_RecvAsync_GetIf(&o->con);
129  
130 // init receive interface
131 PacketPassInterface_Init(&o->recv_if, RECV_MTU, (PacketPassInterface_handler_send)recv_if_handler_send, o, pg);
132  
133 // init receive decoder
134 if (!PacketProtoDecoder_Init(&o->recv_decoder, con_recv_if, &o->recv_if, pg, o, (PacketProtoDecoder_handler_error)decoder_handler_error)) {
135 BLog(BLOG_ERROR, "PacketProtoDecoder_Init failed");
136 goto fail1;
137 }
138  
139 // init send sender
140 PacketStreamSender_Init(&o->send_sender, con_send_if, PACKETPROTO_ENCLEN(SEND_MTU), pg);
141  
142 // init send queue
143 PacketPassFifoQueue_Init(&o->send_queue, PacketStreamSender_GetInput(&o->send_sender), pg);
144  
145 // set state connected
146 o->state = CSTATE_CONNECTED;
147  
148 // call connected handler
149 o->handler_connected(o->user);
150 return;
151  
152 fail1:
153 PacketPassInterface_Free(&o->recv_if);
154 BConnection_RecvAsync_Free(&o->con);
155 BConnection_SendAsync_Free(&o->con);
156 BConnection_Free(&o->con);
157 fail0:
158 report_error(o);
159 }
160  
161 static void connection_handler (NCDRequestClient *o, int event)
162 {
163 DebugObject_Access(&o->d_obj);
164 DebugError_AssertNoError(&o->d_err);
165 ASSERT(o->state == CSTATE_CONNECTED)
166  
167 BLog(BLOG_ERROR, "connection error");
168  
169 report_error(o);
170 }
171  
172 static void decoder_handler_error (NCDRequestClient *o)
173 {
174 DebugObject_Access(&o->d_obj);
175 DebugError_AssertNoError(&o->d_err);
176 ASSERT(o->state == CSTATE_CONNECTED)
177  
178 BLog(BLOG_ERROR, "decoder error");
179  
180 report_error(o);
181 }
182  
183 static void recv_if_handler_send (NCDRequestClient *o, uint8_t *data, int data_len)
184 {
185 DebugObject_Access(&o->d_obj);
186 DebugError_AssertNoError(&o->d_err);
187 ASSERT(o->state == CSTATE_CONNECTED)
188 ASSERT(data_len >= 0)
189 ASSERT(data_len <= RECV_MTU)
190  
191 // accept packet
192 PacketPassInterface_Done(&o->recv_if);
193  
194 if (data_len < sizeof(struct requestproto_header)) {
195 BLog(BLOG_ERROR, "missing requestproto header");
196 goto fail;
197 }
198  
199 struct requestproto_header header;
200 memcpy(&header, data, sizeof(header));
201 uint32_t request_id = ltoh32(header.request_id);
202 uint32_t type = ltoh32(header.type);
203  
204 uint8_t *payload = data + sizeof(header);
205 int payload_len = data_len - sizeof(header);
206  
207 // find request
208 struct NCDRequestClient_req *req = find_req(o, request_id);
209 if (!req) {
210 BLog(BLOG_ERROR, "received packet with unknown request ID");
211 goto fail;
212 }
213  
214 switch (type) {
215 case REQUESTPROTO_TYPE_SERVER_REPLY: {
216 switch (o->state) {
217 case RSTATE_READY: {
218 // init memory
219 NCDValMem mem;
220 NCDValMem_Init(&mem, o->string_index);
221  
222 // parse payload
223 NCDValRef payload_value;
224 if (!NCDValParser_Parse(MemRef_Make((char *)payload, payload_len), &mem, &payload_value)) {
225 BLog(BLOG_ERROR, "failed to parse reply payload");
226 NCDValMem_Free(&mem);
227 goto fail;
228 }
229  
230 // call reply handler
231 req->creq->handler_reply(req->creq->user, mem, payload_value);
232 return;
233 } break;
234  
235 case RSTATE_SENDING_ABORT:
236 case RSTATE_WAITING_END:
237 return;
238  
239 default:
240 BLog(BLOG_ERROR, "received unexpected reply");
241 goto fail;
242 }
243 } break;
244  
245 case REQUESTPROTO_TYPE_SERVER_FINISHED:
246 case REQUESTPROTO_TYPE_SERVER_ERROR: {
247 if (payload_len != 0) {
248 BLog(BLOG_ERROR, "finshed/aborted message has non-empty payload");
249 goto fail;
250 }
251  
252 NCDRequestClientRequest *creq = req->creq;
253 req->creq = NULL;
254  
255 switch (req->state) {
256 case RSTATE_SENDING_ABORT: {
257 // set state dying send
258 req->state = RSTATE_DEAD_SENDING;
259 } break;
260  
261 case RSTATE_WAITING_END:
262 case RSTATE_READY: {
263 // free req
264 req_free(req);
265 } break;
266  
267 default:
268 BLog(BLOG_ERROR, "received unexpected finished/aborted");
269 goto fail;
270 }
271  
272 // report finished
273 if (creq) {
274 request_report_finished(creq, type == REQUESTPROTO_TYPE_SERVER_ERROR);
275 }
276 return;
277 } break;
278  
279 default:
280 BLog(BLOG_ERROR, "received invalid message type");
281 goto fail;
282 }
283  
284 ASSERT(0)
285  
286 fail:
287 report_error(o);
288 }
289  
290 static struct NCDRequestClient_req * find_req (NCDRequestClient *o, uint32_t request_id)
291 {
292 BAVLNode *tn = BAVL_LookupExact(&o->reqs_tree, &request_id);
293 if (!tn) {
294 return NULL;
295 }
296  
297 struct NCDRequestClient_req *req = UPPER_OBJECT(tn, struct NCDRequestClient_req, reqs_tree_node);
298 ASSERT(req->request_id == request_id)
299  
300 return req;
301 }
302  
303 static int get_free_request_id (NCDRequestClient *o, uint32_t *out)
304 {
305 uint32_t first = o->next_request_id;
306  
307 do {
308 if (!find_req(o, o->next_request_id)) {
309 *out = o->next_request_id;
310 return 1;
311 }
312 o->next_request_id++;
313 } while (o->next_request_id != first);
314  
315 return 0;
316 }
317  
318 static int build_requestproto_packet (uint32_t request_id, uint32_t type, NCDValRef payload_value, uint8_t **out_data, int *out_len)
319 {
320 ExpString str;
321 if (!ExpString_Init(&str)) {
322 BLog(BLOG_ERROR, "ExpString_Init failed");
323 goto fail0;
324 }
325  
326 if (!ExpString_AppendZeros(&str, sizeof(struct packetproto_header) + sizeof(struct requestproto_header))) {
327 BLog(BLOG_ERROR, "ExpString_AppendBinary failed");
328 goto fail1;
329 }
330  
331 if (!NCDVal_IsInvalid(payload_value) && !NCDValGenerator_AppendGenerate(payload_value, &str)) {
332 BLog(BLOG_ERROR, "NCDValGenerator_AppendGenerate failed");
333 goto fail1;
334 }
335  
336 size_t len = ExpString_Length(&str);
337 if (len > INT_MAX || len > PACKETPROTO_ENCLEN(SEND_MTU) || len - sizeof(struct packetproto_header) > UINT16_MAX) {
338 BLog(BLOG_ERROR, "reply is too long");
339 goto fail1;
340 }
341  
342 uint8_t *packet = (uint8_t *)ExpString_Get(&str);
343  
344 struct packetproto_header pp;
345 pp.len = htol16(len - sizeof(struct packetproto_header));
346  
347 struct requestproto_header rp;
348 rp.request_id = htol32(request_id);
349 rp.type = htol32(type);
350  
351 memcpy(packet, &pp, sizeof(pp));
352 memcpy(packet + sizeof(pp), &rp, sizeof(rp));
353  
354 *out_data = packet;
355 *out_len = len;
356 return 1;
357  
358 fail1:
359 ExpString_Free(&str);
360 fail0:
361 return 0;
362 }
363  
364 static void build_nodata_packet (uint32_t request_id, uint32_t type, uint8_t *data, int *out_len)
365 {
366 struct packetproto_header pp;
367 pp.len = htol16(sizeof(struct requestproto_header));
368  
369 struct requestproto_header rp;
370 rp.request_id = htol32(request_id);
371 rp.type = htol32(type);
372  
373 memcpy(data, &pp, sizeof(pp));
374 memcpy(data + sizeof(pp), &rp, sizeof(rp));
375  
376 *out_len = sizeof(pp) + sizeof(rp);
377 }
378  
379 static int req_is_aborted (struct NCDRequestClient_req *req)
380 {
381 switch (req->state) {
382 case RSTATE_SENDING_REQUEST:
383 case RSTATE_READY:
384 return 0;
385 default:
386 return 1;
387 }
388 }
389  
390 static void req_abort (struct NCDRequestClient_req *req)
391 {
392 ASSERT(!req_is_aborted(req))
393 ASSERT(!req->client->is_error)
394  
395 switch (req->state) {
396 case RSTATE_SENDING_REQUEST: {
397 req->state = RSTATE_SENDING_REQUEST_ABORT;
398 } break;
399  
400 case RSTATE_READY: {
401 req_send_abort(req);
402 } break;
403  
404 default: ASSERT(0);
405 }
406 }
407  
408 static void req_free (struct NCDRequestClient_req *req)
409 {
410 NCDRequestClient *client = req->client;
411 PacketPassFifoQueueFlow_AssertFree(&req->send_qflow);
412 ASSERT(!req->creq)
413  
414 // free queue flow
415 PacketPassFifoQueueFlow_Free(&req->send_qflow);
416  
417 // free request data
418 free(req->request_data);
419  
420 // remove from reqs tree
421 BAVL_Remove(&client->reqs_tree, &req->reqs_tree_node);
422  
423 // free structure
424 free(req);
425 }
426  
427 static void req_send_abort (struct NCDRequestClient_req *req)
428 {
429 // build packet
430 build_nodata_packet(req->request_id, REQUESTPROTO_TYPE_CLIENT_ABORT, req->request_data, &req->request_len);
431  
432 // start sending
433 PacketPassInterface_Sender_Send(req->send_qflow_iface, req->request_data, req->request_len);
434  
435 // set state sending abort
436 req->state = RSTATE_SENDING_ABORT;
437 }
438  
439 static void req_qflow_send_iface_handler_done (struct NCDRequestClient_req *req)
440 {
441 switch (req->state) {
442 case RSTATE_SENDING_REQUEST: {
443 // set state ready
444 req->state = RSTATE_READY;
445  
446 // call sent handler
447 req->creq->handler_sent(req->creq->user);
448 return;
449 } break;
450  
451 case RSTATE_SENDING_REQUEST_ABORT: {
452 // send abort
453 req_send_abort(req);
454 } break;
455  
456 case RSTATE_SENDING_ABORT: {
457 // set state waiting end
458 req->state = RSTATE_WAITING_END;
459 } break;
460  
461 case RSTATE_DEAD_SENDING: {
462 // free req
463 req_free(req);
464 } break;
465  
466 default: ASSERT(0);
467 }
468 }
469  
470 int NCDRequestClient_Init (NCDRequestClient *o, struct BConnection_addr addr, BReactor *reactor, NCDStringIndex *string_index,
471 void *user,
472 NCDRequestClient_handler_error handler_error,
473 NCDRequestClient_handler_connected handler_connected)
474 {
475 ASSERT(handler_error)
476 ASSERT(handler_connected)
477  
478 // init arguments
479 o->reactor = reactor;
480 o->string_index = string_index;
481 o->user = user;
482 o->handler_error = handler_error;
483 o->handler_connected = handler_connected;
484  
485 // init connector
486 if (!BConnector_InitGeneric(&o->connector, addr, reactor, o, (BConnector_handler)connector_handler)) {
487 BLog(BLOG_ERROR, "BConnector_InitGeneric failed");
488 goto fail0;
489 }
490  
491 // init reqs tree
492 BAVL_Init(&o->reqs_tree, OFFSET_DIFF(struct NCDRequestClient_req, request_id, reqs_tree_node), uint32_comparator, NULL);
493  
494 // set next request ID
495 o->next_request_id = 0;
496  
497 // set state connecting
498 o->state = CSTATE_CONNECTING;
499  
500 // set is not error
501 o->is_error = 0;
502  
503 DebugCounter_Init(&o->d_reqests_ctr);
504 DebugError_Init(&o->d_err, BReactor_PendingGroup(reactor));
505 DebugObject_Init(&o->d_obj);
506 return 1;
507  
508 fail0:
509 return 0;
510 }
511  
512 void NCDRequestClient_Free (NCDRequestClient *o)
513 {
514 DebugObject_Free(&o->d_obj);
515 DebugError_Free(&o->d_err);
516 DebugCounter_Free(&o->d_reqests_ctr);
517  
518 if (o->state == CSTATE_CONNECTED) {
519 // allow freeing queue flow
520 PacketPassFifoQueue_PrepareFree(&o->send_queue);
521  
522 // free remaining reqs
523 BAVLNode *tn;
524 while (tn = BAVL_GetFirst(&o->reqs_tree)) {
525 struct NCDRequestClient_req *req = UPPER_OBJECT(tn, struct NCDRequestClient_req, reqs_tree_node);
526 ASSERT(!req->creq)
527 req_free(req);
528 }
529  
530 // free connection stuff
531 PacketPassFifoQueue_Free(&o->send_queue);
532 PacketStreamSender_Free(&o->send_sender);
533 PacketProtoDecoder_Free(&o->recv_decoder);
534 PacketPassInterface_Free(&o->recv_if);
535 BConnection_RecvAsync_Free(&o->con);
536 BConnection_SendAsync_Free(&o->con);
537 BConnection_Free(&o->con);
538 }
539  
540 // free connector
541 BConnector_Free(&o->connector);
542 }
543  
544 int NCDRequestClientRequest_Init (NCDRequestClientRequest *o, NCDRequestClient *client, NCDValRef payload_value, void *user,
545 NCDRequestClientRequest_handler_sent handler_sent,
546 NCDRequestClientRequest_handler_reply handler_reply,
547 NCDRequestClientRequest_handler_finished handler_finished)
548 {
549 ASSERT(client->state == CSTATE_CONNECTED)
550 DebugError_AssertNoError(&client->d_err);
551 ASSERT(!NCDVal_IsInvalid(payload_value))
552 ASSERT(handler_sent)
553 ASSERT(handler_reply)
554 ASSERT(handler_finished)
555  
556 // init arguments
557 o->client = client;
558 o->user = user;
559 o->handler_sent = handler_sent;
560 o->handler_reply = handler_reply;
561 o->handler_finished = handler_finished;
562  
563 // allocate req structure
564 struct NCDRequestClient_req *req = malloc(sizeof(*req));
565 if (!req) {
566 BLog(BLOG_ERROR, "malloc failed");
567 goto fail0;
568 }
569  
570 // allocate request ID
571 if (!get_free_request_id(client, &req->request_id)) {
572 BLog(BLOG_ERROR, "failed to allocate request ID");
573 goto fail1;
574 }
575  
576 // insert to reqs tree
577 int res = BAVL_Insert(&client->reqs_tree, &req->reqs_tree_node, NULL);
578 ASSERT_EXECUTE(res)
579  
580 // set pointers
581 o->req = req;
582 req->creq = o;
583 req->client = client;
584  
585 // build request
586 if (!build_requestproto_packet(req->request_id, REQUESTPROTO_TYPE_CLIENT_REQUEST, payload_value, &req->request_data, &req->request_len)) {
587 BLog(BLOG_ERROR, "failed to build request");
588 goto fail2;
589 }
590  
591 // init queue flow
592 PacketPassFifoQueueFlow_Init(&req->send_qflow, &client->send_queue);
593  
594 // init send interface
595 req->send_qflow_iface = PacketPassFifoQueueFlow_GetInput(&req->send_qflow);
596 PacketPassInterface_Sender_Init(req->send_qflow_iface, (PacketPassInterface_handler_done)req_qflow_send_iface_handler_done, req);
597  
598 // start sending request
599 PacketPassInterface_Sender_Send(req->send_qflow_iface, req->request_data, req->request_len);
600  
601 // set state sending request
602 req->state = RSTATE_SENDING_REQUEST;
603  
604 DebugCounter_Increment(&client->d_reqests_ctr);
605 DebugError_Init(&o->d_err, BReactor_PendingGroup(client->reactor));
606 DebugObject_Init(&o->d_obj);
607 return 1;
608  
609 fail2:
610 BAVL_Remove(&client->reqs_tree, &req->reqs_tree_node);
611 fail1:
612 free(req);
613 fail0:
614 return 0;
615 }
616  
617 void NCDRequestClientRequest_Free (NCDRequestClientRequest *o)
618 {
619 struct NCDRequestClient_req *req = o->req;
620 DebugObject_Free(&o->d_obj);
621 DebugError_Free(&o->d_err);
622 DebugCounter_Decrement(&o->client->d_reqests_ctr);
623  
624 if (req) {
625 ASSERT(req->creq == o)
626  
627 // remove reference to us
628 req->creq = NULL;
629  
630 // abort req if not already
631 if (!req->client->is_error && !req_is_aborted(req)) {
632 req_abort(req);
633 }
634 }
635 }
636  
637 void NCDRequestClientRequest_Abort (NCDRequestClientRequest *o)
638 {
639 struct NCDRequestClient_req *req = o->req;
640 DebugObject_Access(&o->d_obj);
641 DebugError_AssertNoError(&o->d_err);
642 DebugError_AssertNoError(&o->client->d_err);
643 ASSERT(req)
644 ASSERT(req->creq == o)
645 ASSERT(!req_is_aborted(req))
646  
647 // abort req
648 req_abort(req);
649 }