Changeset 2ea77243f4b484e20c2101cda30ec9fa0e30ea7b
- Timestamp:
- 09/12/09 00:10:24 (4 years ago)
- git-parent:
- Files:
-
- configure.in (modified) (1 diff)
- src/Makefile.in (modified) (5 diffs)
- src/modules/Makefile.in (modified) (2 diffs)
- src/modules/http.c (modified) (24 diffs)
- src/stomp/Makefile.in (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
configure.in
r4d8986f r2ea7724 290 290 291 291 APRPREFIX="`apr-1-config --prefix`" 292 AC_MSG_CHECKING([libserf cflags])293 292 AC_SUBST(APRPREFIX) 294 293 AC_MSG_RESULT([$APRPREFIX]) 295 294 296 AC_MSG_CHECKING([libserf cflags]) 297 SERFCFLAGS="`apr-1-config --cflags --cppflags`" 298 SERFCFLAGS="$SERFCFLAGS -I`apu-1-config --includedir` -I`apr-1-config --includedir`" 299 AC_SUBST(SERFCFLAGS) 300 AC_MSG_RESULT([$SERFCFLAGS]) 301 302 AC_MSG_CHECKING([libserf libs]) 303 SERFLIBS="`apu-1-config --link-ld --ldflags --libs` `apr-1-config --link-ld --ldflags --libs`" 304 AC_SUBST(SERFLIBS) 305 AC_MSG_RESULT([$SERFLIBS]) 295 AC_MSG_CHECKING([libapr cflags]) 296 APRCFLAGS="`apr-1-config --cflags --cppflags --includes`" 297 AC_SUBST(APRCFLAGS) 298 AC_MSG_RESULT([$APRCFLAGS]) 299 300 AC_MSG_CHECKING([libapr libs]) 301 APRLIBS="`apr-1-config --link-ld --ldflags --libs`" 302 AC_SUBST(APRLIBS) 303 AC_MSG_RESULT([$APRLIBS]) 304 305 AC_MSG_CHECKING([libcurl cflags]) 306 CURLCFLAGS="`curl-config --cflags`" 307 AC_SUBST(CURLCFLAGS) 308 AC_MSG_RESULT([$CURLCFLAGS]) 309 310 AC_MSG_CHECKING([libcurl libs]) 311 CURLLIBS="`curl-config --libs`" 312 AC_SUBST(CURLLIBS) 313 AC_MSG_RESULT([$CURLLIBS]) 306 314 307 315 AC_TRY_LINK([], src/Makefile.in
r7e47bd8 r2ea7724 53 53 all: noitd stratcond noit.conf test-noit.conf stratcon.conf test-stratcon.conf 54 54 55 make-subdirs: serf/.libs/libserf-0.ojlog/libjlog.a55 make-subdirs: jlog/libjlog.a 56 56 @for dir in $(SUBS) ; do \ 57 57 echo "- building $$dir bits" ; \ … … 65 65 jlog/libjlog.a: 66 66 @(cd jlog && make libjlog.a) 67 68 serf/.libs/libserf-0.a:69 @(cd serf && \70 env \71 CFLAGS="$(CFLAGS)" \72 LDFLAGS="$(LDFLAGS)" \73 python serfmake build --with-apr=@APRPREFIX@)74 75 serf/.libs/libserf-0.o: serf/.libs/libserf-0.a76 @ld -r -o serf/.libs/libserf-0.o \77 serf/.libs/context.o serf/.libs/outgoing.o \78 serf/.libs/incoming.o serf/buckets/.libs/*.o79 67 80 68 noitd: make-subdirs $(NOIT_OBJS) … … 102 90 -Lstomp -lstomp \ 103 91 $(NOWHOLE_ARCHIVE) \ 104 $(LIBS) $(PGLIBS) @ SERFLIBS@92 $(LIBS) $(PGLIBS) @APRLIBS@ 105 93 @echo "- linking $@" 106 94 … … 110 98 111 99 stratcon_iep.o: stratcon_iep.c 112 @$(CC) $(CPPFLAGS) $(CFLAGS) @ SERFCFLAGS@ -c $<100 @$(CC) $(CPPFLAGS) $(CFLAGS) @APRCFLAGS@ -c $< 113 101 @echo "- compiling $<" 114 102 … … 193 181 clean: clean-subdirs 194 182 rm -f *.o noitd 195 rm serf/.libs/libserf-0.a serf/.libs/libserf-0.ojlog/libjlog.a183 rm jlog/libjlog.a 196 184 (cd jlog && make clean) 197 (cd serf && \198 env \199 CFLAGS="$(CFLAGS)" \200 LDFLAGS="$(LDFLAGS)" \201 python serfmake clean)202 185 src/modules/Makefile.in
r36b6874 r2ea7724 49 49 50 50 postgres.@MODULEEXT@: postgres.lo 51 @$(MODULELD) $(LDFLAGS) -o $@ postgres.lo @SERFLIBS@$(PGLIBS) -lz -lssl -lcrypto51 @$(MODULELD) $(LDFLAGS) -o $@ postgres.lo $(PGLIBS) -lz -lssl -lcrypto 52 52 @echo "- linking $@" 53 53 … … 73 73 74 74 http.@MODULEEXT@: http.lo 75 @$(MODULELD) $(LDFLAGS) -o $@ http.lo @ SERFLIBS@ ../serf/.libs/libserf-0.o-lz -lssl -lcrypto75 @$(MODULELD) $(LDFLAGS) -o $@ http.lo @CURLLIBS@ -lz -lssl -lcrypto 76 76 @echo "- linking $@" 77 77 78 78 http.lo: http.c http.xmlh resmon.xmlh resmon_part.xmlh 79 @$(CC) $(CPPFLAGS) $(SHCFLAGS) -I$(top_srcdir)/src/serf @SERFCFLAGS@ -c http.c -o $@79 @$(CC) $(CPPFLAGS) $(SHCFLAGS) @CURLCFLAGS@ -c http.c -o $@ 80 80 @echo "- compiling $<" 81 81 src/modules/http.c
r1c3b685 r2ea7724 38 38 #include <assert.h> 39 39 #include <math.h> 40 #include <ctype.h> 40 41 41 42 #include <pcre.h> … … 44 45 #include <libxml/tree.h> 45 46 #include <libxml/xpath.h> 47 #include <libxml/uri.h> 46 48 47 49 #include "noit_module.h" … … 51 53 #include "utils/noit_hash.h" 52 54 53 #include <apr_uri.h> 54 #include <apr_atomic.h> 55 #include <apr_strings.h> 56 #include <apr_portable.h> 57 #include "serf.h" 55 #include <curl/curl.h> 58 56 59 57 #define NOIT_HTTP_VERSION_STRING "0.1" … … 62 60 noit_hash_table *options; 63 61 void (*results)(noit_module_t *, noit_check_t *); 64 } serf_module_conf_t; 65 66 typedef struct { 67 int using_ssl; 68 const char *ca_chain_file; 69 const char *certificate_file; 70 serf_ssl_context_t *ssl_ctx; 71 serf_bucket_alloc_t *bkt_alloc; 72 } app_baton_t; 73 74 typedef struct { 75 serf_response_acceptor_t acceptor; 76 app_baton_t *acceptor_baton; 77 78 serf_response_handler_t handler; 79 const char *host; 80 const char *method; 81 const char *path; 82 const char *authn; 83 84 noit_module_t *self; 85 noit_check_t *check; 86 } handler_baton_t; 62 } http_module_conf_t; 87 63 88 64 typedef struct buf_t { … … 91 67 } buf_t; 92 68 69 /* pqTODO: directly copied from serf_bucket_types.h */ 70 #define HTTP_VERSION(major, minor) ((major) * 1000 + (minor)) 71 #define HTTP_11 HTTP_VERSION(1, 1) 72 #define HTTP_10 HTTP_VERSION(1, 0) 73 93 74 typedef struct { 94 apr_pool_t *pool; 95 apr_sockaddr_t *address; 96 serf_context_t *context; 97 serf_connection_t *connection; 98 serf_request_t *request; 99 app_baton_t app_ctx; 100 handler_baton_t handler_ctx; 101 apr_uri_t url; 75 int version; 76 int code; 77 char *reason; 78 } http_status_line; 79 80 typedef struct { 81 struct curl_slist *cheaders; 82 CURL *curl; 83 CURLM *mcurl; 102 84 int timed_out; 103 85 104 serf_status_line status;86 xmlURIPtr url; 105 87 buf_t headers; 106 88 buf_t body; … … 109 91 eventer_t fd_event; 110 92 eventer_t timeout_event; 111 } serf_check_info_t; 93 eventer_t process_event; 94 eventer_t done_event; 95 96 noit_module_t *self; 97 noit_check_t *check; 98 99 http_status_line status; 100 int inside_handler; 101 } http_check_info_t; 112 102 113 103 typedef struct { 114 serf_check_info_t serf;104 http_check_info_t http; 115 105 struct timeval xml_doc_time; 116 106 char *xpathexpr; … … 120 110 } resmon_check_info_t; 121 111 122 typedef struct {123 noit_module_t *self;124 noit_check_t *check;125 void *serf_baton;126 apr_socket_t *skt;127 } serf_closure_t;128 129 112 static noit_log_stream_t nlerr = NULL; 130 113 static noit_log_stream_t nldeb = NULL; 131 static int serf_handler(eventer_t e, int mask, void *closure,132 struct timeval *now);133 static void serf_log_results(noit_module_t *self, noit_check_t *check);114 static void http_eventer_free(eventer_t e, http_check_info_t *ci); 115 static int http_consume_messages(http_check_info_t *ci); 116 static void http_log_results(noit_module_t *self, noit_check_t *check); 134 117 static void resmon_log_results(noit_module_t *self, noit_check_t *check); 135 118 static void resmon_part_log_results(noit_module_t *self, noit_check_t *check, 136 119 noit_check_t *parent); 137 120 138 static int serf_config(noit_module_t *self, noit_hash_table *options) {139 serf_module_conf_t *conf;121 static int http_config(noit_module_t *self, noit_hash_table *options) { 122 http_module_conf_t *conf; 140 123 conf = noit_module_get_userdata(self); 141 124 if(conf) { … … 148 131 conf = calloc(1, sizeof(*conf)); 149 132 conf->options = options; 150 conf->results = serf_log_results;133 conf->results = http_log_results; 151 134 noit_module_set_userdata(self, conf); 152 135 return 1; 153 136 } 154 137 static int resmon_config(noit_module_t *self, noit_hash_table *options) { 155 serf_module_conf_t *conf;138 http_module_conf_t *conf; 156 139 conf = noit_module_get_userdata(self); 157 140 if(conf) { … … 171 154 return 1; 172 155 } 156 173 157 static void generic_log_results(noit_module_t *self, noit_check_t *check) { 174 serf_module_conf_t *module_conf; 175 module_conf = noit_module_get_userdata(self); 176 module_conf->results(self, check); 177 } 178 static void serf_log_results(noit_module_t *self, noit_check_t *check) { 179 serf_check_info_t *ci = check->closure; 158 http_module_conf_t *conf; 159 conf = noit_module_get_userdata(self); 160 conf->results(self, check); 161 } 162 163 static void http_log_results(noit_module_t *self, noit_check_t *check) { 164 http_check_info_t *ci = check->closure; 180 165 struct timeval duration; 181 166 stats_t current; … … 199 184 noitL(nlerr, "http code match /%s/ failed @ %d: %s\n", (char *)code_str, 200 185 erroffset, error); 201 186 202 187 if(noit_hash_retrieve(check->config, "body", strlen("body"), &body_str)) { 203 188 body_match = pcre_compile((const char *)body_str, 0, … … 265 250 noit_check_t *check, 266 251 xmlDocPtr xml) { 267 serf_check_info_t *ci = check->closure;268 252 resmon_check_info_t *rci = check->closure; 253 http_check_info_t *ci = &rci->http; 269 254 xmlXPathContextPtr xpath_ctxt = NULL; 270 255 stats_t current; … … 306 291 } 307 292 } 308 memcpy(¤t.whence, & rci->serf.finish_time, sizeof(current.whence));293 memcpy(¤t.whence, &ci->finish_time, sizeof(current.whence)); 309 294 current.status = current.status ? current.status : strdup("unknown"); 310 295 noitL(nldeb, "resmon_part(%s/%s/%s) [%s]\n", check->target, … … 319 304 } 320 305 static void resmon_log_results(noit_module_t *self, noit_check_t *check) { 321 serf_check_info_t *ci = check->closure;322 306 resmon_check_info_t *rci = check->closure; 307 http_check_info_t *ci = &rci->http; 323 308 struct timeval duration; 324 309 stats_t current; … … 433 418 if(xpath_ctxt) xmlXPathFreeContext(xpath_ctxt); 434 419 } 435 static void serf_cleanup(noit_module_t *self, noit_check_t *check) { 436 serf_check_info_t *ci; 420 421 static void http_cleanup_check(noit_module_t *self, noit_check_t *check) { 422 http_check_info_t *ci; 437 423 ci = check->closure; 438 if(ci->connection) { 439 serf_connection_close(ci->connection); 440 ci->connection = NULL; 441 } 424 noitL(nldeb, "http_cleanup_check(%p)\n", ci); 425 if (ci->curl) { 426 if (ci->mcurl) { 427 curl_multi_remove_handle(ci->mcurl, ci->curl); 428 } 429 curl_easy_cleanup(ci->curl); 430 ci->curl = NULL; 431 } 432 433 if (ci->mcurl) { 434 curl_multi_cleanup(ci->mcurl); 435 ci->mcurl = NULL; 436 } 437 438 if (ci->cheaders) { 439 curl_slist_free_all(ci->cheaders); 440 ci->cheaders = NULL; 441 } 442 442 443 if(ci->fd_event) { 443 eventer_remove_fd(ci->fd_event->fd); 444 eventer_free(ci->fd_event); 444 http_eventer_free(eventer_remove_fd(ci->fd_event->fd), ci); 445 445 ci->fd_event = NULL; 446 446 } 447 448 if(ci->process_event) { 449 http_eventer_free(eventer_remove_recurrent(ci->process_event), ci); 450 ci->process_event = NULL; 451 } 452 453 if (ci->status.reason) { 454 free(ci->status.reason); 455 ci->status.reason = NULL; 456 } 457 458 ci->check->flags &= ~NP_RUNNING; 447 459 ci->timeout_event = NULL; 448 if(ci->pool) apr_pool_destroy(ci->pool); 460 free(ci->body.b); 461 free(ci->headers.b); 449 462 memset(ci, 0, sizeof(*ci)); 450 463 } 451 static int serf_complete(eventer_t e, int mask, 452 void *closure, struct timeval *now) { 453 serf_closure_t *ccl = (serf_closure_t *)closure; 454 455 noitLT(nldeb, now, "serf_complete(%s)\n", ccl->check->target); 456 if(!NOIT_CHECK_DISABLED(ccl->check) && !NOIT_CHECK_KILLED(ccl->check)) { 457 serf_check_info_t *ci = ccl->check->closure; 458 if(ci->finish_time.tv_sec == 0 && ci->finish_time.tv_usec == 0) 459 memcpy(&ci->finish_time, now, sizeof(*now)); 460 generic_log_results(ccl->self, ccl->check); 461 } 462 serf_cleanup(ccl->self, ccl->check); 463 ccl->check->flags &= ~NP_RUNNING; 464 free(ccl); 465 return 0; 466 } 467 468 static int serf_handler(eventer_t e, int mask, 469 void *closure, struct timeval *now) { 470 apr_pollfd_t desc = { 0 }; 471 serf_closure_t *sct = closure; 472 serf_check_info_t *ci = sct->check->closure; 473 474 desc.desc_type = APR_POLL_SOCKET; 475 desc.desc.s = sct->skt; 476 477 desc.rtnevents = 0; 478 if(mask & EVENTER_READ) desc.rtnevents |= APR_POLLIN; 479 if(mask & EVENTER_WRITE) desc.rtnevents |= APR_POLLOUT; 480 if(mask & EVENTER_EXCEPTION) desc.rtnevents |= APR_POLLERR; 481 noitL(nldeb, "serf_handler() => %d, %x [%c%c%c]\n", 482 e->fd, desc.rtnevents, 483 (desc.rtnevents & APR_POLLIN) ? 'I' : '-', 484 (desc.rtnevents & APR_POLLOUT) ? 'O' : '-', 485 (desc.rtnevents & APR_POLLERR) ? 'E' : '-'); 486 serf_event_trigger(ci->context, sct->serf_baton, &desc); 487 serf_context_prerun(ci->context); 488 489 /* We're about to deschedule and free the event, drop our reference */ 490 if(!e->mask) 491 ci->fd_event = NULL; 492 493 return e->mask; 494 } 495 496 static int serf_init(noit_module_t *self) { 497 return 0; 498 } 499 static void closed_connection(serf_connection_t *conn, 500 void *closed_baton, 501 apr_status_t why, 502 apr_pool_t *pool) { 503 } 504 static apr_status_t need_client_cert(void *data, 505 const char **path) { 506 app_baton_t *ctx = data; 507 *path = ctx->certificate_file; 508 return APR_SUCCESS; 509 } 510 static apr_status_t need_server_cert(void *data, 511 int failures, 512 const serf_ssl_certificate_t *cert) { 513 return APR_SUCCESS; 514 } 515 static apr_status_t conn_setup(apr_socket_t *skt, 516 serf_bucket_t **input_bkt, 517 serf_bucket_t **output_bkt, 518 void *setup_baton, 519 apr_pool_t *pool) 520 { 521 serf_bucket_t *c; 522 app_baton_t *ctx = setup_baton; 523 524 c = serf_bucket_socket_create(skt, ctx->bkt_alloc); 525 if (ctx->using_ssl) { 526 c = serf_bucket_ssl_decrypt_create(c, ctx->ssl_ctx, ctx->bkt_alloc); 527 if (!ctx->ssl_ctx) { 528 serf_ssl_certificate_t *cert; 529 ctx->ssl_ctx = serf_bucket_ssl_decrypt_context_get(c); 530 531 /* Setup CA chain */ 532 if(ctx->ca_chain_file && 533 serf_ssl_load_cert_file(&cert, ctx->ca_chain_file, 534 pool) != APR_SUCCESS) 535 serf_ssl_trust_cert(ctx->ssl_ctx, cert); 536 else 537 serf_ssl_use_default_certificates(ctx->ssl_ctx); 538 539 /* Setup client cert */ 540 serf_ssl_client_cert_provider_set(ctx->ssl_ctx, need_client_cert, 541 ctx, pool); 542 } 543 serf_ssl_server_cert_callback_set(ctx->ssl_ctx, need_server_cert, 544 ctx); 545 *output_bkt = serf_bucket_ssl_encrypt_create(*output_bkt, ctx->ssl_ctx, 546 ctx->bkt_alloc); 547 } 548 *input_bkt = c; 549 550 return APR_SUCCESS; 551 } 552 553 static serf_bucket_t* accept_response(serf_request_t *request, 554 serf_bucket_t *stream, 555 void *acceptor_baton, 556 apr_pool_t *pool) { 557 serf_bucket_t *c; 558 serf_bucket_alloc_t *bkt_alloc; 559 560 /* get the per-request bucket allocator */ 561 bkt_alloc = serf_request_get_alloc(request); 562 563 /* Create a barrier so the response doesn't eat us! */ 564 c = serf_bucket_barrier_create(stream, bkt_alloc); 565 566 return serf_bucket_response_create(c, bkt_alloc); 567 } 568 569 static void append_buf(apr_pool_t *p, buf_t *b, 464 465 466 static int http_init(noit_module_t *self) { 467 return 0; 468 } 469 470 static void append_buf(buf_t *b, 570 471 const char *data, int len) { 571 char *n; 572 n = apr_palloc(p, b->l + len + 1); 573 if(b->l == 0) 574 b->b = n; 575 else { 576 memcpy(n, b->b, b->l); 577 b->b = n; 578 } 472 //noitL(nldeb, "append_buf(%p, %d)\n", b, len); 473 b->b = realloc(b->l == 0 ? NULL : b->b, b->l + len + 1); 579 474 memcpy(b->b + b->l, data, len); 580 475 b->l += len; … … 582 477 } 583 478 584 static apr_status_t handle_response(serf_request_t *request, 585 serf_bucket_t *response, 586 void *handler_baton, 587 apr_pool_t *pool){588 const char *data;589 apr_size_t len;590 apr_status_t status;591 handler_baton_t *ctx = handler_baton;592 serf_check_info_t *ci = ctx->check->closure;593 594 if(response == NULL) {595 /* We were cancelled. */596 goto finish; 597 } 598 status = serf_bucket_response_status(response, &ci->status); 599 if (status) { 600 if (APR_STATUS_IS_EAGAIN(status)){601 return status;602 }603 goto finish;604 }605 606 while (1) {607 status = serf_bucket_read(response, 1024*32, &data, &len);608 if (SERF_BUCKET_READ_ERROR(status)) 609 return status;610 611 append_buf(ci->pool, &ci->body, data, len);612 613 /* are we done yet? */614 if (APR_STATUS_IS_EOF(status)) {615 serf_bucket_t *hdrs;616 hdrs = serf_bucket_response_get_headers(response);617 while (1) {618 status = serf_bucket_read(hdrs, 2048, &data, &len);619 if (SERF_BUCKET_READ_ERROR(status))620 return status;621 622 append_buf(ci->pool, &ci->headers, data, len);623 if ( APR_STATUS_IS_EOF(status)) {624 break;479 #define BODY_MAX_SIZE 1024 * 512 480 481 static size_t http_write_data( void *ptr, size_t size, size_t nmemb, void *baton) 482 { 483 http_check_info_t *ci = baton; 484 size_t len = size * nmemb; 485 size_t used = MIN(BODY_MAX_SIZE - ci->body.l, len); 486 noitL(nldeb, "http_write_data(%p, %d)\n", ci, (int)used); 487 if (used != 0) { 488 append_buf(&ci->body, ptr, used); 489 } 490 return used; 491 } 492 493 494 static size_t http_write_headers( void *ptr, size_t size, size_t nmemb, void *baton) 495 { 496 http_check_info_t *ci = baton; 497 size_t len = size * nmemb; 498 size_t used = MIN(BODY_MAX_SIZE - ci->headers.l, len); 499 noitL(nldeb, "http_write_headers(%p, %d)\n", ci, (int)used); 500 if (used != 0) { 501 append_buf(&ci->headers, ptr, used); 502 } 503 504 if (ci->status.code == 0) { 505 /* HTTP/1.1 200 OK */ 506 if (ci->headers.l > strlen("HTTP/#.# ###")) { 507 char *p = NULL; 508 ci->status.version = HTTP_VERSION(ci->headers.b[5] - '0', ci->headers.b[7] - '0'); 509 if (ci->status.version != HTTP_11 && ci->status.version != HTTP_10) { 510 /* TODO: log error*/ 511 noitL(nldeb, "http_write_headers(%p) -- Invalid HTTP Version: %d\n", ci, ci->status.version); 512 return 0; 513 } 514 515 ci->status.code = strtol(ci->headers.b + 8, &p, 10); 516 if (ci->status.code != 0 && p) { 517 while (*p && isspace(*p)) p++; 518 if (*p) { 519 ci->status.reason = strdup(p); 625 520 } 626 521 } 627 628 goto finish; 629 } 630 631 /* have we drained the response so far? */ 632 if (APR_STATUS_IS_EAGAIN(status)) 633 return status; 634 635 /* loop to read some more. */ 636 } 637 finish: 638 gettimeofday(&ci->finish_time, NULL); 639 noitL(nldeb, "serf finished request (%s) [%ld.%06d]\n", ctx->check->target, 640 (long int)ci->finish_time.tv_sec, (int)ci->finish_time.tv_usec); 641 if(ci->timeout_event) { 642 eventer_remove(ci->timeout_event); 643 ci->timed_out = 0; 644 memcpy(&ci->timeout_event->whence, &ci->finish_time, 645 sizeof(ci->finish_time)); 646 eventer_add(ci->timeout_event); 647 } 648 return APR_EOF; 649 } 650 651 static apr_status_t setup_request(serf_request_t *request, 652 void *setup_baton, 653 serf_bucket_t **req_bkt, 654 serf_response_acceptor_t *acceptor, void **acceptor_baton, 655 serf_response_handler_t *handler, 656 void **handler_baton, 657 apr_pool_t *pool) { 658 handler_baton_t *ctx = setup_baton; 659 serf_bucket_t *hdrs_bkt; 660 serf_bucket_t *body_bkt; 661 662 body_bkt = NULL; 663 664 *req_bkt = serf_bucket_request_create(ctx->method, ctx->path, body_bkt, 665 serf_request_get_alloc(request)); 666 667 hdrs_bkt = serf_bucket_request_get_headers(*req_bkt); 668 669 serf_bucket_headers_setn(hdrs_bkt, "Host", ctx->host); 670 serf_bucket_headers_setn(hdrs_bkt, "User-Agent", 671 "Noit/" NOIT_HTTP_VERSION_STRING); 672 /* Shouldn't serf do this for us? */ 673 serf_bucket_headers_setn(hdrs_bkt, "Accept-Encoding", "gzip"); 674 675 if (ctx->authn != NULL) { 676 serf_bucket_headers_setn(hdrs_bkt, "Authorization", ctx->authn); 677 } 678 679 *acceptor = ctx->acceptor; 680 *acceptor_baton = ctx->acceptor_baton; 681 *handler = ctx->handler; 682 *handler_baton = ctx; 683 684 return APR_SUCCESS; 685 } 686 687 static apr_status_t serf_eventer_add(void *user_baton, 688 apr_pollfd_t *pfd, 689 void *serf_baton) { 690 eventer_t e, newe = NULL; 691 serf_closure_t *sct = user_baton, *newsct; 692 assert(pfd->desc_type == APR_POLL_SOCKET); 693 apr_os_sock_t fd; 694 apr_os_sock_get(&fd, pfd->desc.s); 695 696 noitL(nldeb, "serf_eventer_add() => %d, %x [%c%c%c]\n", 697 fd, pfd->reqevents, 698 (pfd->reqevents & APR_POLLIN) ? 'I' : '-', 699 (pfd->reqevents & APR_POLLOUT) ? 'O' : '-', 700 (pfd->reqevents & APR_POLLERR) ? 'E' : '-'); 522 } 523 } 524 return used; 525 } 526 527 static int http_handler(eventer_t e, int mask, 528 void *closure, struct timeval *now) 529 { 530 int cmask = 0; 531 int handles = 0; 532 http_check_info_t *ci = closure; 533 534 if (!ci->curl) { 535 return 0; 536 } 537 538 if(mask & EVENTER_READ) cmask |= CURL_CSELECT_IN; 539 if(mask & EVENTER_WRITE) cmask|= CURL_CSELECT_OUT; 540 if(mask & EVENTER_EXCEPTION) cmask |= CURL_CSELECT_ERR; 541 542 ci->inside_handler = 1; 543 //noitL(nldeb, "http_handler(%p, emask=%d, cmask=%d)\n", ci, mask, cmask); 544 curl_multi_socket_action(ci->mcurl, e->fd, cmask, &handles); 545 ci->inside_handler = 0; 546 547 return e->mask; 548 } 549 550 static int http_socket_cb(CURL *_curl, curl_socket_t fd, int action, 551 void *userp, 552 void *socketp) 553 { 554 eventer_t e; 555 http_check_info_t *ci = (http_check_info_t *)userp; 556 701 557 e = eventer_find_fd(fd); 702 if(!e) { 703 newe = e = eventer_alloc(); 704 e->fd = fd; 705 e->callback = serf_handler; 706 } 707 if(!e->closure) 708 e->closure = calloc(1, sizeof(serf_closure_t)); 709 newsct = e->closure; 710 newsct->self = sct->self; 711 newsct->check = sct->check; 712 newsct->serf_baton = serf_baton; 713 newsct->skt = pfd->desc.s; 714 e->mask = 0; 715 if(pfd->reqevents & APR_POLLIN) e->mask |= EVENTER_READ; 716 if(pfd->reqevents & APR_POLLOUT) e->mask |= EVENTER_WRITE; 717 if(pfd->reqevents & APR_POLLERR) e->mask |= EVENTER_EXCEPTION; 718 if(newe) { 719 serf_check_info_t *ci = sct->check->closure; 720 eventer_add(newe); 721 ci->fd_event = newe; 722 } 723 /* ** Unneeded as this is called recursively ** 724 else 725 eventer_update(e); 726 */ 727 return APR_SUCCESS; 728 } 729 static apr_status_t serf_eventer_remove(void *user_baton, 730 apr_pollfd_t *pfd, 731 void *serf_baton) { 732 serf_closure_t *sct = user_baton; 733 serf_check_info_t *ci; 734 eventer_t e; 735 736 ci = sct->check->closure; 737 assert(pfd->desc_type == APR_POLL_SOCKET); 738 apr_os_sock_t fd; 739 apr_os_sock_get(&fd, pfd->desc.s); 740 741 noitL(nldeb, "serf_eventer_remove() => %d\n", fd); 742 e = eventer_find_fd(fd); 743 if(e) { 744 free(e->closure); 745 e->closure = NULL; 746 e->mask = 0; 747 } 748 return 0; 749 } 750 751 static int serf_initiate(noit_module_t *self, noit_check_t *check) { 752 serf_closure_t *ccl; 753 serf_check_info_t *ci; 558 switch (action) { 559 case CURL_POLL_INOUT: 560 case CURL_POLL_OUT: 561 case CURL_POLL_IN: 562 if(!e) { 563 ci->fd_event = e = eventer_alloc(); 564 e->fd = fd; 565 e->callback = http_handler; 566 e->closure = ci; 567 } 568 569 /* curl API don't have a command to look for err, but it actually 570 * does want to know if there is one! 571 */ 572 e->mask |= EVENTER_EXCEPTION; 573 if (action == CURL_POLL_INOUT) e->mask |= EVENTER_READ|EVENTER_WRITE; 574 if (action == CURL_POLL_OUT) e->mask |= EVENTER_WRITE; 575 if (action == CURL_POLL_IN) e->mask |= EVENTER_READ; 576 noitL(nldeb, "http_socket_cb(add) => %d, %x [%c%c%c]\n", 577 fd, action, 578 (e->mask & EVENTER_READ) ? 'I' : '-', 579 (e->mask & EVENTER_WRITE) ? 'O' : '-', 580 (e->mask & EVENTER_EXCEPTION) ? 'E' : '-'); 581 eventer_add(e); 582 break; 583 case CURL_POLL_REMOVE: 584 noitL(nldeb, "http_socket_cb(remove) => %d\n", fd); 585 if (e) { 586 e->closure = NULL; 587 e->mask = 0; 588 if (ci->fd_event) { 589 eventer_t te = eventer_remove_fd(ci->fd_event->fd); 590 if (te && ci->inside_handler == 0) { 591 http_eventer_free(te, ci); 592 } 593 else { 594 te->mask = 0; 595 } 596 ci->fd_event = NULL; 597 } 598 } 599 break; 600 default: 601 abort(); 602 } 603 604 return 0; 605 } 606 607 608 static int http_all_done(eventer_t e, int mask, 609 void *closure, struct timeval *now) 610 { 611 http_check_info_t *ci = closure; 612 noitL(nldeb, "http_all_done(%p)\n", ci); 613 generic_log_results(ci->self, ci->check); 614 http_cleanup_check(ci->self, ci->check); 615 return 0; 616 } 617 618 static int http_consume_messages(http_check_info_t *ci) 619 { 620 CURLMsg *msg; 621 int count; 622 623 while ((msg = curl_multi_info_read(ci->mcurl, &count)) != NULL) { 624 if (msg->msg == CURLMSG_DONE) { 625 struct timeval when; 626 long ret; 627 628 noitL(nldeb, "http_consume_messages(%p) => DONE\n", ci); 629 gettimeofday(&when, NULL); 630 memcpy(&ci->finish_time, &when, sizeof(when)); 631 curl_easy_getinfo(ci->curl, CURLINFO_RESPONSE_CODE, &ret); 632 if (ret == 0) { 633 /* no HTTP transfer took place! */ 634 ci->timed_out = 1; 635 } 636 else { 637 ci->timed_out = 0; 638 } 639 640 ci->done_event = eventer_alloc();; 641 ci->done_event->mask = EVENTER_TIMER; 642 memcpy(&ci->done_event->whence, &when, sizeof(when)); 643 ci->done_event->closure = ci; 644 ci->done_event->callback = http_all_done; 645 eventer_add(ci->done_event); 646 } 647 } 648 649 return 0; 650 } 651 652 653 static int http_recurrent(eventer_t e, int mask, 654 void *closure, struct timeval *now) 655 { 656 http_check_info_t *ci = closure; 657 http_consume_messages(ci); 658 return e->mask; 659 } 660 661 static int http_timeout(eventer_t e, int mask, 662 void *closure, struct timeval *now) 663 { 664 int cc; 665 int handles = 0; 666 http_check_info_t *ci = closure; 667 668 if (ci->mcurl == NULL) { 669 ci->timeout_event = NULL; 670 return 0; 671 } 672 673 noitL(nldeb, "http_timeout(%p)\n", ci); 674 675 do { 676 cc = curl_multi_socket(ci->mcurl, CURL_SOCKET_TIMEOUT, &handles); 677 } while(cc == CURLM_CALL_MULTI_PERFORM && handles != 0); 678 679 ci->timeout_event = NULL; 680 return 0; 681 } 682 683 static int http_set_timeout_cb(CURLM *_curlm, long timeoutms, void *closure) 684 { 754 685 struct timeval when, p_int; 755 apr_status_t status; 756 eventer_t newe; 757 serf_module_conf_t *mod_config; 686 http_check_info_t *ci = closure; 687 688 noitL(nldeb, "http_set_timeout_cb(%p, %d)\n", ci, (int)timeoutms); 689 690 if (ci->timeout_event != NULL) { 691 http_eventer_free(eventer_remove(ci->timeout_event), ci); 692 ci->timeout_event = NULL; 693 } 694 695 ci->timeout_event = eventer_alloc(); 696 ci->timeout_event->mask = EVENTER_TIMER; 697 gettimeofday(&when, NULL); 698 p_int.tv_sec = timeoutms / 1000; 699 p_int.tv_usec = (timeoutms % 1000) * 1000; 700 add_timeval(when, p_int, &ci->timeout_event->whence); 701 ci->timeout_event->closure = ci; 702 ci->timeout_event->callback = http_timeout; 703 eventer_add(ci->timeout_event); 704 705 return 0; 706 } 707 708 static int http_initiate(noit_module_t *self, noit_check_t *check) { 709 char buf[1024]; 710 struct timeval when; 711 http_check_info_t *ci; 712 http_module_conf_t *mod_config; 758 713 void *config_url; 714 char *urlstr; 759 715 760 716 mod_config = noit_module_get_userdata(self); 761 ci = ( serf_check_info_t *)check->closure;717 ci = (http_check_info_t *)check->closure; 762 718 /* We cannot be running */ 763 assert(!(check->flags & NP_RUNNING)); 719 if (check->flags & NP_RUNNING) { 720 generic_log_results(ci->self, ci->check); 721 http_cleanup_check(ci->self, ci->check); 722 assert(!(check->flags & NP_RUNNING)); 723 } 764 724 check->flags |= NP_RUNNING; 765 noitL(nldeb, "serf_initiate(%p,%s)\n",766 self, check->target);767 725 768 726 /* remove a timeout if we still have one -- we should unless someone … … 771 729 ci->timed_out = 1; 772 730 if(ci->timeout_event) { 773 eventer_remove(ci->timeout_event); 774 free(ci->timeout_event->closure); 775 eventer_free(ci->timeout_event); 731 http_eventer_free(eventer_remove(ci->timeout_event), ci); 776 732 ci->timeout_event = NULL; 777 733 } 778 assert(!ci->pool);779 apr_pool_create(&ci->pool, NULL);780 apr_atomic_init(ci->pool);781 734 782 735 gettimeofday(&when, NULL); … … 784 737 ci->finish_time.tv_sec = ci->finish_time.tv_usec = 0L; 785 738 786 ccl = apr_pcalloc(ci->pool, sizeof(*ccl)); 787 ccl->self = self; 788 ccl->check = check; 789 790 if(!noit_hash_retrieve(check->config, "url", strlen("url"), &config_url)) 739 ci->self = self; 740 ci->check = check; 741 742 if(!noit_hash_retrieve(check->config, "url", strlen("url"), &config_url)) { 791 743 if(!mod_config->options || 792 744 !noit_hash_retrieve(mod_config->options, "url", strlen("url"), 793 &config_url)) 745 &config_url)) { 794 746 config_url = "http://localhost/"; 795 apr_uri_parse(ci->pool, config_url, &ci->url); 796 797 if (!ci->url.port) { 798 ci->url.port = apr_uri_port_of_scheme(ci->url.scheme); 799 } 800 if (!ci->url.path) { 801 ci->url.path = "/"; 802 } 803 804 if (strcasecmp(ci->url.scheme, "https") == 0) { 747 } 748 } 749 750 ci->url = xmlParseURI(config_url); 751 752 if (!ci->url->scheme) { 753 ci->url->scheme = strdup("http"); 754 } 755 756 if (!ci->url->port) { 757 if (strcmp("http", ci->url->scheme) == 0) { 758 ci->url->port = 80; 759 } 760 else if (strcmp("https", ci->url->scheme) == 0) { 761 ci->url->port = 443; 762 } 763 else { 764 ci->url->port = 80; 765 } 766 } 767 768 if (!ci->url->path) { 769 ci->url->path = strdup("/"); 770 } 771 772 if (strcasecmp(ci->url->scheme, "https") == 0) { 773 #if 0 774 /* TODO: Custom CA validation */ 805 775 void *vstr; 806 serf_module_conf_t *conf;776 http_module_conf_t *conf; 807 777 conf = noit_module_get_userdata(self); 808 809 ci->app_ctx.using_ssl = 1;810 811 778 if(noit_hash_retrieve(check->config, "ca_chain", 812 779 strlen("ca_chain"), &vstr)) … … 822 789 strlen("certificate_file"), &vstr)) 823 790 ci->app_ctx.certificate_file = apr_pstrdup(ci->pool, vstr); 824 } 825 else { 826 ci->app_ctx.using_ssl = 0; 827 } 828 829 status = apr_sockaddr_info_get(&ci->address, 830 check->target, APR_UNSPEC, ci->url.port, 0, 831 ci->pool); 832 if (status) { 833 /* Handle error -- log failure */ 834 apr_pool_destroy(ci->pool); 835 memset(ci, 0, sizeof(*ci)); 836 check->flags &= ~NP_RUNNING; 837 return 0; 838 } 839 840 ci->context = serf_context_create_ex(ccl, serf_eventer_add, 841 serf_eventer_remove, ci->pool); 842 843 ci->app_ctx.bkt_alloc = serf_bucket_allocator_create(ci->pool, NULL, NULL); 844 ci->app_ctx.ssl_ctx = NULL; 845 846 ci->connection = serf_connection_create(ci->context, ci->address, 847 conn_setup, &ci->app_ctx, 848 closed_connection, &ci->app_ctx, 849 ci->pool); 850 851 ci->handler_ctx.method = apr_pstrdup(ci->pool, "GET"); 852 ci->handler_ctx.host = apr_pstrdup(ci->pool, ci->url.hostname); 853 ci->handler_ctx.path = ci->url.path; 854 ci->handler_ctx.authn = NULL; 855 856 ci->handler_ctx.acceptor = accept_response; 857 ci->handler_ctx.acceptor_baton = &ci->app_ctx; 858 ci->handler_ctx.handler = handle_response; 859 ci->handler_ctx.self = self; 860 ci->handler_ctx.check = check; 861 862 ci->request = serf_connection_request_create(ci->connection, setup_request, 863 &ci->handler_ctx); 864 serf_context_prerun(ci->context); 865 866 newe = eventer_alloc(); 867 newe->mask = EVENTER_TIMER; 868 gettimeofday(&when, NULL); 869 p_int.tv_sec = check->timeout / 1000; 870 p_int.tv_usec = (check->timeout % 1000) * 1000; 871 add_timeval(when, p_int, &newe->whence); 872 ccl = calloc(1, sizeof(*ccl)); 873 ccl->self = self; 874 ccl->check = check; 875 newe->closure = ccl; 876 newe->callback = serf_complete; 877 eventer_add(newe); 878 ci->timeout_event = newe; 879 return 0; 880 } 881 static int serf_initiate_check(noit_module_t *self, noit_check_t *check, 791 #endif 792 } 793 794 snprintf(buf, sizeof(buf), "Host: %s", ci->url->server); 795 ci->cheaders = curl_slist_append(ci->cheaders, buf); 796 ci->cheaders = curl_slist_append(ci->cheaders, "Accept-Encoding: deflate,gzip"); 797 798 ci->curl = curl_easy_init(); 799 800 curl_easy_setopt(ci->curl, CURLOPT_NOSIGNAL, 0); 801 curl_easy_setopt(ci->curl, CURLOPT_WRITEFUNCTION, http_write_data); 802 curl_easy_setopt(ci->curl, CURLOPT_WRITEDATA, ci); 803 curl_easy_setopt(ci->curl, CURLOPT_HEADERFUNCTION, http_write_headers); 804 curl_easy_setopt(ci->curl, CURLOPT_HEADERDATA, ci); 805 806 free(ci->url->server); 807 ci->url->server = strdup(check->target); 808 urlstr = (char *)xmlSaveUri(ci->url); 809 curl_easy_setopt(ci->curl, CURLOPT_URL, urlstr); 810 noitL(nldeb, "http_initiate(%p,%s,url=%s)\n", 811 ci, check->target, urlstr); 812 xmlFreeURI(ci->url); 813 free(urlstr); 814 ci->url = NULL; 815 816 817 curl_easy_setopt(ci->curl, CURLOPT_PROTOCOLS, CURLPROTO_HTTP|CURLPROTO_HTTPS); 818 curl_easy_setopt(ci->curl, CURLOPT_FOLLOWLOCATION, 0); 819 curl_easy_setopt(ci->curl, CURLOPT_PROTOCOLS, CURLPROTO_HTTP); 820 821 curl_easy_setopt(ci->curl, CURLOPT_USERAGENT, "Noit/" NOIT_HTTP_VERSION_STRING); 822 curl_easy_setopt(ci->curl, CURLOPT_HTTPHEADER, ci->cheaders); 823 824 curl_easy_setopt(ci->curl, CURLOPT_FRESH_CONNECT, 1); 825 curl_easy_setopt(ci->curl, CURLOPT_FORBID_REUSE, 1); 826 827 /* TODO: more SSL options */ 828 curl_easy_setopt(ci->curl, CURLOPT_SSL_VERIFYPEER, 0); 829 curl_easy_setopt(ci->curl, CURLOPT_SSL_VERIFYHOST, 0); 830 curl_easy_setopt(ci->curl, CURLOPT_TIMEOUT_MS, check->timeout); 831 curl_easy_setopt(ci->curl, CURLOPT_CONNECTTIMEOUT_MS, check->timeout); 832 833 /* TODO: Consider re-using the multi-init */ 834 ci->mcurl = curl_multi_init(); 835 curl_multi_setopt(ci->mcurl, CURLMOPT_SOCKETFUNCTION, http_socket_cb); 836 curl_multi_setopt(ci->mcurl, CURLMOPT_SOCKETDATA, ci); 837 curl_multi_setopt(ci->mcurl, CURLMOPT_PIPELINING, 0); 838 839 curl_multi_setopt(ci->mcurl, CURLMOPT_TIMERFUNCTION, http_set_timeout_cb); 840 curl_multi_setopt(ci->mcurl, CURLMOPT_TIMERDATA, ci); 841 842 curl_multi_add_handle(ci->mcurl, ci->curl); 843 844 { 845 int running_handles = 0; 846 while (curl_multi_perform(ci->mcurl, &running_handles) == CURLM_CALL_MULTI_PERFORM); 847 } 848 849 ci->process_event = eventer_alloc(); 850 ci->process_event->closure = ci; 851 ci->process_event->mask = EVENTER_RECURRENT; 852 ci->process_event->callback = http_recurrent; 853 854 eventer_add_recurrent(ci->process_event); 855 856 return 0; 857 } 858 static int http_initiate_check(noit_module_t *self, noit_check_t *check, 882 859 int once, noit_check_t *cause) { 883 if(!check->closure) check->closure = calloc(1, sizeof( serf_check_info_t));884 INITIATE_CHECK( serf_initiate, self, check);860 if(!check->closure) check->closure = calloc(1, sizeof(http_check_info_t)); 861 INITIATE_CHECK(http_initiate, self, check); 885 862 return 0; 886 863 } … … 889 866 /* resmon_check_info_t gives us a bit more space */ 890 867 if(!check->closure) check->closure = calloc(1, sizeof(resmon_check_info_t)); 891 INITIATE_CHECK( serf_initiate, self, check);892 return 0; 893 } 894 895 static void resmon_cleanup (noit_module_t *self, noit_check_t *check) {868 INITIATE_CHECK(http_initiate, self, check); 869 return 0; 870 } 871 872 static void resmon_cleanup_check(noit_module_t *self, noit_check_t *check) { 896 873 resmon_check_info_t *rci; 897 874 rci = check->closure; … … 901 878 if(rci->resserv) free(rci->resserv); 902 879 if(rci->xml_doc) xmlFreeDoc(rci->xml_doc); 903 serf_cleanup(self, check);880 http_cleanup_check(self, check); 904 881 memset(rci, 0, sizeof(*rci)); 905 882 } … … 936 913 if(parent && !strcmp(parent->module, "resmon")) { 937 914 /* Content is cached in the parent */ 938 serf_check_info_t *ci = (serf_check_info_t *)rci;915 http_check_info_t *ci = &rci->http; 939 916 gettimeofday(&ci->finish_time, NULL); 940 917 resmon_part_log_results(self, check, parent); 941 918 return 0; 942 919 } 943 INITIATE_CHECK(serf_initiate, self, check); 944 return 0; 945 } 946 947 static int serf_onload(noit_image_t *self) { 948 apr_initialize(); 949 atexit(apr_terminate); 950 951 nlerr = noit_log_stream_find("error/serf"); 952 nldeb = noit_log_stream_find("debug/serf"); 920 INITIATE_CHECK(http_initiate, self, check); 921 return 0; 922 } 923 924 static void http_eventer_free(eventer_t e, http_check_info_t *ci) 925 { 926 noitL(nldeb, "http_eventer_free(%p)\n", e); 927 if (!e) 928 return; 929 eventer_free(e); 930 return; 931 } 932 933 934 static int http_onload(noit_image_t *self) { 935 curl_global_init(CURL_GLOBAL_ALL); 936 atexit(curl_global_cleanup); 937 938 nlerr = noit_log_stream_find("error/http"); 939 nldeb = noit_log_stream_find("debug/http"); 953 940 if(!nlerr) nlerr = noit_stderr; 954 941 if(!nldeb) nldeb = noit_debug; 955 942 956 eventer_name_callback("http/serf_handler", serf_handler); 957 eventer_name_callback("http/serf_complete", serf_complete); 943 eventer_name_callback("http/http_handler", http_handler); 944 eventer_name_callback("http/http_timeout", http_timeout); 945 eventer_name_callback("http/http_all_done", http_all_done); 946 eventer_name_callback("http/http_recurrent", http_recurrent); 958 947 return 0; 959 948 } … … 965 954 NOIT_MODULE_ABI_VERSION, 966 955 "http", 967 "lib serf-based HTTP and HTTPS resource checker",956 "libcurl-based HTTP and HTTPS resource checker", 968 957 http_xml_description, 969 serf_onload958 http_onload 970 959 }, 971 serf_config,972 serf_init,973 serf_initiate_check,974 serf_cleanup960 http_config, 961 http_init, 962 http_initiate_check, 963 http_cleanup_check 975 964 }; 976 965 … … 983 972 "libserf-based resmon resource checker", 984 973 resmon_xml_description, 985 serf_onload974 http_onload 986 975 }, 987 976 resmon_config, 988 serf_init,977 http_init, 989 978 resmon_initiate_check, 990 resmon_cleanup 979 resmon_cleanup_check 991 980 }; 992 981 … … 999 988 "resmon part resource checker", 1000 989 resmon_part_xml_description, 1001 serf_onload990 http_onload 1002 991 }, 1003 992 resmon_config, 1004 serf_init,993 http_init, 1005 994 resmon_part_initiate_check, 1006 resmon_cleanup 995 resmon_cleanup_check 1007 996 }; 1008 997 src/stomp/Makefile.in
ra907717 r2ea7724 29 29 30 30 .c.o: 31 @$(CC) $(CPPFLAGS) $(CFLAGS) @ SERFCFLAGS@ -I../libopenwire -c $<31 @$(CC) $(CPPFLAGS) $(CFLAGS) @APRCFLAGS@ -I../libopenwire -c $< 32 32 @echo "- compiling $<" 33 33
