📄 sip_transport_tls_ossl.c
字号:
else if (SSL_want_read (ssl)) PJ_FD_SET(tls->sock, &rd_set); else status = -1; /* Doesn't want anything - bail out */ } else { status = -1; } break; default: ssl_report_error(tls->base.obj_name, 4, PJ_SUCCESS, "SSL_connect() error"); status = -1; break; } if (status == 1) { pj_time_val timeout, *p_timeout; /* Must have at least one handle to wait for at this point. */ pj_assert(PJ_FD_COUNT(&rd_set) == 1 || PJ_FD_COUNT(&wr_set) == 1); /* This will block the whole stack!!! */ PJ_TODO(SUPPORT_SSL_ASYNCHRONOUS_CONNECT); if (tls->listener->setting.timeout.sec == 0 && tls->listener->setting.timeout.msec == 0) { p_timeout = NULL; } else { timeout = tls->listener->setting.timeout; p_timeout = &timeout; } /* Block indefinitely if timeout pointer is zero. */ status = pj_sock_select(tls->sock+1, &rd_set, &wr_set, NULL, p_timeout); /* 0 is timeout, so we're done. * -1 is error, so we're done. * Could be both handles set (same handle in both masks) so set to 1. */ if (status >= 1) status = 1; else if (status == 0) return PJSIP_TLS_ETIMEDOUT; else status = -1; } } while (status == 1 && !SSL_is_init_finished (ssl)); return (status == -1 ? PJSIP_TLS_ECONNECT : PJ_SUCCESS);}/* * Perform SSL_accept() on the newly established incoming TLS connection. */static pj_status_t ssl_accept(struct tls_transport *tls){ SSL *ssl = tls->ssl; int rc; if (SSL_is_init_finished (ssl)) return PJ_SUCCESS; if (!SSL_in_accept_init(ssl)) SSL_set_accept_state(ssl); PJ_LOG(5,(tls->base.obj_name, "Starting SSL_accept() negotiation")); /* Repeat retrying SSL_accept() procedure until it completes either * successfully or with failure. */ do { /* These handle sets are used to set up for whatever SSL_accept says * it wants next. They're reset on each pass around the loop. */ pj_fd_set_t rd_set; pj_fd_set_t wr_set; PJ_FD_ZERO(&rd_set); PJ_FD_ZERO(&wr_set); rc = SSL_accept (ssl); switch (SSL_get_error (ssl, rc)) { case SSL_ERROR_NONE: /* Success! */ rc = 0; PJ_LOG(5,(tls->base.obj_name, "SSL_accept() negotiation completes successfully")); break; case SSL_ERROR_WANT_WRITE: PJ_FD_SET(tls->sock, &wr_set); rc = 1; /* Wait for more activity */ break; case SSL_ERROR_WANT_READ: PJ_FD_SET(tls->sock, &rd_set); rc = 1; /* Need to read more data */ break; case SSL_ERROR_ZERO_RETURN: /* The peer has notified us that it is shutting down via the SSL * "close_notify" message so we need to shutdown, too. */ PJ_LOG(4,(tls->base.obj_name, "Incoming SSL connection closed prematurely by client")); return PJ_STATUS_FROM_OS(OSERR_ENOTCONN); case SSL_ERROR_SYSCALL: /* Explicitly check for EWOULDBLOCK since it doesn't get converted * to an SSL_ERROR_WANT_{READ,WRITE} on some platforms. * If SSL_accept failed outright, though, don't bother checking * more. This can happen if the socket gets closed during the * handshake. */ if (pj_get_netos_error()==PJ_STATUS_FROM_OS(OSERR_EWOULDBLOCK) && rc==-1) { /* Although the SSL_ERROR_WANT_READ/WRITE isn't getting set * correctly, the read/write state should be valid. Use that * to decide what to do. */ rc = 1; /* Wait for more activity */ if (SSL_want_write(ssl)) PJ_FD_SET(tls->sock, &wr_set); else if (SSL_want_read(ssl)) PJ_FD_SET(tls->sock, &rd_set); else { /* Doesn't want anything - bail out */ return PJ_STATUS_FROM_OS(OSERR_ENOTCONN); } } else { return PJSIP_TLS_EUNKNOWN; } break; default: ssl_report_error(tls->base.obj_name, 4, PJ_SUCCESS, "Error calling SSL_accept()"); return pj_get_netos_error() ? pj_get_netos_error() : PJSIP_TLS_EUNKNOWN; } if (rc == 1) { pj_time_val timeout, *p_timeout; /* Must have at least one handle to wait for at this point. */ pj_assert(PJ_FD_COUNT(&rd_set) == 1 || PJ_FD_COUNT(&wr_set) == 1); if (tls->listener->setting.timeout.sec == 0 && tls->listener->setting.timeout.msec == 0) { p_timeout = NULL; } else { timeout = tls->listener->setting.timeout; p_timeout = &timeout; } rc = pj_sock_select(tls->sock+1, &rd_set, &wr_set, NULL, p_timeout); if (rc >= 1) rc = 1; else if (rc == 0) return PJSIP_TLS_ETIMEDOUT; else return pj_get_netos_error(); } } while (rc == 1 && !SSL_is_init_finished(ssl)); return (rc == -1 ? PJSIP_TLS_EUNKNOWN : PJ_SUCCESS);}/* Send outgoing data with SSL connection */static pj_status_t ssl_write(struct tls_transport *tls, pjsip_tx_data *tdata){ int size = tdata->buf.cur - tdata->buf.start; int sent = 0; do { const int fragment_sent = SSL_write(tls->ssl, tdata->buf.start + sent, size - sent); switch( SSL_get_error(tls->ssl, fragment_sent)) { case SSL_ERROR_NONE: sent += fragment_sent; break; case SSL_ERROR_WANT_READ: case SSL_ERROR_WANT_WRITE: /* For now, we can't handle situation where WANT_READ/WANT_WRITE * is raised after some data has been sent, since we don't have * mechanism to keep track of how many bytes have been sent * inside the individual tdata. */ pj_assert(sent == 0); PJ_TODO(PARTIAL_SSL_SENT); return PJ_STATUS_FROM_OS(OSERR_EWOULDBLOCK); case SSL_ERROR_ZERO_RETURN: /* The peer has notified us that it is shutting down via the SSL * "close_notify" message. Tell the transport manager that it * shouldn't use this transport any more and return ENOTCONN * to caller. */ /* It is safe to call this multiple times. */ pjsip_transport_shutdown(&tls->base); return PJ_STATUS_FROM_OS(OSERR_ENOTCONN); case SSL_ERROR_SYSCALL: if (fragment_sent == 0) { /* An EOF occured but the SSL "close_notify" message was not * sent. Shutdown the transport and return ENOTCONN. */ /* It is safe to call this multiple times. */ pjsip_transport_shutdown(&tls->base); return PJ_STATUS_FROM_OS(OSERR_ENOTCONN); } /* Other error */ return pj_get_netos_error(); default: ssl_report_error(tls->base.obj_name, 4, PJ_SUCCESS, "Error sending %s with SSL_write()", pjsip_tx_data_get_info(tdata)); return pj_get_netos_error() ? pj_get_netos_error() : PJSIP_TLS_ESEND; } } while (sent < size); return PJ_SUCCESS;}/* Read data from SSL connection */static pj_status_t ssl_read(struct tls_transport *tls){ pjsip_rx_data *rdata = &tls->rdata; int bytes_read, max_size; max_size = sizeof(rdata->pkt_info.packet) - rdata->pkt_info.len; bytes_read = SSL_read(tls->ssl, rdata->pkt_info.packet+rdata->pkt_info.len, max_size); switch (SSL_get_error(tls->ssl, bytes_read)) { case SSL_ERROR_NONE: /* Data successfully read */ rdata->pkt_info.len += bytes_read; return PJ_SUCCESS; case SSL_ERROR_WANT_READ: case SSL_ERROR_WANT_WRITE: return PJ_STATUS_FROM_OS(OSERR_EWOULDBLOCK); case SSL_ERROR_ZERO_RETURN: /* The peer has notified us that it is shutting down via the SSL * "close_notify" message. */ pjsip_transport_shutdown(&tls->base); return PJ_STATUS_FROM_OS(OSERR_ENOTCONN); case SSL_ERROR_SYSCALL: if (bytes_read == 0) { /* An EOF occured but the SSL "close_notify" message was not * sent. */ pjsip_transport_shutdown(&tls->base); return PJ_STATUS_FROM_OS(OSERR_ENOTCONN); } /* Other error */ return pj_get_netos_error(); default: ssl_report_error(tls->base.obj_name, 4, PJ_SUCCESS, "Error reading data with SSL_read()"); return pj_get_netos_error() ? pj_get_netos_error() : PJSIP_TLS_EREAD; } /* Should not reach here */}/**************************************************************************** * The TLS listener/transport factory. *//* * This is the public API to create, initialize, register, and start the * TLS listener. */PJ_DEF(pj_status_t) pjsip_tls_transport_start( pjsip_endpoint *endpt, const pjsip_tls_setting *opt, const pj_sockaddr_in *local, const pjsip_host_port *a_name, unsigned async_cnt, pjsip_tpfactory **p_factory){ pj_pool_t *pool; struct tls_listener *listener; pj_ioqueue_callback listener_cb; pj_sockaddr_in *listener_addr; int addr_len; unsigned i; pj_status_t status; /* Sanity check */ PJ_ASSERT_RETURN(endpt && async_cnt, PJ_EINVAL); /* Verify that address given in a_name (if any) is valid */ if (a_name && a_name->host.slen) { pj_sockaddr_in tmp; status = pj_sockaddr_in_init(&tmp, &a_name->host, (pj_uint16_t)a_name->port); if (status != PJ_SUCCESS || tmp.sin_addr.s_addr == PJ_INADDR_ANY || tmp.sin_addr.s_addr == PJ_INADDR_NONE) { /* Invalid address */ return PJ_EINVAL; } } pool = pjsip_endpt_create_pool(endpt, "tlslis", POOL_LIS_INIT, POOL_LIS_INC); PJ_ASSERT_RETURN(pool, PJ_ENOMEM); listener = pj_pool_zalloc(pool, sizeof(struct tls_listener)); listener->factory.pool = pool; listener->factory.type = PJSIP_TRANSPORT_TLS; listener->factory.type_name = "tls"; listener->factory.flag = pjsip_transport_get_flag_from_type(PJSIP_TRANSPORT_TLS); listener->sock = PJ_INVALID_SOCKET; /* Create object name */ pj_ansi_snprintf(listener->factory.obj_name, sizeof(listener->factory.obj_name), "tls%p", listener); /* Create duplicate of TLS settings */ if (opt) pjsip_tls_setting_copy(pool, &listener->setting, opt); else pjsip_tls_setting_default(&listener->setting); /* Initialize SSL context to be used by this listener */ status = create_ctx(listener, &listener->ctx); if (status != PJ_SUCCESS) goto on_error; status = pj_lock_create_recursive_mutex(pool, "tlslis", &listener->factory.lock); if (status != PJ_SUCCESS) goto on_error; /* Create and bind socket */ status = pj_sock_socket(PJ_AF_INET, PJ_SOCK_STREAM, 0, &listener->sock); if (status != PJ_SUCCESS) goto on_error; listener_addr = (pj_sockaddr_in*)&listener->factory.local_addr; if (local) { pj_memcpy(listener_addr, local, sizeof(pj_sockaddr_in)); } else { pj_sockaddr_in_init(listener_addr, NULL, 0); } status = pj_sock_bind(listener->sock, listener_addr, sizeof(pj_sockaddr_in)); if (status != PJ_SUCCESS) goto on_error; /* Retrieve the bound address */ addr_len = sizeof(pj_sockaddr_in); status = pj_sock_getsockname(listener->sock, listener_addr, &addr_len); if (status != PJ_SUCCESS) goto on_error; /* If published host/IP is specified, then use that address as the * listener advertised address. */ if (a_name && a_name->host.slen) { /* Copy the address */ listener->factory.addr_name = *a_name; pj_strdup(listener->factory.pool, &listener->factory.addr_name.host, &a_name->host); listener->factory.addr_name.port = a_name->port; } else { /* No published address is given, use the bound address */ /* If the address returns 0.0.0.0, use the default * interface address as the transport's address. */ if (listener_addr->sin_addr.s_addr == 0) { pj_in_addr hostip; status = pj_gethostip(&hostip); if (status != PJ_SUCCESS) goto on_error; listener_addr->sin_addr = hostip; } /* Save the address name */ sockaddr_to_host_port(listener->factory.pool, &listener->factory.addr_name, listener_addr); } /* If port is zero, get the bound port */ if (listener->factory.addr_name.port == 0) { listener->factory.addr_name.port = pj_ntohs(listener_addr->sin_port); } /* Start listening to the address */ status = pj_sock_listen(listener->sock, PJSIP_TLS_TRANSPORT_BACKLOG); if (status != PJ_SUCCESS) goto on_error; /* Register socket to ioqeuue */ pj_bzero(&listener_cb, sizeof(listener_cb)); listener_cb.on_accept_complete = &on_accept_complete; status = pj_ioqueue_register_sock(pool, pjsip_endpt_get_ioqueue(endpt), listener->sock, listener, &listener_cb, &listener->key); if (status != PJ_SUCCESS) goto on_error; /* Register to transport manager */ listener->endpt = endpt; listener->tpmgr = pjsip_endpt_get_tpmgr(endpt); listener->factory.create_transport = lis_create_transport; listener->factory.destroy = lis_destroy; listener->is_registered = PJ_TRUE; status = pjsip_tpmgr_register_tpfactory(listener->tpmgr, &listener->factory); if (status != PJ_SUCCESS) { listener->is_registered = PJ_FALSE; goto on_error; } /* Start pending accept() operations */ if (async_cnt > MAX_ASYNC_CNT) async_cnt = MAX_ASYNC_CNT; listener->async_cnt = async_cnt; for (i=0; i<async_cnt; ++i) { pj_pool_t *pool; pool = pjsip_endpt_create_pool(endpt, "tlss%p", POOL_TP_INIT, POOL_TP_INIT); if (!pool) { status = PJ_ENOMEM; goto on_error; } listener->accept_op[i] = pj_pool_zalloc(pool, sizeof(struct pending_accept)); pj_ioqueue_op_key_init(&listener->accept_op[i]->op_key, sizeof(listener->accept_op[i]->op_key)); listener->accept_op[i]->pool = pool; listener->accept_op[i]->listener = listener; listener->accept_op[i]->index = i; on_accept_complete(listener->key, &listener->accept_op[i]->op_key, listener->sock, PJ_EPENDING); } PJ_LOG(4,(listener->factory.obj_name, "SIP TLS listener ready for incoming connections at %.*s:%d", (int)listener->factory.addr_name.host.slen, listener->factory.addr_name.host.ptr, listener->factory.addr_name.port)); /* Return the pointer to user */ if (p_factory) *p_factory = &listener->factory; return PJ_SUCCESS;on_error: lis_destroy(&listener->factory); return status;}/* This callback is called by transport manager to destroy listener */static pj_status_t lis_destroy(pjsip_tpfactory *factory){ struct tls_listener *listener = (struct tls_listener *)factory; unsigned i; if (listener->is_registered) { pjsip_tpmgr_unregister_tpfactory(listener->tpmgr, &listener->factory); listener->is_registered = PJ_FALSE; } if (listener->key) { pj_ioqueue_unregister(listener->key); listener->key = NULL; listener->sock = PJ_INVALID_SOCKET; } if (listener->sock != PJ_INVALID_SOCKET) { pj_sock_close(listener->sock); listener->sock = PJ_INVALID_SOCKET; } if (listener->factory.lock) { pj_lock_destroy(listener->factory.lock); listener->factory.lock = NULL; } for (i=0; i<PJ_ARRAY_SIZE(listener->accept_op); ++i) { if (listener->accept_op[i] && listener->accept_op[i]->pool) { pj_pool_t *pool = listener->accept_op[i]->pool; listener->accept_op[i]->pool = NULL; pj_pool_release(pool); } } if (listener->ctx) { destroy_ctx(listener->ctx); listener->ctx = NULL; } if (listener->factory.pool) { pj_pool_t *pool = listener->factory.pool; PJ_LOG(4,(listener->factory.obj_name, "SIP TLS listener destroyed"));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -