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

📄 sip_transport_tls_ossl.c

📁 一个开源SIP协议栈
💻 C
📖 第 1 页 / 共 5 页
字号:

	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"));

	listener->factory.pool = NULL;
	pj_pool_release(pool);
    }

    return PJ_SUCCESS;
}


/***************************************************************************/
/*
 * TLS Transport
 */

/*
 * Prototypes.
 */
/* Called by transport manager to send message */
static pj_status_t tls_send_msg(pjsip_transport *transport, 
				pjsip_tx_data *tdata,
				const pj_sockaddr_t *rem_addr,
				int addr_len,
				void *token,
				void (*callback)(pjsip_transport *transport,
						 void *token, 
						 pj_ssize_t sent_bytes));

/* Called by transport manager to shutdown */
static pj_status_t tls_shutdown(pjsip_transport *transport);

/* Called by transport manager to destroy transport */
static pj_status_t tls_destroy_transport(pjsip_transport *transport);

/* Utility to destroy transport */
static pj_status_t tls_destroy(pjsip_transport *transport,
			       pj_status_t reason);

/* Callback from ioqueue on incoming packet */
static void on_read_complete(pj_ioqueue_key_t *key, 
                             pj_ioqueue_op_key_t *op_key, 
                             pj_ssize_t bytes_read);

/* Callback from ioqueue when packet is sent */
static void on_write_complete(pj_ioqueue_key_t *key, 
                              pj_ioqueue_op_key_t *op_key, 
                              pj_ssize_t bytes_sent);

/* Callback from ioqueue when connect completes */
static void on_connect_complete(pj_ioqueue_key_t *key, 
                                pj_status_t status);


/*
 * Common function to create TLS transport, called when pending accept() and
 * pending connect() complete.
 */
static pj_status_t tls_create( struct tls_listener *listener,
			       pj_pool_t *pool,
			       pj_sock_t sock, pj_bool_t is_server,
			       const pj_sockaddr_in *local,
			       const pj_sockaddr_in *remote,
			       struct tls_transport **p_tls)
{
    struct tls_transport *tls;
    pj_ioqueue_t *ioqueue;
    pj_ioqueue_callback tls_callback;
    int rc;
    pj_status_t status;
    

    PJ_ASSERT_RETURN(sock != PJ_INVALID_SOCKET, PJ_EINVAL);


    if (pool == NULL) {
	pool = pjsip_endpt_create_pool(listener->endpt, "tls",
				       POOL_TP_INIT, POOL_TP_INC);
	PJ_ASSERT_RETURN(pool != NULL, PJ_ENOMEM);
    }    

    /*
     * Create and initialize basic transport structure.
     */
    tls = pj_pool_zalloc(pool, sizeof(*tls));
    tls->sock = sock;
    tls->is_server = is_server;
    tls->listener = listener;
    pj_list_init(&tls->delayed_list);
    tls->base.pool = pool;

    pj_ansi_snprintf(tls->base.obj_name, PJ_MAX_OBJ_NAME, 
		     (is_server ? "tlss%p" :"tlsc%p"), tls);

    /* Initialize transport reference counter to 1 */
    status = pj_atomic_create(pool, 1, &tls->base.ref_cnt);
    if (status != PJ_SUCCESS) {
	goto on_error;
    }

    status = pj_lock_create_recursive_mutex(pool, "tls", &tls->base.lock);
    if (status != PJ_SUCCESS) {
	goto on_error;
    }

    tls->base.key.type = PJSIP_TRANSPORT_TLS;
    pj_memcpy(&tls->base.key.rem_addr, remote, sizeof(pj_sockaddr_in));
    tls->base.type_name = "tls";
    tls->base.flag = pjsip_transport_get_flag_from_type(PJSIP_TRANSPORT_TLS);

    tls->base.info = pj_pool_alloc(pool, 64);
    pj_ansi_snprintf(tls->base.info, 64, "TLS to %s:%d",
		     pj_inet_ntoa(remote->sin_addr), 
		     (int)pj_ntohs(remote->sin_port));

    tls->base.addr_len = sizeof(pj_sockaddr_in);
    pj_memcpy(&tls->base.local_addr, local, sizeof(pj_sockaddr_in));
    sockaddr_to_host_port(pool, &tls->base.local_name, local);
    sockaddr_to_host_port(pool, &tls->base.remote_name, remote);

    tls->base.endpt = listener->endpt;
    tls->base.tpmgr = listener->tpmgr;
    tls->base.send_msg = &tls_send_msg;
    tls->base.do_shutdown = &tls_shutdown;
    tls->base.destroy = &tls_destroy_transport;

    /* Create SSL connection object */
    tls->ssl = SSL_new(listener->ctx);
    if (tls->ssl == NULL) {
	ssl_report_error(tls->base.obj_name, 4, PJ_SUCCESS,
			 "Error creating SSL connection object");
	status = PJSIP_TLS_ESSLCONN;
	goto on_error;
    }

    /* Associate network socket with SSL connection object */
    rc = SSL_set_fd(tls->ssl, (int)sock);
    if (rc != 1) {
	ssl_report_error(tls->base.obj_name, 4, PJ_SUCCESS,
			 "Error calling SSL_set_fd");
	status = PJSIP_TLS_ESSLCONN;
	goto on_error;
    }

    /* Register socket to ioqueue */
    pj_bzero(&tls_callback, sizeof(pj_ioqueue_callback));
    tls_callback.on_read_complete = &on_read_complete;
    tls_callback.on_write_complete = &on_write_complete;
    tls_callback.on_connect_complete = &on_connect_complete;

    ioqueue = pjsip_endpt_get_ioqueue(listener->endpt);
    status = pj_ioqueue_register_sock(pool, ioqueue, sock, 
				      tls, &tls_callback, &tls->key);
    if (status != PJ_SUCCESS) {
	goto on_error;
    }

    /* Register transport to transport manager */
    status = pjsip_transport_register(listener->tpmgr, &tls->base);
    if (status != PJ_SUCCESS) {
	goto on_error;
    }

    tls->is_registered = PJ_TRUE;

    /* Done setting up basic transport. */
    *p_tls = tls;

    PJ_LOG(4,(tls->base.obj_name, "TLS %s transport created",
	      (tls->is_server ? "server" : "client")));

    return PJ_SUCCESS;

on_error:
    tls_destroy(&tls->base, status);
    return status;
}


/* Flush all delayed transmision once the socket is connected. 
 * Return non-zero if pending transmission list is empty after
 * the function returns.
 */
static pj_bool_t tls_flush_pending_tx(struct tls_transport *tls)
{
    pj_bool_t empty;

    pj_lock_acquire(tls->base.lock);
    while (!pj_list_empty(&tls->delayed_list)) {
	struct delayed_tdata *pending_tx;
	pjsip_tx_data *tdata;
	pj_ioqueue_op_key_t *op_key;
	pj_ssize_t size;
	pj_status_t status;

	pending_tx = tls->delayed_list.next;

	tdata = pending_tx->tdata_op_key->tdata;
	op_key = (pj_ioqueue_op_key_t*)pending_tx->tdata_op_key;

	/* send the txdata */
	status = ssl_write(tls, tdata);

	/* On EWOULDBLOCK, suspend further transmissions */
	if (status == PJ_STATUS_FROM_OS(OSERR_EWOULDBLOCK)) {
	    break;
	}

	/* tdata has been transmitted (successfully or with failure).
	 * In any case, remove it from pending transmission list.
	 */
	pj_list_erase(pending_tx);

	/* Notify callback */
	if (status == PJ_SUCCESS)
	    size = tdata->buf.cur - tdata->buf.start;
	else
	    size = -status;

	on_write_complete(tls->key, op_key, size);

    }

    empty = pj_list_empty(&tls->delayed_list);

    pj_lock_release(tls->base.lock);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -