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