/** Keepalive timer. */ void tport_keepalive_timer(tport_t *self, su_time_t now) { unsigned timeout = self->tp_params->tpp_pingpong; if (timeout != 0) { if (self->tp_ptime.tv_sec && !self->tp_recv_close && su_time_cmp(su_time_add(self->tp_ptime, timeout), now) < 0) { SU_DEBUG_3(("%s(%p): %s to " TPN_FORMAT "%s\n", __func__, (void *)self, "closing connection", TPN_ARGS(self->tp_name), " because of PONG timeout")); tport_error_report(self, EPIPE, NULL); if (!self->tp_closed) tport_close(self); return; } } timeout = self->tp_params->tpp_keepalive; if (timeout != 0 && timeout != UINT_MAX) { if (su_time_cmp(su_time_add(self->tp_ktime, timeout), now) < 0) { tport_tcp_ping(self, now); } } }
static void tport_http_deliver(tport_t *self, msg_t *msg, su_time_t now) { tport_http_connect_instance_t *thci = (tport_http_connect_instance_t*)self; if (msg && thci->thci_response == msg) { tport_http_connect_t *thc = (tport_http_connect_t *)self->tp_pri; http_t *http = http_object(msg); if (http && http->http_status) { SU_DEBUG_0(("tport_http_connect: %u %s\n", http->http_status->st_status, http->http_status->st_phrase)); if (http->http_status->st_status < 300) { msg_buf_move(thci->thci_stackmsg, msg); thci->thci_response = NULL; thci->thci_stackmsg = NULL; return; } } msg_destroy(msg); thci->thci_response = NULL; tport_error_report(self, EPROTO, (void *)thc->thc_proxy->ai_addr); tport_close(self); return; } tport_base_deliver(self, msg, now); }
/** Send PING */ int tport_ws_ping(tport_t *self, su_time_t now) { ssize_t n; char *why = ""; if (tport_has_queued(self)) return 0; n = send(self->tp_socket, "\r\n\r\n", 4, 0); if (n > 0) self->tp_ktime = now; if (n == 4) { if (self->tp_ptime.tv_sec == 0) self->tp_ptime = now; } else if (n == -1) { int error = su_errno(); why = " failed"; if (!su_is_blocking(error)) tport_error_report(self, error, NULL); else why = " blocking"; return -1; } SU_DEBUG_7(("%s(%p): %s to " TPN_FORMAT "%s\n", __func__, (void *)self, "sending PING", TPN_ARGS(self->tp_name), why)); return n == -1 ? -1 : 0; }
int tls_connect(su_root_magic_t *magic, su_wait_t *w, tport_t *self) { tport_master_t *mr = self->tp_master; tport_tls_t *tlstp = (tport_tls_t *)self; tls_t *tls; int events = su_wait_events(w, self->tp_socket); int error; SU_DEBUG_7(("%s(%p): events%s%s%s%s\n", __func__, (void *)self, events & (SU_WAIT_CONNECT) ? " CONNECTING" : "", events & SU_WAIT_IN ? " NEGOTIATING" : "", events & SU_WAIT_ERR ? " ERROR" : "", events & SU_WAIT_HUP ? " HANGUP" : "")); #if HAVE_POLL assert(w->fd == self->tp_socket); #endif if (events & SU_WAIT_ERR) tport_error_event(self); if (events & SU_WAIT_HUP && !self->tp_closed) tport_hup_event(self); if (self->tp_closed) return 0; error = su_soerror(self->tp_socket); if (error) { tport_error_report(self, error, NULL); return 0; } if ((tls = tlstp->tlstp_context) == NULL) { SU_DEBUG_3(("%s(%p): Error: no TLS context data for connected socket.\n", __func__, (void *)tlstp)); tport_close(self); tport_set_secondary_timer(self); return 0; } if (self->tp_is_connected == 0) { int ret, status; ret = self->tp_accepted ? SSL_accept(tls->con) : SSL_connect(tls->con); status = SSL_get_error(tls->con, ret); switch (status) { case SSL_ERROR_WANT_READ: /* OpenSSL is waiting for the peer to send handshake data */ self->tp_events = SU_WAIT_IN | SU_WAIT_ERR | SU_WAIT_HUP; su_root_eventmask(mr->mr_root, self->tp_index, self->tp_socket, self->tp_events); return 0; case SSL_ERROR_WANT_WRITE: /* OpenSSL is waiting for the peer to receive handshake data */ self->tp_events = SU_WAIT_IN | SU_WAIT_ERR | SU_WAIT_HUP | SU_WAIT_OUT; su_root_eventmask(mr->mr_root, self->tp_index, self->tp_socket, self->tp_events); return 0; case SSL_ERROR_NONE: /* TLS Handshake complete */ status = tls_post_connection_check(self, tls); if ( status == X509_V_OK ) { su_wait_t wait[1] = {SU_WAIT_INIT}; tport_master_t *mr = self->tp_master; su_root_deregister(mr->mr_root, self->tp_index); self->tp_index = -1; self->tp_events = SU_WAIT_IN | SU_WAIT_ERR | SU_WAIT_HUP; if ((su_wait_create(wait, self->tp_socket, self->tp_events) == -1) || ((self->tp_index = su_root_register(mr->mr_root, wait, tport_wakeup, self, 0)) == -1)) { tport_close(self); tport_set_secondary_timer(self); return 0; } tls->read_events = SU_WAIT_IN; tls->write_events = 0; self->tp_is_connected = 1; self->tp_verified = tls->x509_verified; self->tp_subjects = tls->subjects; if (tport_has_queued(self)) tport_send_event(self); else tport_set_secondary_timer(self); return 0; } break; default: { char errbuf[64]; ERR_error_string_n(status, errbuf, 64); SU_DEBUG_3(("%s(%p): TLS setup failed (%s)\n", __func__, (void *)self, errbuf)); } break; } } /* TLS Handshake Failed or Peer Certificate did not Verify */ tport_close(self); tport_set_secondary_timer(self); return 0; }