⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sip_transport_tls_ossl.c

📁 基于sip协议的网络电话源码
💻 C
📖 第 1 页 / 共 4 页
字号:
		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 + -