/** 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);
}
Beispiel #3
0
/** 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;
}
Beispiel #4
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;
}