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; }
static tport_t *tport_http_connect(tport_primary_t *pri, su_addrinfo_t *ai, tp_name_t const *tpn) { tport_http_connect_t *thc = (tport_http_connect_t *)pri; tport_http_connect_instance_t *thci; tport_master_t *mr = pri->pri_master; msg_t *msg, *response; char hostport[TPORT_HOSTPORTSIZE]; tport_t *tport; http_request_t *rq; msg = msg_create(http_default_mclass(), 0); if (!msg) return NULL; tport_hostport(hostport, sizeof hostport, (void *)ai->ai_addr, 1); rq = http_request_format(msg_home(msg), "CONNECT %s HTTP/1.1", hostport); if (msg_header_insert(msg, NULL, (void *)rq) < 0 || msg_header_add_str(msg, NULL, "User-Agent: Sofia-SIP/" VERSION "\n") < 0 || msg_header_add_str(msg, NULL, "Proxy-Connection: keepalive\n") < 0 || msg_header_add_make(msg, NULL, http_host_class, hostport) < 0 || msg_header_add_make(msg, NULL, http_separator_class, "\r\n") < 0 || msg_serialize(msg, NULL) < 0 || msg_prepare(msg) < 0) return (void)msg_destroy(msg), NULL; /* * Create a response message that ignores the body * if there is no Content-Length */ response = msg_create(http_default_mclass(), mr->mr_log | MSG_FLG_MAILBOX); tport = tport_base_connect(pri, thc->thc_proxy, ai, tpn); if (!tport) { msg_destroy(msg); msg_destroy(response); return tport; } thci = (tport_http_connect_instance_t*)tport; thci->thci_response = response; tport->tp_msg = response; msg_set_next(response, thci->thci_stackmsg = tport_msg_alloc(tport, 512)); if (tport_send_msg(tport, msg, tpn, NULL) < 0) { SU_DEBUG_9(("tport_send_msg failed in tpot_http_connect\n" VA_NONE)); msg_destroy(msg); tport_zap_secondary(tport); return NULL; } tport_set_secondary_timer(tport); return tport; }