1 /* $Id: transaction.c 20918 2012-01-27 04:31:58Z m-oki $ */
2
3 /*
4 * Copyright (c) 2012, Internet Initiative Japan, Inc.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
21 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
24 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
26 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
27 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30 #include "config.h"
31
32 #include <errno.h>
33 #include <time.h>
34 #include <string.h>
35 #include <unistd.h>
36
37 #include <libarms/queue.h>
38 #include <sys/socket.h>
39 #include <netdb.h>
40 #ifdef HAVE_FCNTL
41 #include <fcntl.h>
42 #endif
43 #include <sys/ioctl.h>
44
45 #include <openssl/ssl.h>
46
47 #include <libarms.h>
48 #include <libarms_resource.h>
49 #include <armsd_conf.h> /* for ACMI */
50
51 #include <axp_extern.h>
52 #include <libarms/malloc.h>
53 #include <libarms/time.h>
54 #include <libarms/ssl.h>
55 #include <armsd_conf.h>
56 #include <libarms_log.h>
57 #include <scheduler/scheduler.h>
58 #include <transaction/transaction.h>
59 #include <protocol/arms_methods.h>
60 #include <http/http.h>
61
62 #include "compat.h"
63
64 static struct tr_list tr_list =
65 LIST_HEAD_INITIALIZER(tr_list);
66
67 /* for pull (LS-PULL, RS-PULL, PUSH-READY) */
68 static int ssl_send_req(struct arms_schedule *, int);
69 static int ssl_recv_res(struct arms_schedule *, int);
70
71 /* for push */
72 static int ssl_req_accept(struct arms_schedule *, int);
73 static int ssl_req_ssl_connect(struct arms_schedule *, int);
74 static int ssl_recv_req(struct arms_schedule *, int);
75 static int ssl_send_res(struct arms_schedule *, int);
76 static int ssl_req_connect(struct arms_schedule *, int);
77
78 /* with proxy */
79 static int ssl_req_proxy_connect(struct arms_schedule *, int);
80 static int ssl_req_proxy_response(struct arms_schedule *, int);
81
82 /*
83 * for check-transaction
84 */
85 struct tr_list *
get_tr_list(void)86 get_tr_list(void)
87 {
88 return &tr_list;
89 }
90
91 static const char *
tr_msgstr(const transaction * tr)92 tr_msgstr(const transaction *tr)
93 {
94 const tr_ctx_t *tr_ctx = &tr->tr_ctx;
95
96 if (tr_ctx->pm)
97 return tr_ctx->pm->pm_string;
98
99 return "transaction";
100 }
101
102 static const char *
tr_rsstr(transaction * tr)103 tr_rsstr(transaction *tr)
104 {
105 static char buf[16];
106
107 if (TR_TYPE(tr->state) == TR_DONE) {
108 snprintf(buf, sizeof(buf), "End Point");
109 } else {
110 snprintf(buf, sizeof(buf), "RS[%d]", tr->cur_uri);
111 }
112 return buf;
113 }
114
115 /*
116 * socket is connected or accepted
117 *
118 * tr->ssl
119 * tr->ssl_ctx
120 */
121 static int
ssl_setup(transaction * tr,int fd,arms_context_t * res)122 ssl_setup(transaction *tr, int fd, arms_context_t *res)
123 {
124 EVP_PKEY *mykey;
125 X509 *mycert;
126 X509_STORE *store;
127 struct sockaddr_storage ss;
128 socklen_t ss_len;
129 char hostname[128];
130
131 if (tr->state == TR_START_REQUEST) {
132 tr->ssl_ctx = arms_ssl_ctx_new(ARMS_SSL_SERVER_METHOD);
133 } else {
134 tr->ssl_ctx = arms_ssl_ctx_new(ARMS_SSL_CLIENT_METHOD);
135 }
136 if (tr->ssl_ctx == NULL) {
137 libarms_log(ARMS_LOG_DEBUG, "SSL_CTX_new failed.");
138 return -1;
139 }
140
141 store = SSL_CTX_get_cert_store(tr->ssl_ctx);
142 if (TR_TYPE(tr->state) == TR_LSPULL) {
143 arms_ssl_register_cacert(res->root_ca_cert);
144 } else {
145 arms_ssl_register_cacert(
146 acmi_get_cert_idx(res->acmi, ACMI_CONFIG_CONFSOL, 0));
147 }
148 X509_STORE_add_cert(store, arms_ssl_cacert());
149 SSL_CTX_set_verify_depth(tr->ssl_ctx, SSL_VERIFY_DEPTH);
150 tr->ssl = arms_ssl_new(tr->ssl_ctx);
151 if (tr->ssl == NULL) {
152 libarms_log(ARMS_LOG_DEBUG, "SSL_new failed.");
153 return -1;
154 }
155 SSL_set_fd(tr->ssl, fd);
156
157 mycert = arms_ssl_mycert();
158 mykey = arms_ssl_mykey();
159 if (mycert) {
160 if (SSL_use_certificate(tr->ssl, mycert) != 1) {
161 libarms_log(ARMS_LOG_DEBUG, "SSL_use_certificate failed.");
162 return -1;
163 }
164 }
165 if (mykey) {
166 if (SSL_use_PrivateKey(tr->ssl, mykey) != 1) {
167 libarms_log(ARMS_LOG_DEBUG, "SSL_use_PrivateKey failed.");
168 return -1;
169 }
170 if (SSL_check_private_key(tr->ssl) != 1) {
171 return -1;
172 }
173 }
174 SSL_set_ex_data(tr->ssl, 0, tr);
175 SSL_set_verify(tr->ssl, SSL_VERIFY_PEER,
176 arms_ssl_servercert_verify_cb);
177
178 memset(&ss, 0, sizeof(ss));
179 #if defined(HAVE_STRUCT_SOCKADDR_SA_LEN) && !defined(__OpenBSD__)
180 ss_len = ss.ss_len = sizeof(ss);
181 #else
182 ss_len = sizeof(ss);
183 #endif
184 if (getsockname(fd, (struct sockaddr *)&ss, &ss_len) == 0) {
185 if (getnameinfo((struct sockaddr *)&ss, ss_len,
186 hostname, sizeof(hostname), NULL, 0,
187 NI_NUMERICHOST | NI_NUMERICSERV) == 0) {
188 tr->sa_af = ss.ss_family;
189 strlcpy(tr->sa_address, hostname,
190 sizeof(tr->sa_address));
191 }
192 }
193
194 return 0;
195 }
196
197 static void
ssl_close(transaction * tr)198 ssl_close(transaction *tr)
199 {
200 if (tr->ssl) {
201 arms_ssl_shutdown(tr->ssl);
202 arms_ssl_free(tr->ssl);
203 tr->ssl = NULL;
204 }
205 if (tr->ssl_ctx) {
206 arms_ssl_ctx_free(tr->ssl_ctx);
207 tr->ssl_ctx = NULL;
208 }
209 }
210
211 /*
212 * call pending callback function for output.
213 * this function is useful if SSL is disconnected
214 * when sending application data.
215 */
216 void
arms_tr_reset_callback_state(transaction * tr)217 arms_tr_reset_callback_state(transaction *tr)
218 {
219 if (TR_OUT(tr->state) &&
220 tr->tr_ctx.pm != NULL && tr->builder != NULL &&
221 tr->uriinfo[tr->cur_uri] != NULL) {
222 /* dummy call to reset state of callback. */
223 int rv, len;
224 do {
225 rv = tr->builder(tr,
226 tr->buf, sizeof(tr->buf),
227 &len);
228 } while (rv == TR_WANT_WRITE);
229 }
230 }
231
232 void
arms_tr_ctx_free(tr_ctx_t * tr_ctx)233 arms_tr_ctx_free(tr_ctx_t *tr_ctx)
234 {
235 /* release tr_ctx->arg */
236 if (tr_ctx->pm != NULL) {
237 if (tr_ctx->id != 0) {
238 libarms_log(ARMS_LOG_DEBUG,
239 "[%d] End %s",
240 tr_ctx->id,
241 tr_ctx->pm->pm_string);
242 } else {
243 libarms_log(ARMS_LOG_DEBUG,
244 "[-] End %s",
245 tr_ctx->pm->pm_string);
246 }
247 if (tr_ctx->pm->pm_release != NULL) {
248 tr_ctx->pm->pm_release(tr_ctx);
249 }
250 }
251 /* release tr_ctx->axp */
252 if (tr_ctx->axp) {
253 axp_destroy(tr_ctx->axp);
254 tr_ctx->axp = NULL;
255 }
256 }
257
258 static void
tr_clean_sendbuf(transaction * tr)259 tr_clean_sendbuf(transaction *tr)
260 {
261 struct mem_block *blk;
262
263 while ((blk = TAILQ_FIRST(&tr->head)) != NULL) {
264 TAILQ_REMOVE(&tr->head, blk, next);
265 FREE(blk);
266 }
267 }
268
269 static void
tr_clean(transaction * tr)270 tr_clean(transaction *tr)
271 {
272 int i;
273
274 memset(tr->buf, 0, sizeof(tr->buf));
275 tr->len = 0;
276
277 for (i = 0; (i < tr->nuri) && (i < MAX_URIINFO); i++) {
278 if (tr->uriinfo[i] != NULL) {
279 FREE(tr->uriinfo[i]);
280 tr->uriinfo[i] = NULL;
281 }
282 }
283 tr->cur_uri = 0;
284 tr->nuri = 0;
285 /* free http */
286 if (tr->release_data) {
287 tr->release_data(tr);
288 tr->release_data = NULL;
289 }
290 }
291
292 /*
293 * public version function
294 */
295 void
arms_transaction_free(transaction * tr)296 arms_transaction_free(transaction *tr)
297 {
298 ssl_close(tr);
299 tr_clean_sendbuf(tr);
300 tr_clean(tr);
301 FREE(tr);
302 }
303
304 /*
305 * remove transaction from list and free it.
306 */
307 static void
tr_remove(transaction * tr)308 tr_remove(transaction *tr)
309 {
310 LIST_REMOVE(tr, next);
311 arms_tr_reset_callback_state(tr);
312 arms_tr_ctx_free(&tr->tr_ctx);
313 arms_transaction_free(tr);
314 }
315
316 static
317 void
tr_shift(transaction * tr)318 tr_shift(transaction *tr)
319 {
320 arms_context_t *res = arms_get_context();
321 int num_server = 0;
322 int current_server = 0;
323
324 switch (TR_TYPE(tr->state)) {
325 case TR_LSPULL:
326 acmi_shift_current_server(res->acmi, ACMI_CONFIG_RSSOL, 1);
327 num_server = acmi_get_num_server(res->acmi, ACMI_CONFIG_RSSOL);
328 current_server = acmi_get_current_server(res->acmi, ACMI_CONFIG_RSSOL);
329 #if defined(ARMS_DEBUG)
330 libarms_log(ARMS_LOG_DEBUG,
331 "shift server: ACMI_CONFIG_RSSOL: %d of %d\n", current_server + 1, num_server);
332 #endif /* defined(ARMS_DEBUG) */
333 break;
334
335 case TR_RSPULL:
336 acmi_shift_current_server(res->acmi, ACMI_CONFIG_CONFSOL, 1);
337 num_server = acmi_get_num_server(res->acmi, ACMI_CONFIG_CONFSOL);
338 current_server = acmi_get_current_server(res->acmi, ACMI_CONFIG_CONFSOL);
339 #if defined(ARMS_DEBUG)
340 libarms_log(ARMS_LOG_DEBUG,
341 "shift server: ACMI_CONFIG_CONFSOL: %d of %d\n", current_server + 1, num_server);
342 #endif /* defined(ARMS_DEBUG) */
343 break;
344
345 default:
346 /* ignore */
347 break;
348 }
349 }
350
351
352 /*
353 * start
354 */
355 void
arms_transaction_setup(transaction * tr)356 arms_transaction_setup(transaction *tr)
357 {
358 arms_context_t *res = arms_get_context();
359 const char *url;
360 int i;
361 int num_server = 0;
362 int current_server = 0;
363 tr_ctx_t *tr_ctx;
364
365 tr_ctx = &tr->tr_ctx;
366 switch (TR_TYPE(tr->state)) {
367 case TR_LSPULL:
368 tr->retry_interval =
369 acmi_retry_interval(res->acmi, ACMI_CONFIG_RSSOL);
370 tr->retry_max =
371 acmi_retry_max(res->acmi, ACMI_CONFIG_RSSOL);
372 num_server = acmi_get_num_server(res->acmi, ACMI_CONFIG_RSSOL);
373 current_server = acmi_get_current_server(res->acmi, ACMI_CONFIG_RSSOL);
374 #if defined(ARMS_DEBUG)
375 libarms_log(ARMS_LOG_DEBUG,
376 "current server: ACMI_CONFIG_RSSOL: %d of %d\n",
377 current_server + 1, num_server);
378 #endif /* defined(ARMS_DEBUG) */
379 for (i = 0; i < num_server; i++) {
380 url = acmi_refer_url(res->acmi,
381 ACMI_CONFIG_RSSOL,
382 ACMI_MODULO_SHIFT(current_server, i, num_server));
383 if (url == NULL)
384 break;
385 if (strlen(url) == 0) {
386 tr->uriinfo[i] = NULL;
387 break;
388 }
389 tr->uriinfo[i] = STRDUP(url);
390 #if defined(ARMS_DEBUG)
391 libarms_log(ARMS_LOG_DEBUG,
392 "uriinfo[%d] = %s\n", i, tr->uriinfo[i]);
393 #endif /* defined(ARMS_DEBUG) */
394 }
395 tr->cur_uri = 0;
396 tr->nuri = i;
397 tr->tr_ctx.pm = &rs_sol_methods;
398 tr->passwd = res->ls_preshared_key;
399 break;
400
401 case TR_RSPULL:
402 tr->retry_interval =
403 acmi_retry_interval(res->acmi, ACMI_CONFIG_CONFSOL);
404 tr->retry_max =
405 acmi_retry_max(res->acmi, ACMI_CONFIG_CONFSOL);
406 num_server = acmi_get_num_server(res->acmi, ACMI_CONFIG_CONFSOL);
407 current_server = acmi_get_current_server(res->acmi, ACMI_CONFIG_CONFSOL);
408 #if defined(ARMS_DEBUG)
409 libarms_log(ARMS_LOG_DEBUG,
410 "current server: ACMI_CONFIG_CONFSOL: %d of %d\n",
411 current_server + 1, num_server);
412 #endif /* defined(ARMS_DEBUG) */
413 for (i = 0; i < num_server; i++) {
414 url = acmi_refer_url(res->acmi,
415 ACMI_CONFIG_CONFSOL,
416 ACMI_MODULO_SHIFT(current_server, i, num_server));
417 if (url == NULL)
418 break;
419 if (strlen(url) == 0) {
420 tr->uriinfo[i] = NULL;
421 break;
422 }
423 tr->uriinfo[i] = STRDUP(url);
424 #if defined(ARMS_DEBUG)
425 libarms_log(ARMS_LOG_DEBUG,
426 "uriinfo[%d] = %s\n", i, tr->uriinfo[i]);
427 #endif /* defined(ARMS_DEBUG) */
428 }
429 tr->cur_uri = 0;
430 tr->nuri = i;
431 tr->passwd = res->rs_preshared_key;
432 tr->tr_ctx.pm = &conf_sol_methods;
433 break;
434 case TR_METHOD_QUERY:
435 /* like RSPULL, but method is method-query-methods */
436 tr->retry_interval =
437 acmi_retry_interval(res->acmi, ACMI_CONFIG_CONFSOL);
438 tr->retry_max =
439 acmi_retry_max(res->acmi, ACMI_CONFIG_CONFSOL);
440 /* calc number of uri */
441 for (tr->nuri = 0; tr->nuri < MAX_RS_INFO; tr->nuri++) {
442 url = res->rs_pull_url[tr->nuri];
443 if (url == NULL) {
444 /* no more RS. */
445 break;
446 }
447 }
448 /* put (shifted) uri */
449 for (i = 0; i < tr->nuri; i++) {
450 int n = (res->rs_pull_1st + i) % tr->nuri;
451 url = res->rs_pull_url[n];
452 if (strlen(url) == 0) {
453 tr->uriinfo[i] = NULL;
454 break;
455 }
456 tr->uriinfo[i] = STRDUP(url);
457 }
458 #if defined(ARMS_DEBUG)
459 for (i = 0; i < tr->nuri; i++) {
460 libarms_log(ARMS_LOG_DEBUG,
461 "uriinfo[%d] = %s\n", i, tr->uriinfo[i]);
462 }
463 #endif /* defined(ARMS_DEBUG) */
464 tr->cur_uri = 0;
465 tr->passwd = res->rs_preshared_key;
466 tr->tr_ctx.pm = &method_query_methods;
467 break;
468
469 case TR_CONFIRM_START:
470 /* like RSPULL, but method is confirm-start-methods */
471 tr->retry_interval = 0;
472 tr->retry_max = 0;
473 tr->cur_uri = 0;
474 tr->nuri = 1;
475 /* uriinfo[0] is prepared by new_confirm_start_transaction. */
476 tr->passwd = res->rs_preshared_key;
477 tr->tr_ctx.pm = &confirm_start_methods;
478 break;
479
480 case TR_START:
481 case TR_CONFIRM_DONE:
482 /*
483 * like PUSH_READY, but incoming settings.
484 * - method is unkonwn.
485 * - only one url (make from <result-url> in the request)
486 */
487 tr->retry_interval =
488 acmi_retry_interval(res->acmi, ACMI_CONFIG_CONFSOL);
489 tr->retry_max =
490 acmi_retry_max(res->acmi, ACMI_CONFIG_CONFSOL);
491 tr->passwd = res->rs_preshared_key;
492 return;
493
494 case TR_DONE:
495 /*
496 * like PUSH_READY, but URL is only one
497 * (and already prepared by start-req.)
498 */
499 tr->retry_interval =
500 acmi_retry_interval(res->acmi, ACMI_CONFIG_CONFSOL);
501 tr->retry_max =
502 acmi_retry_max(res->acmi, ACMI_CONFIG_CONFSOL);
503 return;
504 default:
505 break;
506 }
507 if (TR_TYPE(tr->state) != TR_START &&
508 TR_TYPE(tr->state) != TR_DONE) {
509 /*
510 * PULL, PUSH-READY.
511 */
512 if (tr_ctx->pm != NULL) {
513 if (tr_ctx->id != 0) {
514 libarms_log(ARMS_LOG_DEBUG,
515 "[%d] Start %s",
516 tr_ctx->id, tr_ctx->pm->pm_string);
517 } else {
518 libarms_log(ARMS_LOG_DEBUG,
519 "[-] Start %s",
520 tr_ctx->pm->pm_string);
521 }
522 if (tr_ctx->pm->pm_context != NULL &&
523 tr_ctx->arg == NULL)
524 tr_ctx->arg =
525 tr_ctx->pm->pm_context(tr_ctx);
526 }
527 }
528 }
529
530 /*
531 * call from libarms.
532 *
533 * builder: chunked or directly content builder w/ http header.
534 */
535 int
new_ls_pull_transaction(arms_context_t * res,const char * user)536 new_ls_pull_transaction(arms_context_t *res, const char *user)
537 {
538 transaction *tr;
539 struct timeval timo;
540
541 tr = CALLOC(1, sizeof(transaction));
542 if (tr == NULL) {
543 return -1;
544 }
545 tr->user = user;
546 TAILQ_INIT(&tr->head);
547 LIST_INSERT_HEAD(&tr_list, tr, next);
548
549 tr->state = TR_LSPULL_REQUEST;
550
551 /* server type depnded setup */
552 arms_transaction_setup(tr);
553 if (tr->nuri == 0) {
554 libarms_log(ARMS_LOG_EHOST,
555 "LS not found.");
556 res->trigger = "LS not found";
557 res->result = ARMS_ESYSTEM;
558 return -1;
559 }
560
561 arms_get_time_remaining(&timo, 0);
562 new_arms_schedule(SCHED_TYPE_EXEC,
563 -1, &timo, ssl_req_connect, tr);
564 return 0;
565 }
566
567 int
new_rs_pull_transaction(arms_context_t * res,const char * user)568 new_rs_pull_transaction(arms_context_t *res, const char *user)
569 {
570 transaction *tr;
571 struct timeval timo;
572 int i;
573
574 tr = CALLOC(1, sizeof(transaction));
575 if (tr == NULL) {
576 return -1;
577 }
578 tr->user = user;
579 TAILQ_INIT(&tr->head);
580 LIST_INSERT_HEAD(&tr_list, tr, next);
581
582 tr->state = TR_RSPULL_REQUEST;
583
584 /* server type depnded setup */
585 arms_transaction_setup(tr);
586 if (tr->nuri == 0) {
587 libarms_log(ARMS_LOG_EHOST,
588 "RS not found.");
589 res->trigger = "RS not found";
590 res->result = ARMS_ESYSTEM;
591 return -1;
592 }
593 for (i = 0; i < tr->nuri; i++) {
594 libarms_log(ARMS_LOG_DEBUG,
595 "RS[%d]: %s", i, tr->uriinfo[i]);
596 }
597
598 arms_get_time_remaining(&timo, 0);
599 new_arms_schedule(SCHED_TYPE_EXEC,
600 -1, &timo, ssl_req_connect, tr);
601 return 0;
602 }
603
604 /*
605 * push-method-query transaction.
606 * call from libarms.
607 *
608 * builder: chunked or directly content builder w/ http header.
609 */
610 int
new_method_query_transaction(arms_context_t * res,const char * user)611 new_method_query_transaction(arms_context_t *res, const char *user)
612 {
613 transaction *tr;
614 struct timeval timo;
615
616 if (res->rs_pull_url[0] == NULL) {
617 libarms_log(ARMS_LOG_EHOST,
618 "RS not found.");
619 res->trigger = "push server not found";
620 res->result = ARMS_ESYSTEM;
621 return -1;
622 }
623
624 tr = CALLOC(1, sizeof(transaction));
625 if (tr == NULL) {
626 return -1;
627 }
628 tr->user = user;
629 tr->num = res->rs_pull_1st;
630 TAILQ_INIT(&tr->head);
631 LIST_INSERT_HEAD(&tr_list, tr, next);
632
633 tr->state = TR_METHOD_QUERY_REQUEST;
634
635 /* server type depnded setup */
636 arms_transaction_setup(tr);
637
638 arms_get_time_remaining(&timo, 0);
639 new_arms_schedule(SCHED_TYPE_EXEC,
640 -1, &timo, ssl_req_connect, tr);
641 return 0;
642 }
643
644 /*
645 * push-confirmation transaction.
646 * call from libarms.
647 *
648 * builder: chunked or directly content builder w/ http header.
649 */
650 int
new_confirm_start_transaction(arms_context_t * res,const char * user,const char * rs_url,int num)651 new_confirm_start_transaction(arms_context_t *res, const char *user,
652 const char *rs_url, int num)
653 {
654 transaction *tr;
655 struct timeval timo;
656
657 tr = CALLOC(1, sizeof(transaction));
658 if (tr == NULL) {
659 return -1;
660 }
661 tr->user = user;
662 tr->num = num;
663 TAILQ_INIT(&tr->head);
664 LIST_INSERT_HEAD(&tr_list, tr, next);
665
666 tr->state = TR_CONFIRM_START_REQUEST;
667
668 /* server type depnded setup */
669 arms_transaction_setup(tr);
670 tr->uriinfo[0] = STRDUP(rs_url);
671
672 arms_get_time_remaining(&timo, 0);
673 new_arms_schedule(SCHED_TYPE_EXEC,
674 -1, &timo, ssl_req_connect, tr);
675
676 if (arms_get_global_state() != ARMS_ST_PUSH_SENDREADY)
677 libarms_log(ARMS_LOG_IPROTO_CONFIRM_START,
678 "Start push confirmation");
679 arms_set_global_state(ARMS_ST_PUSH_SENDREADY);
680 return 0;
681 }
682
683 /*
684 * call from server.
685 */
686 int
new_push_transaction(int s,struct sockaddr_storage * ss,socklen_t socklen,const char * user)687 new_push_transaction(int s,
688 struct sockaddr_storage *ss, socklen_t socklen,
689 const char *user)
690 {
691 struct timeval timo;
692 transaction *tr;
693
694 tr = CALLOC(1, sizeof(transaction));
695 if (tr == NULL) {
696 return -1;
697 }
698 tr->state = TR_START_REQUEST;
699 tr->user = user;
700 /* send response buffer */
701 TAILQ_INIT(&tr->head);
702 arms_transaction_setup(tr);
703 /* default result (for retry) -- 4xx */
704 tr->tr_ctx.result = 400;
705
706 LIST_INSERT_HEAD(&tr_list, tr, next);
707
708 SET_TR_PARSER(tr, http_request_parser);
709 SET_TR_BUILDER(tr, http_response_builder);
710
711 arms_get_time_remaining(&timo, 30);
712 new_arms_schedule(SCHED_TYPE_IO,
713 s, &timo, ssl_req_accept, tr);
714 return 0;
715 }
716
717 /*
718 * called from scheduler directly.
719 */
720 static int
ssl_req_accept(struct arms_schedule * obj,int event)721 ssl_req_accept(struct arms_schedule *obj, int event)
722 {
723 transaction *tr = obj->userdata;
724 arms_context_t *res = arms_get_context();
725 int rv;
726
727 if (tr == NULL) {
728 CLOSE_FD(obj->fd);
729 return SCHED_FINISHED_THIS;
730 }
731
732 switch (event) {
733 case EVENT_TYPE_TIMEOUT:
734 case EVENT_TYPE_FINISH:
735 tr_remove(tr);
736 CLOSE_FD(obj->fd);
737 return SCHED_FINISHED_THIS;
738 default:
739 break;
740 }
741 /* new ssl */
742 if (tr->ssl == NULL) {
743 if (ssl_setup(tr, obj->fd, res) < 0) {
744 tr_remove(tr);
745 CLOSE_FD(obj->fd);
746 return SCHED_FINISHED_THIS;
747 }
748 }
749 rv = SSL_accept(tr->ssl);
750 if (rv <= 0) {
751 switch (SSL_get_error(tr->ssl, rv)) {
752 case SSL_ERROR_WANT_READ:
753 case SSL_ERROR_WANT_WRITE:
754 return SCHED_CONTINUE_THIS;
755 default:
756 libarms_log(ARMS_LOG_ESSL,
757 "SSL Connection reset by peer.");
758 tr_remove(tr);
759 CLOSE_FD(obj->fd);
760 return SCHED_FINISHED_THIS;
761 }
762 }
763
764 SET_NEW_METHOD(obj, ssl_recv_req);
765 arms_get_time_remaining(&obj->timeout, 30);
766 return SCHED_CONTINUE_THIS;
767 }
768
769 /*
770 * called from scheduler directly.
771 */
772 static int
ssl_recv_req(struct arms_schedule * obj,int event)773 ssl_recv_req(struct arms_schedule *obj, int event)
774 {
775 transaction *tr = obj->userdata;
776 arms_context_t *res = arms_get_context();
777 int len, n;
778
779 if (tr == NULL) {
780 CLOSE_FD(obj->fd);
781 return SCHED_FINISHED_THIS;
782 }
783
784 switch (event) {
785 case EVENT_TYPE_READ:
786 break;
787 case EVENT_TYPE_WRITE:
788 break;
789 case EVENT_TYPE_TIMEOUT:
790 libarms_log(ARMS_LOG_DEBUG,
791 "transaction timeout id=%d",
792 tr->tr_ctx.id);
793 /*FALLTHROUGH*/
794 case EVENT_TYPE_FINISH:
795 tr_remove(tr);
796 CLOSE_FD(obj->fd);
797 return SCHED_FINISHED_THIS;
798 default:
799 break;
800 }
801 if (tr->parser == NULL) {
802 /* request parser is nothing. umm, bug? */
803 tr_remove(tr);
804 CLOSE_FD(obj->fd);
805 return SCHED_FINISHED_THIS;
806 }
807
808 rerun:
809 len = sizeof(tr->buf);
810 if (res->fragment > 0 && len > res->fragment)
811 len = res->fragment;
812 if ((tr->len = n = arms_ssl_read(tr->ssl, tr->buf, len)) > 0) {
813 transaction *ntr;
814 int numtr, r;
815
816 tr->zero = 0;
817 /* read partly. call parser (http_req_parser). */
818 switch ((r = tr->parser(tr, tr->buf, n))) {
819 case TR_PARSE_ERROR:
820 goto tr_send_response;
821 case TR_HTTP_AUTH_ERROR:
822 goto tr_send_response;
823 case TR_READ_DONE:
824 numtr = 0;
825 LIST_FOREACH(ntr, &tr_list, next)
826 numtr++;
827 if (numtr > TR_LIMIT)
828 tr->tr_ctx.result = 406;
829 tr_send_response:
830 /*
831 * start to send response.
832 * tr->builder is prepared by parser.
833 */
834 tr->len = 0;
835 if (tr->tr_ctx.pm != NULL &&
836 tr->tr_ctx.pm->pm_done != NULL)
837 tr->state = TR_START_RESPONSE;
838 else
839 tr->state = TR_RESPONSE;
840 obj->type = SCHED_TYPE_IOW;
841 arms_get_time_remaining(&obj->timeout, 30);
842 SET_NEW_METHOD(obj, ssl_send_res);
843 return SCHED_CONTINUE_THIS;
844
845 case TR_WANT_READ:
846 if (SSL_pending(tr->ssl) > 0)
847 goto rerun;
848 return SCHED_CONTINUE_THIS;
849
850 case TR_FATAL_ERROR:
851 tr_remove(tr);
852 CLOSE_FD(obj->fd);
853 return SCHED_FINISHED_THIS;
854 default:
855 /*bug?*/
856 libarms_log(ARMS_LOG_DEBUG,
857 "unknown result %d\n", r);
858 break;
859 }
860 } else if (n == 0) {
861 obj->type = SCHED_TYPE_IOR;
862 return SCHED_CONTINUE_THIS;
863 /*NOTREACHED*/
864 } else {
865 /* if configure transaction is failed, fatal error. */
866 libarms_log(ARMS_LOG_ESSL,
867 "SSL Connection reset by peer.");
868 if (tr->tr_ctx.pm && tr->tr_ctx.pm->pm_rollback) {
869 libarms_log(ARMS_LOG_DEBUG,
870 "configure transaction cannot continue.");
871 res->result = ARMS_EPULL;
872 return SCHED_FINISHED_SCHEDULER;
873 }
874 /* transaction is lost. */
875 tr_remove(tr);
876 CLOSE_FD(obj->fd);
877 return SCHED_FINISHED_THIS;
878 /*NOTREACHED*/
879 }
880 /*bug?*/
881 tr_remove(tr);
882 CLOSE_FD(obj->fd);
883 return SCHED_FINISHED_THIS;
884 }
885
886 /*
887 * called from scheduler directly.
888 */
889 static int
ssl_send_res(struct arms_schedule * obj,int event)890 ssl_send_res(struct arms_schedule *obj, int event)
891 {
892 transaction *tr = obj->userdata;
893 arms_context_t *res = arms_get_context();
894 int rv;
895
896 if (tr == NULL) {
897 CLOSE_FD(obj->fd);
898 return SCHED_FINISHED_THIS;
899 }
900
901 switch (event) {
902 case EVENT_TYPE_TIMEOUT:
903 libarms_log(ARMS_LOG_DEBUG,
904 "transaction timeout id=%d",
905 tr->tr_ctx.id);
906 /*FALLTHROUGH*/
907 case EVENT_TYPE_FINISH:
908 do {
909 rv = tr->builder(tr, tr->buf,
910 sizeof(tr->buf), &tr->len);
911 } while (rv == TR_WANT_WRITE);
912 goto err;
913 case EVENT_TYPE_READ:
914 case EVENT_TYPE_WRITE:
915 break;
916 default:
917 break;
918 }
919
920 if (tr->builder == NULL) {
921 /* response builder is nothing. umm, bug? */
922 goto err;
923 }
924
925 rerun:
926 /* fill data by builder, and write. */
927 if (tr->len > 0) {
928 rv = TR_WANT_WRITE;
929 } else {
930 /* start timer */
931 arms_get_time_remaining(&obj->timeout, 30);
932 rv = tr->builder(tr, tr->buf, sizeof(tr->buf), &tr->len);
933 tr->wp = tr->buf;
934 }
935 switch (rv) {
936 case TR_WANT_STOP:
937 libarms_log(ARMS_LOG_DEBUG,
938 "stop scheduler requested by internal routine");
939 return SCHED_FINISHED_SCHEDULER;
940
941 case TR_WRITE_DONE:
942 /* sent response. */
943 if ((tr->tr_ctx.pm != NULL &&
944 tr->tr_ctx.pm->pm_done == NULL) ||
945 tr->tr_ctx.result != 100) {
946 /*
947 * sync method.
948 * or async method with error.
949 */
950 /* goto err; */
951 break;
952 }
953 /*
954 * async method.
955 * release SSL and fd, but transaction is
956 * still alive. don't release data.
957 * tr->builder is replaced with for done-req
958 * by old tr-builder.
959 */
960 ssl_close(tr);
961 CLOSE_FD(obj->fd);
962 tr_clean(tr);
963 tr_clean_sendbuf(tr);
964
965 /*
966 * if execution method is available, call it.
967 */
968 if (tr->tr_ctx.pm != NULL && tr->tr_ctx.pm->pm_exec) {
969 if (tr->tr_ctx.pm->pm_exec(tr) != 0) {
970 /*
971 * exec and rollback failure.
972 * fatal. reboot.
973 */
974 res->trigger = "rollback failure";
975 res->result = ARMS_EPULL;
976 libarms_log(ARMS_LOG_EROLLBACK,
977 "rollback failure.");
978 return SCHED_FINISHED_SCHEDULER;
979 }
980 }
981 /*
982 * prepare for done-req.
983 */
984 tr->state = TR_DONE_REQUEST;
985 tr->tr_ctx.write_done = 0;
986 SET_TR_BUILDER(tr, http_request_builder);
987 SET_TR_PARSER(tr, http_response_parser);
988 obj->type = SCHED_TYPE_TIMER;
989 arms_get_time_remaining(&obj->timeout, 0);
990 SET_NEW_METHOD(obj, ssl_req_connect);
991 return obj->method(obj, EVENT_TYPE_EXEC);
992
993 case TR_WANT_WRITE:
994 if (tr->len == 0) {
995 /* if tr->builder return 0 bytes data */
996 goto rerun;
997 }
998 do {
999 rv = arms_ssl_write(tr->ssl, tr->wp, tr->len);
1000 if (rv > 0) {
1001 arms_get_time_remaining(&obj->timeout, 30);
1002 tr->wp += rv;
1003 tr->len -= rv;
1004 /*refill or send */
1005 }
1006 } while (tr->len > 0 && rv > 0);
1007 if (tr->len == 0) {
1008 /* all data sent. refill */
1009 goto rerun;
1010 }
1011 if (rv >= 0) {
1012 /* no error. */
1013 return SCHED_CONTINUE_THIS;
1014 }
1015 libarms_log(ARMS_LOG_ESSL,
1016 "SSL Connection reset by peer.");
1017 do {
1018 rv = tr->builder(tr, tr->buf,
1019 sizeof(tr->buf), &tr->len);
1020 } while (rv == TR_WANT_WRITE);
1021
1022 /* if configure transaction is failed, fatal error. */
1023 if (tr->tr_ctx.pm && tr->tr_ctx.pm->pm_rollback) {
1024 libarms_log(ARMS_LOG_DEBUG,
1025 "configure transaction cannot continue.");
1026 res->result = ARMS_EPULL;
1027 return SCHED_FINISHED_SCHEDULER;
1028 }
1029 /*FALLTHROUGH*/
1030 default:
1031 tr_remove(tr);
1032 CLOSE_FD(obj->fd);
1033 return SCHED_FINISHED_THIS;
1034
1035 case TR_FATAL_ERROR:
1036 libarms_log(ARMS_LOG_DEBUG,
1037 "fatal error detected");
1038 return SCHED_FINISHED_SCHEDULER;
1039 }
1040 err:
1041 tr_remove(tr);
1042 CLOSE_FD(obj->fd);
1043 return SCHED_FINISHED_THIS;
1044 }
1045
1046 /*
1047 * SCHED_TYPE_EXEC or SCHED_TYPE_TIMER.
1048 * call from scheduler directly if retry.
1049 *
1050 * TR_LSPULL
1051 * TR_RSPULL
1052 * TR_PUSH_READY
1053 * TR_DONE
1054 */
1055 static int
ssl_req_connect(struct arms_schedule * obj,int event)1056 ssl_req_connect(struct arms_schedule *obj, int event)
1057 {
1058 struct addrinfo hints, *re, *dst_re, *proxy_re;
1059 const char *url;
1060 transaction *tr = obj->userdata;
1061 arms_context_t *res = arms_get_context();
1062 char hostname[80], port[8];
1063 int r, s, on, scheme;
1064
1065 if (tr == NULL) {
1066 CLOSE_FD(obj->fd);
1067 return SCHED_FINISHED_THIS;
1068 }
1069
1070 switch (event) {
1071 case EVENT_TYPE_TIMEOUT:
1072 /* failed to connect. retry? */
1073 #if defined(ARMS_DEBUG)
1074 libarms_log(ARMS_LOG_DEBUG,
1075 "SSL Connection failed: %s: %d.", __func__, __LINE__);
1076 #endif /* defined(ARMS_DEBUG) */
1077 return ssl_client_retry(obj, tr);
1078 case EVENT_TYPE_FINISH:
1079 /* socket is not opened */
1080 tr_remove(tr);
1081 return SCHED_FINISHED_THIS;
1082 case EVENT_TYPE_EXEC:
1083 default:
1084 break;
1085 }
1086
1087 tr->tr_ctx.res_result = 100; /* success is default */
1088 dst_re = NULL;
1089 proxy_re = NULL;
1090 memset(&hints, 0, sizeof(hints));
1091 #ifdef USE_INET6
1092 hints.ai_family = PF_UNSPEC; /* any protocol such as IPv6 */
1093 #else
1094 hints.ai_family = AF_INET;
1095 #endif
1096 hints.ai_socktype = SOCK_STREAM;
1097
1098 /* get hostname and port from URL */
1099
1100 if (TR_TYPE(tr->state) == TR_DONE) {
1101 /* push done-request */
1102 url = res->rs_endpoint;
1103 } else {
1104 /* pull or push-ready. */
1105 url = tr->uriinfo[tr->cur_uri];
1106 }
1107 scheme = arms_parse_url(url,
1108 hostname, sizeof(hostname),
1109 port, sizeof(port), NULL, 0);
1110 /* invalid URL, retry next url */
1111 if (scheme == URL_ERROR) {
1112 libarms_log(ARMS_LOG_EURL, "invalid url: %s", url);
1113 goto soft_err;
1114 }
1115 if (scheme != URL_SCHEME_HTTPS) {
1116 libarms_log(ARMS_LOG_EURL,
1117 "%s: scheme is not https, cannot access", url);
1118 goto soft_err;
1119 }
1120
1121 r = getaddrinfo(hostname, port, &hints, &dst_re);
1122 if (r != 0 || dst_re == NULL) {
1123 libarms_log(ARMS_LOG_EHOST,
1124 "failed to get host information: %s:%s",
1125 hostname, port);
1126 goto soft_err;
1127 }
1128 /* adress family mismatched in URL and line, retry next url */
1129 if (tr->state == TR_LSPULL_REQUEST || tr->state == TR_RSPULL_REQUEST) {
1130 if (res->line_af != AF_UNSPEC &&
1131 res->line_af != dst_re->ai_family) {
1132 libarms_log(ARMS_LOG_DEBUG,
1133 "address family mismatched: %s", hostname);
1134 goto next_url;
1135 }
1136 }
1137 if (tr->state == TR_CONFIRM_START_REQUEST) {
1138 if (res->sa_af && res->sa_af != dst_re->ai_family) {
1139 libarms_log(ARMS_LOG_DEBUG,
1140 "address family mismatched: %s", hostname);
1141 goto af_err;
1142 }
1143 }
1144
1145 tr->sa_af = dst_re->ai_family;
1146 if (res->proxy_is_available) {
1147 char h[80], p[8];
1148
1149 arms_parse_url(res->proxy_url,
1150 h, sizeof(h),
1151 p, sizeof(p), NULL, 0);
1152 memset(&hints, 0, sizeof(hints));
1153 hints.ai_family = dst_re->ai_family;
1154 hints.ai_socktype = SOCK_STREAM;
1155 r = getaddrinfo(h, p, &hints, &proxy_re);
1156 if (r != 0 || proxy_re == NULL) {
1157 libarms_log(ARMS_LOG_DEBUG, "no web proxy available");
1158 goto next_url;
1159 }
1160 re = proxy_re;
1161 } else {
1162 re = dst_re;
1163 }
1164
1165 s = socket(re->ai_family, re->ai_socktype, re->ai_protocol);
1166 if (s == -1) {
1167 /* fatal. */
1168 libarms_log(ARMS_LOG_ESOCKET, "socket(2) failed.");
1169 res->trigger = "internal error(socket)";
1170 goto err;
1171 }
1172 #ifdef HAVE_FCNTL
1173 fcntl(s, F_SETFD, FD_CLOEXEC);
1174 #endif
1175 on = 1;
1176 ioctl(s, FIONBIO, &on);
1177 obj->fd = s;
1178 libarms_log(ARMS_LOG_DEBUG,
1179 "%s: socket prepared. connecting...", tr_rsstr(tr));
1180 r = connect(obj->fd, re->ai_addr, re->ai_addrlen);
1181 if (res->proxy_is_available && proxy_re != NULL)
1182 freeaddrinfo(proxy_re);
1183 freeaddrinfo(dst_re);
1184 proxy_re = NULL;
1185 dst_re = NULL;
1186 if (r == 0 || errno == EINPROGRESS || errno == EINTR) {
1187 if (res->proxy_is_available) {
1188 obj->type = SCHED_TYPE_IO;
1189 SET_NEW_METHOD(obj, ssl_req_proxy_connect);
1190 arms_get_time_remaining(&obj->timeout, 30);
1191 if (r == 0)
1192 return obj->method(obj, EVENT_TYPE_EXEC);
1193 return SCHED_CONTINUE_THIS;
1194 }
1195 if (ssl_setup(tr, obj->fd, res) == 0) {
1196 obj->type = SCHED_TYPE_IO;
1197 SET_NEW_METHOD(obj, ssl_req_ssl_connect);
1198 arms_get_time_remaining(&obj->timeout, 30);
1199 if (tr->state == TR_METHOD_QUERY_REQUEST) {
1200 res->sa_af = tr->sa_af;
1201 strlcpy(res->sa_address, tr->sa_address,
1202 sizeof(res->sa_address));
1203 }
1204 return obj->method(obj, EVENT_TYPE_EXEC);
1205 } else {
1206 }
1207 /* SSL_new is failed... */
1208 }
1209 libarms_log(ARMS_LOG_ECONNECT,
1210 "%s: Connect error (%d).", tr_rsstr(tr), errno);
1211 soft_err:
1212 /* failed to connect. retry? */
1213 #if defined(ARMS_DEBUG)
1214 libarms_log(ARMS_LOG_DEBUG,
1215 "SSL Connection failed: %s: %d.", __func__, __LINE__);
1216 #endif /* defined(ARMS_DEBUG) */
1217 /*FALLTHROUGH*/
1218 next_url:
1219 if (res->proxy_is_available && proxy_re != NULL)
1220 freeaddrinfo(proxy_re);
1221 if (dst_re != NULL)
1222 freeaddrinfo(dst_re);
1223 return ssl_client_retry(obj, tr);
1224
1225 af_err:
1226 /*
1227 * address family mismatched.
1228 * don't retry, but other push-confirmation is working in progress.
1229 */
1230 if (res->proxy_is_available && proxy_re != NULL)
1231 freeaddrinfo(proxy_re);
1232 if (dst_re != NULL)
1233 freeaddrinfo(dst_re);
1234 tr_remove(tr);
1235 CLOSE_FD(obj->fd);
1236 return SCHED_FINISHED_THIS;
1237
1238 err:
1239 if (res->proxy_is_available && proxy_re != NULL)
1240 freeaddrinfo(proxy_re);
1241 if (dst_re != NULL)
1242 freeaddrinfo(dst_re);
1243 if (TR_TYPE(tr->state) == TR_PUSH_READY)
1244 res->result = ARMS_EPULL;
1245 else if (TR_TYPE(tr->state) == TR_CONFIRM_START)
1246 res->result = ARMS_ETIMEOUT;
1247 else
1248 res->result = ARMS_EREBOOT;
1249
1250 return SCHED_FINISHED_SCHEDULER;
1251 }
1252
1253 /*
1254 * call from scheduler directly.
1255 */
1256 static int
ssl_req_proxy_connect(struct arms_schedule * obj,int event)1257 ssl_req_proxy_connect(struct arms_schedule *obj, int event)
1258 {
1259 transaction *tr = obj->userdata;
1260 arms_context_t *res = arms_get_context();
1261 int rv;
1262 socklen_t optlen;
1263
1264 if (tr == NULL) {
1265 CLOSE_FD(obj->fd);
1266 return SCHED_FINISHED_THIS;
1267 }
1268
1269 switch (event) {
1270 case EVENT_TYPE_TIMEOUT:
1271 /* failed to connect. retry? */
1272 return ssl_client_retry(obj, tr);
1273 case EVENT_TYPE_FINISH:
1274 tr_remove(tr);
1275 CLOSE_FD(obj->fd);
1276 return SCHED_FINISHED_THIS;
1277 case EVENT_TYPE_EXEC:
1278 case EVENT_TYPE_READ:
1279 /* initialize */
1280 tr->len = 0;
1281 break;
1282 default:
1283 break;
1284 }
1285
1286 optlen = sizeof(rv);
1287 if (getsockopt(obj->fd, SOL_SOCKET, SO_ERROR, &rv, &optlen) != 0) {
1288 return ssl_client_retry(obj, tr);
1289 }
1290 if (rv != 0) {
1291 libarms_log(ARMS_LOG_ECONNECT,
1292 "web proxy connect error (%d).", rv);
1293 return ssl_client_retry(obj, tr);
1294 }
1295 libarms_log(ARMS_LOG_IHTTP_PROXY_CONNECTED,
1296 "Connected to web proxy %s.", res->proxy_url);
1297 /* fill data by builder, and write. */
1298 if (tr->len > 0) {
1299 } else {
1300 char hostname[80], port[8];
1301
1302 /* build HTTP CONNECT request */
1303 arms_parse_url(tr->uriinfo[tr->cur_uri],
1304 hostname, sizeof(hostname),
1305 port, sizeof(port), NULL, 0);
1306
1307 #ifdef USE_INET6
1308 if (tr->sa_af == AF_INET6) {
1309 tr->len = snprintf(tr->buf, sizeof(tr->buf),
1310 "CONNECT [%s]:%s HTTP/1.1\r\n"
1311 "Host: [%s]:%s\r\n\r\n",
1312 hostname, port,
1313 hostname, port);
1314 } else
1315 #endif
1316 {
1317 tr->len = snprintf(tr->buf, sizeof(tr->buf),
1318 "CONNECT %s:%s HTTP/1.1\r\n"
1319 "Host: %s:%s\r\n\r\n",
1320 hostname, port,
1321 hostname, port);
1322 }
1323 if (tr->len < 0) {
1324 return ssl_client_retry(obj, tr);
1325 }
1326
1327 tr->wp = tr->buf;
1328 }
1329 do {
1330 rv = write(obj->fd, tr->wp, tr->len);
1331 if (rv > 0) {
1332 arms_get_time_remaining(&obj->timeout, 30);
1333 tr->wp += rv;
1334 tr->len -= rv;
1335 /*refill or send */
1336 }
1337 } while (tr->len > 0 && rv > 0);
1338 if (tr->len == 0) {
1339 /* sent request. prepare for receive response */
1340 obj->type = SCHED_TYPE_IOR;
1341 SET_NEW_METHOD(obj, ssl_req_proxy_response);
1342 arms_get_time_remaining(&obj->timeout, 30);
1343 return SCHED_CONTINUE_THIS;
1344 }
1345 if (rv >= 0) {
1346 /* no error. */
1347 return SCHED_CONTINUE_THIS;
1348 }
1349
1350 return ssl_client_retry(obj, tr);
1351 }
1352
1353 /*
1354 * call from scheduler directly.
1355 */
1356 static int
ssl_req_proxy_response(struct arms_schedule * obj,int event)1357 ssl_req_proxy_response(struct arms_schedule *obj, int event)
1358 {
1359 transaction *tr = obj->userdata;
1360 arms_context_t *res = arms_get_context();
1361
1362 if (tr == NULL) {
1363 CLOSE_FD(obj->fd);
1364 return SCHED_FINISHED_THIS;
1365 }
1366
1367 switch (event) {
1368 case EVENT_TYPE_TIMEOUT:
1369 /* failed to connect. retry? */
1370 return ssl_client_retry(obj, tr);
1371 case EVENT_TYPE_FINISH:
1372 tr_remove(tr);
1373 CLOSE_FD(obj->fd);
1374 return SCHED_FINISHED_THIS;
1375 case EVENT_TYPE_EXEC:
1376 default:
1377 break;
1378 }
1379
1380 if ((tr->len = read(obj->fd, tr->buf, sizeof(tr->buf) - 1)) > 0) {
1381 int n, major, minor, result;
1382
1383 tr->buf[tr->len] = '\0';
1384 n = sscanf(tr->buf, "HTTP/%u.%u %u",
1385 &major, &minor, &result);
1386 if (n != 3 || result < 200 || result > 299) {
1387 libarms_log(ARMS_LOG_ECONNECT,
1388 "web proxy server response %d", result);
1389 return ssl_client_retry(obj, tr);
1390 }
1391
1392 if (ssl_setup(tr, obj->fd, res) == 0) {
1393 obj->type = SCHED_TYPE_IO;
1394 SET_NEW_METHOD(obj, ssl_req_ssl_connect);
1395 arms_get_time_remaining(&obj->timeout, 30);
1396 if (tr->state == TR_METHOD_QUERY_REQUEST) {
1397 res->sa_af = tr->sa_af;
1398 strlcpy(res->sa_address, tr->sa_address,
1399 sizeof(res->sa_address));
1400 }
1401 return obj->method(obj, EVENT_TYPE_EXEC);
1402 }
1403 /* SSL_new is failed... */
1404 #if defined(ARMS_DEBUG)
1405 libarms_log(ARMS_LOG_DEBUG,
1406 "SSL Connection failed: %s: %d.", __func__, __LINE__);
1407 #endif /* defined(ARMS_DEBUG) */
1408 return ssl_client_retry(obj, tr);
1409 }
1410 return SCHED_CONTINUE_THIS;
1411 }
1412
1413 /*
1414 * call from scheduler directly.
1415 */
1416 static int
ssl_req_ssl_connect(struct arms_schedule * obj,int event)1417 ssl_req_ssl_connect(struct arms_schedule *obj, int event)
1418 {
1419 transaction *tr = obj->userdata;
1420 int rv;
1421
1422 if (tr == NULL) {
1423 CLOSE_FD(obj->fd);
1424 return SCHED_FINISHED_THIS;
1425 }
1426
1427 switch (event) {
1428 case EVENT_TYPE_TIMEOUT:
1429 /* failed to connect. retry? */
1430 libarms_log(ARMS_LOG_ESSL,
1431 "%s: SSL Connection timeout.", tr_rsstr(tr));
1432 return ssl_client_retry(obj, tr);
1433 case EVENT_TYPE_FINISH:
1434 tr_remove(tr);
1435 CLOSE_FD(obj->fd);
1436 return SCHED_FINISHED_THIS;
1437 case EVENT_TYPE_EXEC:
1438 default:
1439 break;
1440 }
1441
1442 rv = arms_ssl_connect(tr->ssl);
1443 if (rv == 1) {
1444 libarms_log(ARMS_LOG_DEBUG,
1445 "%s: SSL connection established.", tr_rsstr(tr));
1446 obj->type = SCHED_TYPE_IO;
1447 SET_TR_BUILDER(tr, http_request_builder);
1448 SET_NEW_METHOD(obj, ssl_send_req);
1449 tr->len = 0;
1450 return ssl_send_req(obj, EVENT_TYPE_WRITE);
1451 }
1452 if (rv == 0) {
1453 obj->type = SCHED_TYPE_IO;
1454 return SCHED_CONTINUE_THIS;
1455 }
1456
1457 libarms_log(ARMS_LOG_ESSL,
1458 "%s: SSL Connection reset by peer.", tr_rsstr(tr));
1459 /* retry? */
1460 return ssl_client_retry(obj, tr);
1461 }
1462
1463 int
ssl_client_retry(struct arms_schedule * obj,transaction * tr)1464 ssl_client_retry(struct arms_schedule *obj, transaction *tr)
1465 {
1466 arms_context_t *res = arms_get_context();
1467 tr_ctx_t *tr_ctx = &tr->tr_ctx;
1468
1469 arms_tr_reset_callback_state(tr);
1470
1471 tr_ctx->write_done = 0;
1472 tr_ctx->read_done = 0;
1473 tr->len = 0;
1474 if (tr->release_data) {
1475 tr->release_data(tr);
1476 tr->release_data = NULL;
1477 }
1478 ssl_close(tr);
1479 CLOSE_FD(obj->fd);
1480
1481 if (tr_ctx->res_result >= 500 ||
1482 (tr_ctx->res_result >= 200 && tr_ctx->res_result <= 299)) {
1483 res->result = ARMS_EREBOOT;
1484 switch(tr_ctx->res_result) {
1485 case 501: /* Out of service. */
1486 res->trigger = "received 501 Out of service";
1487 res->result = ARMS_EDONTRETRY;
1488 break;
1489 case 502: /* Push failed */
1490 res->trigger = "received 502 Push failed";
1491 res->result = ARMS_EPULL;
1492 break;
1493 case 503: /* Need reboot. */
1494 res->trigger = "received 503 Need reboot";
1495 break;
1496 default:
1497 res->trigger = "got result of failure from server";
1498 break;
1499 }
1500 libarms_log(ARMS_LOG_DEBUG,
1501 "libarms got result %d from %s.",
1502 tr_ctx->res_result, tr_rsstr(tr));
1503 return SCHED_FINISHED_SCHEDULER;
1504 }
1505 #if defined(ARMS_DEBUG)
1506 libarms_log(ARMS_LOG_DEBUG,
1507 "res_result = %03d.", tr_ctx->res_result);
1508 libarms_log(ARMS_LOG_DEBUG, "retry operation start.");
1509 #endif /* defined(ARMS_DEBUG) */
1510
1511 /* failed to send request, or failed to receive response. retry? */
1512 if (TR_TYPE(tr->state) != TR_DONE &&
1513 TR_TYPE(tr->state) != TR_CONFIRM_START &&
1514 tr_ctx->pm != NULL &&
1515 tr_ctx->pm->pm_release) {
1516 /*
1517 * pull or push-method-query.
1518 * release and (re)alloc data for next URL.
1519 */
1520 tr_ctx->pm->pm_release(tr_ctx);
1521 if (tr_ctx->pm->pm_context != NULL) {
1522 tr_ctx->arg = tr_ctx->pm->pm_context(tr_ctx);
1523 }
1524 }
1525 tr->state = TR_TYPE(tr->state) | TR_REQUEST;
1526 tr->cur_uri++;
1527 if (tr->nuri > 1) {
1528 /* shift RS index only if multiple URLs are available. */
1529 tr->num = tr->num + 1 % tr->nuri;
1530 }
1531 tr_shift(tr);
1532 if (tr->cur_uri < tr->nuri &&
1533 tr->uriinfo[tr->cur_uri] != NULL) {
1534 /* try next server immediately */
1535 arms_get_time_remaining(&obj->timeout, 0);
1536 obj->type = SCHED_TYPE_EXEC;
1537 SET_NEW_METHOD(obj, ssl_req_connect);
1538 return SCHED_CONTINUE_THIS;
1539 }
1540
1541 if (TR_TYPE(tr->state) == TR_LSPULL ||
1542 TR_TYPE(tr->state) == TR_RSPULL) {
1543 /* exit immediately if method has external retry loop. */
1544 return SCHED_FINISHED_SCHEDULER;
1545 }
1546
1547 /*
1548 * tr_clean_sendbuf(tr) must not call!
1549 * Reuse prepared send buffer by retry.
1550 */
1551 /* re-setup uriinfo. */
1552 tr_clean(tr);
1553 arms_transaction_setup(tr);
1554
1555 switch (TR_TYPE(tr->state)) {
1556 case TR_CONFIRM_START:
1557 /*
1558 * parallel confirmation,
1559 * scheduler shouldn't be stopped.
1560 * only the transaction is finished.
1561 */
1562 if (res->rs_pull_1st == tr->num)
1563 res->rs_pull_1st = -1;
1564 /*FALLTHROUGH*/
1565 case TR_DONE:
1566 if (tr_ctx->pm && tr_ctx->pm->pm_rollback) {
1567 /* configure-done-req should be retry to send. */
1568 break;
1569 }
1570 /*
1571 * done-request/done-response: don't retry.
1572 * because we can't reset application state of callback.
1573 */
1574 libarms_log(ARMS_LOG_DEBUG,
1575 "transaction is aborted.");
1576 tr_remove(tr);
1577 CLOSE_FD(obj->fd);
1578 return SCHED_FINISHED_THIS;
1579 default:
1580 break;
1581 }
1582
1583 /* retry? */
1584 if (++(tr->retry) <= tr->retry_max) {
1585 libarms_log(ARMS_LOG_ITRANSACTION_RETRY,
1586 "retry %s (%d/%d), wait %d sec.",
1587 tr_msgstr(tr),
1588 tr->retry, tr->retry_max, arms_retry_wait(tr));
1589 arms_get_time_remaining(&obj->timeout,
1590 arms_retry_wait(tr));
1591 obj->type = SCHED_TYPE_EXEC;
1592 SET_NEW_METHOD(obj, ssl_req_connect);
1593 return SCHED_CONTINUE_THIS;
1594 }
1595 libarms_log(ARMS_LOG_ERETRY, "retry %s is over.", tr_msgstr(tr));
1596 /* request timeout and retry over. */
1597
1598 /*
1599 * clean send buffer because no more send data.
1600 */
1601 tr_clean_sendbuf(tr);
1602
1603 tr->retry = 0;
1604 switch (TR_TYPE(tr->state)) {
1605 case TR_METHOD_QUERY:
1606 res->trigger = "retry is over";
1607 res->result = ARMS_EPULL;
1608 return SCHED_FINISHED_SCHEDULER;
1609 case TR_DONE:
1610 if (!tr->rollbacked &&
1611 tr_ctx->pm && tr_ctx->pm->pm_rollback) {
1612 tr_ctx->pm->pm_rollback(tr);
1613 SET_TR_BUILDER(tr, http_request_builder);
1614 arms_get_time_remaining(&obj->timeout,
1615 arms_retry_wait(tr));
1616 obj->type = SCHED_TYPE_EXEC;
1617 SET_NEW_METHOD(obj, ssl_req_connect);
1618 return SCHED_CONTINUE_THIS;
1619 }
1620 if (tr->rollbacked) {
1621 /*
1622 * rollback result is timeout.
1623 * fatal. reboot.
1624 */
1625 res->trigger = "rollback failure";
1626 res->result = ARMS_EPULL;
1627 libarms_log(ARMS_LOG_EROLLBACK,
1628 "rollback failure.");
1629 return SCHED_FINISHED_SCHEDULER;
1630 }
1631 /* done-request/response is lost. ignore... */
1632 tr_remove(tr);
1633 CLOSE_FD(obj->fd);
1634 return SCHED_FINISHED_THIS;
1635 default:
1636 /*bug?*/
1637 break;
1638 }
1639 tr_remove(tr);
1640 CLOSE_FD(obj->fd);
1641 res->trigger = "retry is over";
1642 res->result = ARMS_EREBOOT;
1643 return SCHED_FINISHED_THIS;
1644 }
1645
1646 /*
1647 * call from scheduler directly.
1648 */
1649 static int
ssl_send_req(struct arms_schedule * obj,int event)1650 ssl_send_req(struct arms_schedule *obj, int event)
1651 {
1652 transaction *tr = obj->userdata;
1653 int rv;
1654
1655 if (tr == NULL) {
1656 CLOSE_FD(obj->fd);
1657 return SCHED_FINISHED_THIS;
1658 }
1659
1660 switch (event) {
1661 case EVENT_TYPE_TIMEOUT:
1662 libarms_log(ARMS_LOG_ESSL,
1663 "%s: SSL Connection timeout.", tr_rsstr(tr));
1664 return ssl_client_retry(obj, tr);
1665 case EVENT_TYPE_FINISH:
1666 goto err;
1667 case EVENT_TYPE_WRITE:
1668 case EVENT_TYPE_READ:
1669 default:
1670 break;
1671 }
1672 if (tr->builder == NULL) {
1673 /* response builder is nothing. umm, bug? */
1674 goto err;
1675 }
1676
1677 rerun:
1678 /* fill data by builder, and write. */
1679 if (tr->len > 0) {
1680 rv = TR_WANT_WRITE;
1681 } else {
1682 rv = tr->builder(tr, tr->buf, sizeof(tr->buf), &tr->len);
1683 tr->wp = tr->buf;
1684 }
1685 switch (rv) {
1686 case TR_WANT_STOP:
1687 if (TR_TYPE(tr->state) == TR_DONE)
1688 arms_set_global_state(ARMS_ST_PUSH_REBOOT);
1689 else
1690 arms_set_global_state(ARMS_ST_BOOT_FAIL);
1691
1692 return SCHED_FINISHED_SCHEDULER;
1693 case TR_WRITE_DONE:
1694 /* sent request. prepare for receive response */
1695 obj->type = SCHED_TYPE_IOR;
1696 SET_TR_PARSER(tr, http_response_parser);
1697 SET_NEW_METHOD(obj, ssl_recv_res);
1698 if (tr->state == TR_DONE_REQUEST)
1699 tr->state = TR_DONE_RESPONSE;
1700 arms_get_time_remaining(&obj->timeout, 30);
1701 return SCHED_CONTINUE_THIS;
1702 case TR_WANT_WRITE:
1703 if (tr->len == 0) {
1704 /* if tr->builder return 0 bytes data */
1705 goto rerun;
1706 }
1707 do {
1708 rv = arms_ssl_write(tr->ssl, tr->wp, tr->len);
1709 if (rv > 0) {
1710 arms_get_time_remaining(&obj->timeout, 30);
1711 tr->wp += rv;
1712 tr->len -= rv;
1713 /*refill or send */
1714 }
1715 } while (tr->len > 0 && rv > 0);
1716 if (tr->len == 0) {
1717 /* all data sent. refill */
1718 goto rerun;
1719 }
1720 if (rv >= 0) {
1721 /* no error. */
1722 return SCHED_CONTINUE_THIS;
1723 }
1724 switch (SSL_get_error(tr->ssl, rv)) {
1725 case SSL_ERROR_NONE:
1726 case SSL_ERROR_WANT_WRITE:
1727 case SSL_ERROR_WANT_READ:
1728 return SCHED_CONTINUE_THIS;
1729
1730 case SSL_ERROR_ZERO_RETURN:
1731 /* peer connection has been closed */
1732 default:
1733 return ssl_client_retry(obj, tr);
1734 }
1735 break;
1736 case TR_FATAL_ERROR:
1737 libarms_log(ARMS_LOG_EFATAL,
1738 "fatal error from internal routine");
1739 return SCHED_FINISHED_SCHEDULER;
1740 break;
1741 default:
1742 break;
1743 }
1744 err:
1745 tr_remove(tr);
1746 CLOSE_FD(obj->fd);
1747 return SCHED_FINISHED_THIS;
1748 }
1749
1750 /*
1751 * called from scheduler directly.
1752 */
1753 static int
ssl_recv_res(struct arms_schedule * obj,int event)1754 ssl_recv_res(struct arms_schedule *obj, int event)
1755 {
1756 transaction *tr = obj->userdata;
1757 arms_context_t *res = arms_get_context();
1758 tr_ctx_t *tr_ctx = &tr->tr_ctx;
1759 int nrs;
1760
1761 if (tr == NULL) {
1762 CLOSE_FD(obj->fd);
1763 return SCHED_FINISHED_THIS;
1764 }
1765
1766 switch (event) {
1767 case EVENT_TYPE_READ:
1768 break;
1769 case EVENT_TYPE_WRITE:
1770 break;
1771 case EVENT_TYPE_TIMEOUT:
1772 SET_TR_BUILDER(tr, http_request_builder);
1773 return ssl_client_retry(obj, tr);
1774 case EVENT_TYPE_FINISH:
1775 goto err;
1776 default:
1777 break;
1778 }
1779 if (tr->parser == NULL) {
1780 /* request parser is nothing. umm, bug? */
1781 goto err;
1782 }
1783
1784 rerun:
1785 if ((tr->len = arms_ssl_read(tr->ssl, tr->buf, sizeof(tr->buf))) > 0) {
1786 tr->zero = 0;
1787 /* read partly. call parser. */
1788 switch (tr->parser(tr, tr->buf, tr->len)) {
1789 case TR_WANT_READ:
1790 if (SSL_pending(tr->ssl) > 0)
1791 goto rerun;
1792 return SCHED_CONTINUE_THIS;
1793
1794 case TR_WANT_STOP:
1795 /*
1796 * send push-ready immediately if result == ARMS_EPUSH.
1797 * global state is unchanged in this case.
1798 */
1799 if (res->result != ARMS_EPUSH) {
1800 if (TR_TYPE(tr->state) == TR_DONE) {
1801 arms_set_global_state(ARMS_ST_PUSH_REBOOT);
1802 } else {
1803 arms_set_global_state(ARMS_ST_BOOT_FAIL);
1804 res->trigger = "boot failed";
1805 }
1806 }
1807 /* after return, killed by EVENT_TYPE_FINISH */
1808 return SCHED_FINISHED_SCHEDULER;
1809
1810 case TR_WANT_ROLLBACK:
1811 ssl_close(tr);
1812 CLOSE_FD(obj->fd);
1813 tr_clean(tr);
1814 tr_clean_sendbuf(tr);
1815 if (!tr->rollbacked &&
1816 tr_ctx->pm &&
1817 tr_ctx->pm->pm_rollback != NULL &&
1818 tr_ctx->pm->pm_rollback(tr) == 0) {
1819 SET_TR_BUILDER(tr, http_request_builder);
1820 arms_get_time_remaining(&obj->timeout,
1821 arms_retry_wait(tr));
1822 obj->type = SCHED_TYPE_TIMER;
1823 SET_NEW_METHOD(obj, ssl_req_connect);
1824 return SCHED_CONTINUE_THIS;
1825 }
1826 if (tr->rollbacked) {
1827 /*
1828 * rollback result is timeout.
1829 * fatal. reboot.
1830 */
1831 res->trigger = "rollback failure";
1832 res->result = ARMS_EPULL;
1833 libarms_log(ARMS_LOG_EROLLBACK,
1834 "rollback failure.");
1835 return SCHED_FINISHED_SCHEDULER;
1836 }
1837 /* done-request/response is lost. ignore... */
1838 /*goto err;*/
1839 break;
1840
1841 case TR_HTTP_AUTH_ERROR:
1842 case TR_PARSE_ERROR:
1843 case TR_WANT_RETRY:
1844 return ssl_client_retry(obj, tr);
1845
1846 case TR_READ_DONE:
1847 /*
1848 * response is received.
1849 */
1850 switch (TR_TYPE(tr->state)) {
1851 case TR_LSPULL:
1852 res->result = 0;
1853 /* after return, killed by EVENT_TYPE_FINISH */
1854 return SCHED_FINISHED_SCHEDULER;
1855
1856 case TR_RSPULL:
1857 /* make URL for push-ready */
1858 strlcpy(res->rs_endpoint,
1859 tr->uriinfo[tr->cur_uri],
1860 sizeof(res->rs_endpoint));
1861 libarms_log(ARMS_LOG_DEBUG,
1862 "RS End point: %s", res->rs_endpoint);
1863 res->result = 0;
1864 /* after return, killed by EVENT_TYPE_FINISH */
1865 return SCHED_FINISHED_SCHEDULER;
1866
1867 case TR_PUSH_READY:
1868 tr->state = TR_PUSH_WAIT;
1869 libarms_log(ARMS_LOG_IPROTO_CONFIRM_DONE,
1870 "Done push confirmation");
1871 arms_set_global_state(ARMS_ST_PUSH_WAIT);
1872 res->result = 0;
1873 /* after return, killed by EVENT_TYPE_FINISH */
1874 return SCHED_FINISHED_SCHEDULER;
1875 case TR_METHOD_QUERY:
1876 res->rs_pull_1st = tr->num;
1877 /*FALLTHROUGH*/
1878 case TR_CONFIRM_START:
1879 if (res->rs_pull_1st == -1)
1880 res->rs_pull_1st = tr->num;
1881 /* calc number of RS. */
1882 for (nrs = 0; nrs < MAX_RS_INFO; nrs++) {
1883 if (res->rs_pull_url[nrs] == NULL) {
1884 /* no more RS. */
1885 break;
1886 }
1887 }
1888 if (res->rs_pull_1st == tr->num &&
1889 nrs == acmi_get_num_server(res->acmi, ACMI_CONFIG_CONFSOL)) {
1890 /* feedback for conf-sol. */
1891 acmi_set_current_server(res->acmi, ACMI_CONFIG_CONFSOL, tr->num);
1892 }
1893 /*FALLTHROUGH*/
1894 default:
1895 break;
1896 }
1897 /* goto err; */
1898 break;
1899
1900 case TR_FATAL_ERROR:
1901 break;
1902 }
1903 } else if (tr->len == 0) {
1904 return SCHED_CONTINUE_THIS;
1905 /*NOTREACHED*/
1906 } else {
1907 return ssl_client_retry(obj, tr);
1908 /*NOTREACHED*/
1909 }
1910 err:
1911 tr_remove(tr);
1912 CLOSE_FD(obj->fd);
1913 return SCHED_FINISHED_THIS;
1914 }
1915