/* * This callback is called by SSL socket when pending accept() operation * has completed. */ static pj_bool_t on_accept_complete(pj_ssl_sock_t *ssock, pj_ssl_sock_t *new_ssock, const pj_sockaddr_t *src_addr, int src_addr_len) { struct tls_listener *listener; struct tls_transport *tls; char addr[PJ_INET6_ADDRSTRLEN+10]; pj_status_t status; PJ_UNUSED_ARG(src_addr_len); listener = (struct tls_listener*) pj_ssl_sock_get_user_data(ssock); PJ_ASSERT_RETURN(new_ssock, PJ_TRUE); PJ_LOG(4,(listener->factory.obj_name, "TLS listener %.*s:%d: got incoming TLS connection " "from %s, sock=%d", (int)listener->factory.addr_name.host.slen, listener->factory.addr_name.host.ptr, listener->factory.addr_name.port, pj_sockaddr_print(src_addr, addr, sizeof(addr), 3), new_ssock)); /* * Incoming connection! * Create TLS transport for the new socket. */ status = tls_create( listener, NULL, new_ssock, PJ_TRUE, (const pj_sockaddr_in*)&listener->factory.local_addr, (const pj_sockaddr_in*)src_addr, &tls); if (status == PJ_SUCCESS) { /* Set the "pending" SSL socket user data */ pj_ssl_sock_set_user_data(new_ssock, tls); status = tls_start_read(tls); if (status != PJ_SUCCESS) { PJ_LOG(3,(tls->base.obj_name, "New transport cancelled")); tls_destroy(&tls->base, status); } else { /* Start keep-alive timer */ if (PJSIP_TCP_KEEP_ALIVE_INTERVAL) { pj_time_val delay = {PJSIP_TCP_KEEP_ALIVE_INTERVAL, 0}; pjsip_endpt_schedule_timer(listener->endpt, &tls->ka_timer, &delay); tls->ka_timer.id = PJ_TRUE; pj_gettimeofday(&tls->last_activity); } } } return PJ_TRUE; }
/* * Callback from ioqueue when packet is sent. */ static pj_bool_t on_data_sent(pj_ssl_sock_t *ssock, pj_ioqueue_op_key_t *op_key, pj_ssize_t bytes_sent) { struct tls_transport *tls = (struct tls_transport*) pj_ssl_sock_get_user_data(ssock); pjsip_tx_data_op_key *tdata_op_key = (pjsip_tx_data_op_key*)op_key; /* Note that op_key may be the op_key from keep-alive, thus * it will not have tdata etc. */ tdata_op_key->tdata = NULL; if (tdata_op_key->callback) { /* * Notify sip_transport.c that packet has been sent. */ if (bytes_sent == 0) bytes_sent = -PJ_RETURN_OS_ERROR(OSERR_ENOTCONN); tdata_op_key->callback(&tls->base, tdata_op_key->token, bytes_sent); /* Mark last activity time */ pj_gettimeofday(&tls->last_activity); } /* Check for error/closure */ if (bytes_sent <= 0) { pj_status_t status; PJ_LOG(5,(tls->base.obj_name, "TLS send() error, sent=%d", bytes_sent)); status = (bytes_sent == 0) ? PJ_RETURN_OS_ERROR(OSERR_ENOTCONN) : -bytes_sent; tls_init_shutdown(tls, status); return PJ_FALSE; } return PJ_TRUE; }
static pj_bool_t ssl_on_data_sent(pj_ssl_sock_t *ssock, pj_ioqueue_op_key_t *op_key, pj_ssize_t sent) { struct test_state *st = (struct test_state*) pj_ssl_sock_get_user_data(ssock); PJ_UNUSED_ARG(op_key); if (sent < 0) { st->err = -sent; } else { st->sent += sent; /* Send more if any */ while (st->sent < st->send_str_len) { pj_ssize_t size; pj_status_t status; size = st->send_str_len - st->sent; status = pj_ssl_sock_send(ssock, (pj_ioqueue_op_key_t*)&st->send_key, st->send_str + st->sent, &size, 0); if (status != PJ_SUCCESS && status != PJ_EPENDING) { app_perror("...ERROR pj_ssl_sock_send()", status); st->err = status; break; } if (status == PJ_SUCCESS) st->sent += size; else break; } } if (st->err != PJ_SUCCESS) { pj_ssl_sock_close(ssock); if (!st->is_server) clients_num--; return PJ_FALSE; } return PJ_TRUE; }
/* * This callback is called by SSL socket when pending accept() operation * has completed. */ static pj_bool_t on_accept_complete(pj_ssl_sock_t *ssock, pj_ssl_sock_t *new_ssock, const pj_sockaddr_t *src_addr, int src_addr_len) { struct tls_listener *listener; struct tls_transport *tls; pj_ssl_sock_info ssl_info; char addr[PJ_INET6_ADDRSTRLEN+10]; pjsip_tp_state_callback state_cb; pj_bool_t is_shutdown; pj_status_t status; PJ_UNUSED_ARG(src_addr_len); listener = (struct tls_listener*) pj_ssl_sock_get_user_data(ssock); PJ_ASSERT_RETURN(new_ssock, PJ_TRUE); PJ_LOG(4,(listener->factory.obj_name, "TLS listener %.*s:%d: got incoming TLS connection " "from %s, sock=%d", (int)listener->factory.addr_name.host.slen, listener->factory.addr_name.host.ptr, listener->factory.addr_name.port, pj_sockaddr_print(src_addr, addr, sizeof(addr), 3), new_ssock)); /* Retrieve SSL socket info, close the socket if this is failed * as the SSL socket info availability is rather critical here. */ status = pj_ssl_sock_get_info(new_ssock, &ssl_info); if (status != PJ_SUCCESS) { pj_ssl_sock_close(new_ssock); return PJ_TRUE; } /* * Incoming connection! * Create TLS transport for the new socket. */ status = tls_create( listener, NULL, new_ssock, PJ_TRUE, (const pj_sockaddr_in*)&listener->factory.local_addr, (const pj_sockaddr_in*)src_addr, NULL, &tls); if (status != PJ_SUCCESS) return PJ_TRUE; /* Set the "pending" SSL socket user data */ pj_ssl_sock_set_user_data(new_ssock, tls); /* Prevent immediate transport destroy as application may access it * (getting info, etc) in transport state notification callback. */ pjsip_transport_add_ref(&tls->base); /* If there is verification error and verification is mandatory, shutdown * and destroy the transport. */ if (ssl_info.verify_status && listener->tls_setting.verify_client) { if (tls->close_reason == PJ_SUCCESS) tls->close_reason = PJSIP_TLS_ECERTVERIF; pjsip_transport_shutdown(&tls->base); } /* Notify transport state to application */ state_cb = pjsip_tpmgr_get_state_cb(tls->base.tpmgr); if (state_cb) { pjsip_transport_state_info state_info; pjsip_tls_state_info tls_info; pjsip_transport_state tp_state; /* Init transport state info */ pj_bzero(&tls_info, sizeof(tls_info)); pj_bzero(&state_info, sizeof(state_info)); tls_info.ssl_sock_info = &ssl_info; state_info.ext_info = &tls_info; /* Set transport state based on verification status */ if (ssl_info.verify_status && listener->tls_setting.verify_client) { tp_state = PJSIP_TP_STATE_DISCONNECTED; state_info.status = PJSIP_TLS_ECERTVERIF; } else { tp_state = PJSIP_TP_STATE_CONNECTED; state_info.status = PJ_SUCCESS; } (*state_cb)(&tls->base, tp_state, &state_info); } /* Release transport reference. If transport is shutting down, it may * get destroyed here. */ is_shutdown = tls->base.is_shutdown; pjsip_transport_dec_ref(&tls->base); if (is_shutdown) return PJ_TRUE; status = tls_start_read(tls); if (status != PJ_SUCCESS) { PJ_LOG(3,(tls->base.obj_name, "New transport cancelled")); tls_init_shutdown(tls, status); tls_destroy(&tls->base, status); } else { /* Start keep-alive timer */ if (PJSIP_TLS_KEEP_ALIVE_INTERVAL) { pj_time_val delay = {PJSIP_TLS_KEEP_ALIVE_INTERVAL, 0}; pjsip_endpt_schedule_timer(listener->endpt, &tls->ka_timer, &delay); tls->ka_timer.id = PJ_TRUE; pj_gettimeofday(&tls->last_activity); } } return PJ_TRUE; }
static pj_bool_t ssl_on_data_read(pj_ssl_sock_t *ssock, void *data, pj_size_t size, pj_status_t status, pj_size_t *remainder) { struct test_state *st = (struct test_state*) pj_ssl_sock_get_user_data(ssock); PJ_UNUSED_ARG(remainder); PJ_UNUSED_ARG(data); if (size > 0) { pj_size_t consumed; /* Set random remainder */ *remainder = pj_rand() % 100; /* Apply zero remainder if: * - remainder is less than size, or * - connection closed/error * - echo/check_eco set */ if (*remainder > size || status != PJ_SUCCESS || st->echo || st->check_echo) *remainder = 0; consumed = size - *remainder; st->recv += consumed; //printf("%.*s", consumed, (char*)data); pj_memmove(data, (char*)data + consumed, *remainder); /* Echo data when specified to */ if (st->echo) { pj_ssize_t size_ = consumed; status = pj_ssl_sock_send(ssock, (pj_ioqueue_op_key_t*)&st->send_key, data, &size_, 0); if (status != PJ_SUCCESS && status != PJ_EPENDING) { app_perror("...ERROR pj_ssl_sock_send()", status); goto on_return; } if (status == PJ_SUCCESS) st->sent += size_; } /* Verify echoed data when specified to */ if (st->check_echo) { if (!st->check_echo_ptr) st->check_echo_ptr = st->send_str; if (pj_memcmp(st->check_echo_ptr, data, consumed)) { status = PJ_EINVAL; app_perror("...ERROR echoed data not exact", status); goto on_return; } st->check_echo_ptr += consumed; /* Echo received completely */ if (st->send_str_len == st->recv) { pj_ssl_sock_info info; char buf[64]; status = pj_ssl_sock_get_info(ssock, &info); if (status != PJ_SUCCESS) { app_perror("...ERROR pj_ssl_sock_get_info()", status); goto on_return; } pj_sockaddr_print((pj_sockaddr_t*)&info.local_addr, buf, sizeof(buf), 1); PJ_LOG(3, ("", "...%s successfully recv %d bytes echo", buf, st->recv)); st->done = PJ_TRUE; } } } if (status != PJ_SUCCESS) { if (status == PJ_EEOF) { status = PJ_SUCCESS; st->done = PJ_TRUE; } else { app_perror("...ERROR ssl_on_data_read()", status); } } on_return: st->err = status; if (st->err != PJ_SUCCESS || st->done) { pj_ssl_sock_close(ssock); if (!st->is_server) clients_num--; return PJ_FALSE; } return PJ_TRUE; }
static pj_bool_t ssl_on_accept_complete(pj_ssl_sock_t *ssock, pj_ssl_sock_t *newsock, const pj_sockaddr_t *src_addr, int src_addr_len) { struct test_state *parent_st = (struct test_state*) pj_ssl_sock_get_user_data(ssock); struct test_state *st; void *read_buf[1]; pj_ssl_sock_info info; char buf[64]; pj_status_t status; PJ_UNUSED_ARG(src_addr_len); /* Duplicate parent test state to newly accepted test state */ st = pj_pool_zalloc(parent_st->pool, sizeof(struct test_state)); *st = *parent_st; pj_ssl_sock_set_user_data(newsock, st); status = pj_ssl_sock_get_info(newsock, &info); if (status != PJ_SUCCESS) { app_perror("...ERROR pj_ssl_sock_get_info()", status); goto on_return; } pj_sockaddr_print(src_addr, buf, sizeof(buf), 1); PJ_LOG(3, ("", "...Accepted connection from %s", buf)); if (st->is_verbose) dump_ssl_info(&info); /* Start reading data */ read_buf[0] = st->read_buf; status = pj_ssl_sock_start_read2(newsock, st->pool, sizeof(st->read_buf), (void**)read_buf, 0); if (status != PJ_SUCCESS) { app_perror("...ERROR pj_ssl_sock_start_read2()", status); goto on_return; } /* Start sending data */ while (st->sent < st->send_str_len) { pj_ssize_t size; size = st->send_str_len - st->sent; status = pj_ssl_sock_send(newsock, (pj_ioqueue_op_key_t*)&st->send_key, st->send_str + st->sent, &size, 0); if (status != PJ_SUCCESS && status != PJ_EPENDING) { app_perror("...ERROR pj_ssl_sock_send()", status); goto on_return; } if (status == PJ_SUCCESS) st->sent += size; else break; } on_return: st->err = status; if (st->err != PJ_SUCCESS) { pj_ssl_sock_close(newsock); return PJ_FALSE; } return PJ_TRUE; }
static pj_bool_t ssl_on_connect_complete(pj_ssl_sock_t *ssock, pj_status_t status) { struct test_state *st = (struct test_state*) pj_ssl_sock_get_user_data(ssock); void *read_buf[1]; pj_ssl_sock_info info; char buf1[64], buf2[64]; if (status != PJ_SUCCESS) { app_perror("...ERROR ssl_on_connect_complete()", status); goto on_return; } status = pj_ssl_sock_get_info(ssock, &info); if (status != PJ_SUCCESS) { app_perror("...ERROR pj_ssl_sock_get_info()", status); goto on_return; } pj_sockaddr_print((pj_sockaddr_t*)&info.local_addr, buf1, sizeof(buf1), 1); pj_sockaddr_print((pj_sockaddr_t*)&info.remote_addr, buf2, sizeof(buf2), 1); PJ_LOG(3, ("", "...Connected %s -> %s!", buf1, buf2)); if (st->is_verbose) dump_ssl_info(&info); /* Start reading data */ read_buf[0] = st->read_buf; status = pj_ssl_sock_start_read2(ssock, st->pool, sizeof(st->read_buf), (void**)read_buf, 0); if (status != PJ_SUCCESS) { app_perror("...ERROR pj_ssl_sock_start_read2()", status); goto on_return; } /* Start sending data */ while (st->sent < st->send_str_len) { pj_ssize_t size; size = st->send_str_len - st->sent; status = pj_ssl_sock_send(ssock, (pj_ioqueue_op_key_t*)&st->send_key, st->send_str + st->sent, &size, 0); if (status != PJ_SUCCESS && status != PJ_EPENDING) { app_perror("...ERROR pj_ssl_sock_send()", status); goto on_return; } if (status == PJ_SUCCESS) st->sent += size; else break; } on_return: st->err = status; if (st->err != PJ_SUCCESS) { pj_ssl_sock_close(ssock); clients_num--; return PJ_FALSE; } return PJ_TRUE; }