PJ_DEF(pj_ioqueue_t*) pj_ioqueue_create(pj_pool_t *pool, pj_size_t max_fd) { pj_ioqueue_t *ioque; if (max_fd > PJ_IOQUEUE_MAX_HANDLES) { PJ_LOG(1,("ioqueue", "max_fd too large! Can't create ioqueue.")); return NULL; } ioque = pj_pool_alloc(pool, sizeof(pj_ioqueue_t)); ioque->max = max_fd; ioque->count = 0; PJ_FD_ZERO(&ioque->rfdset); PJ_FD_ZERO(&ioque->wfdset); #if PJ_HAS_TCP PJ_FD_ZERO(&ioque->xfdset); #endif pj_list_init(&ioque->hlist); ioque->mutex = pj_mutex_create(pool, "ioq%p", PJ_MUTEX_SIMPLE); if (!ioque->mutex) { PJ_LOG(1,("ioqueue", "Mutex creation failed!")); return NULL; } PJ_LOG(4, ("pjlib", "select() I/O Queue created (%p)", ioque)); return ioque; }
/* * do_select() * * Perform pj_sock_select() and find out which sockets * are signalled. */ static int do_select( pj_sock_t sock1, pj_sock_t sock2, int setcount[]) { pj_fd_set_t fds[3]; pj_time_val timeout; int i, n; for (i=0; i<3; ++i) { PJ_FD_ZERO(&fds[i]); PJ_FD_SET(sock1, &fds[i]); PJ_FD_SET(sock2, &fds[i]); setcount[i] = 0; } timeout.sec = 1; timeout.msec = 0; n = pj_sock_select(PJ_IOQUEUE_MAX_HANDLES, &fds[0], &fds[1], &fds[2], &timeout); if (n < 0) return n; if (n == 0) return 0; for (i=0; i<3; ++i) { if (PJ_FD_ISSET(sock1, &fds[i])) setcount[i]++; if (PJ_FD_ISSET(sock2, &fds[i])) setcount[i]++; } return n; }
static int client_thread(void *unused) { PJ_UNUSED_ARG(unused); while (!client->quit) { pj_fd_set_t readset; pj_time_val delay = {0, 10}; /* Also poll the timer heap */ pj_timer_heap_poll(stun_cfg.timer_heap, NULL); /* Poll client socket */ PJ_FD_ZERO(&readset); PJ_FD_SET(client->sock, &readset); if (pj_sock_select((int)client->sock+1, &readset, NULL, NULL, &delay)==1 && PJ_FD_ISSET(client->sock, &readset)) { char pkt[1000]; pj_ssize_t len; pj_status_t status; pj_sockaddr src_addr; int src_addr_len; len = sizeof(pkt); src_addr_len = sizeof(src_addr); status = pj_sock_recvfrom(client->sock, pkt, &len, 0, &src_addr, &src_addr_len); if (status != PJ_SUCCESS) continue; /* Increment client's receive count */ client->recv_count++; /* Only pass to client if we allow to respond */ if (!client->responding) continue; pj_stun_session_on_rx_pkt(client->sess, pkt, len, PJ_STUN_CHECK_PACKET | PJ_STUN_IS_DATAGRAM, NULL, NULL, &src_addr, src_addr_len); } } return 0; }
static int server_thread(void *unused) { PJ_UNUSED_ARG(unused); PJ_LOG(5,("", " server thread started")); while (!server->quit) { pj_fd_set_t readset; pj_time_val delay = {0, 10}; PJ_FD_ZERO(&readset); PJ_FD_SET(server->sock, &readset); if (pj_sock_select((int)server->sock+1, &readset, NULL, NULL, &delay)==1 && PJ_FD_ISSET(server->sock, &readset)) { char pkt[1000]; pj_ssize_t len; pj_status_t status; pj_sockaddr src_addr; int src_addr_len; len = sizeof(pkt); src_addr_len = sizeof(src_addr); status = pj_sock_recvfrom(server->sock, pkt, &len, 0, &src_addr, &src_addr_len); if (status != PJ_SUCCESS) continue; /* Increment server's receive count */ server->recv_count++; /* Only pass to server if we allow to respond */ if (!server->responding) continue; pj_stun_session_on_rx_pkt(server->sess, pkt, len, PJ_STUN_CHECK_PACKET | PJ_STUN_IS_DATAGRAM, NULL, NULL, &src_addr, src_addr_len); } } return 0; }
static int server_thread_proc(void *p) { struct stun_test_session *test_sess = (struct stun_test_session*)p; pj_pool_t *pool; pj_status_t status; PJ_LOG(4,(THIS_FILE, "Server thread running")); pool = pj_pool_create(test_sess->stun_cfg.pf, "server", 512, 512, NULL); while (!test_sess->thread_quit_flag) { pj_time_val timeout = {0, 10}; pj_fd_set_t rdset; int n; /* Serve client */ PJ_FD_ZERO(&rdset); PJ_FD_SET(test_sess->server_sock, &rdset); n = pj_sock_select(test_sess->server_sock+1, &rdset, NULL, NULL, &timeout); if (n==1 && PJ_FD_ISSET(test_sess->server_sock, &rdset)) { pj_uint8_t pkt[512]; pj_ssize_t pkt_len; pj_size_t res_len; pj_sockaddr client_addr; int addr_len; pj_stun_msg *stun_req, *stun_res; pj_pool_reset(pool); /* Got query */ pkt_len = sizeof(pkt); addr_len = sizeof(client_addr); status = pj_sock_recvfrom(test_sess->server_sock, pkt, &pkt_len, 0, &client_addr, &addr_len); if (status != PJ_SUCCESS) { continue; } status = pj_stun_msg_decode(pool, pkt, pkt_len, PJ_STUN_IS_DATAGRAM, &stun_req, NULL, NULL); if (status != PJ_SUCCESS) { PJ_PERROR(1,(THIS_FILE, status, "STUN request decode error")); continue; } status = pj_stun_msg_create_response(pool, stun_req, PJ_STUN_SC_BAD_REQUEST, NULL, &stun_res); if (status != PJ_SUCCESS) { PJ_PERROR(1,(THIS_FILE, status, "STUN create response error")); continue; } status = pj_stun_msg_encode(stun_res, pkt, sizeof(pkt), 0, NULL, &res_len); if (status != PJ_SUCCESS) { PJ_PERROR(1,(THIS_FILE, status, "STUN encode error")); continue; } /* Ignore request */ if (test_sess->param.server_drop_request) continue; /* Wait for signal to continue */ if (test_sess->param.server_wait_for_event) pj_event_wait(test_sess->server_event); pkt_len = res_len; pj_sock_sendto(test_sess->server_sock, pkt, &pkt_len, 0, &client_addr, pj_sockaddr_get_len(&client_addr)); } } pj_pool_release(pool); PJ_LOG(4,(THIS_FILE, "Server thread quitting")); return 0; }
static int server_thread(void *p) { struct server_t *srv = (struct server_t*)p; char *pkt = (char*)pj_pool_alloc(pool, srv->buf_size); pj_sock_t newsock = PJ_INVALID_SOCKET; while (!thread_quit) { pj_ssize_t pkt_len; int rc; pj_fd_set_t rset; pj_time_val timeout = {0, 500}; while (!thread_quit) { PJ_FD_ZERO(&rset); PJ_FD_SET(srv->sock, &rset); rc = pj_sock_select((int)srv->sock+1, &rset, NULL, NULL, &timeout); if (rc != 1) { continue; } rc = pj_sock_accept(srv->sock, &newsock, NULL, NULL); if (rc == PJ_SUCCESS) { break; } } if (thread_quit) break; while (!thread_quit) { PJ_FD_ZERO(&rset); PJ_FD_SET(newsock, &rset); rc = pj_sock_select((int)newsock+1, &rset, NULL, NULL, &timeout); if (rc != 1) { PJ_LOG(3,("http test", "client timeout")); continue; } pkt_len = srv->buf_size; rc = pj_sock_recv(newsock, pkt, &pkt_len, 0); if (rc == PJ_SUCCESS) { break; } } if (thread_quit) break; /* Simulate network RTT */ pj_thread_sleep(50); if (srv->action == ACTION_IGNORE) { continue; } else if (srv->action == ACTION_REPLY) { pj_size_t send_size = 0; unsigned ctr = 0; pj_ansi_sprintf(pkt, "HTTP/1.0 200 OK\r\n"); if (srv->send_content_length) { pj_ansi_sprintf(pkt + pj_ansi_strlen(pkt), "Content-Length: %d\r\n", srv->data_size); } pj_ansi_sprintf(pkt + pj_ansi_strlen(pkt), "\r\n"); pkt_len = pj_ansi_strlen(pkt); rc = pj_sock_send(newsock, pkt, &pkt_len, 0); if (rc != PJ_SUCCESS) { pj_sock_close(newsock); continue; } while (send_size < srv->data_size) { pkt_len = srv->data_size - send_size; if (pkt_len > (signed)srv->buf_size) pkt_len = srv->buf_size; send_size += pkt_len; pj_create_random_string(pkt, pkt_len); pj_ansi_sprintf(pkt, "\nPacket: %d", ++ctr); pkt[pj_ansi_strlen(pkt)] = '\n'; rc = pj_sock_send(newsock, pkt, &pkt_len, 0); if (rc != PJ_SUCCESS) break; } pj_sock_close(newsock); } } return 0; }
PJ_DEF(pj_status_t) pjstun_get_mapped_addr( pj_pool_factory *pf, int sock_cnt, pj_sock_t sock[], const pj_str_t *srv1, int port1, const pj_str_t *srv2, int port2, pj_sockaddr_in mapped_addr[]) { unsigned srv_cnt; pj_sockaddr_in srv_addr[2]; int i, j, send_cnt = 0, nfds; pj_pool_t *pool; struct query_rec { struct { pj_uint32_t mapped_addr; pj_uint32_t mapped_port; } srv[2]; } *rec; void *out_msg; pj_size_t out_msg_len; int wait_resp = 0; pj_status_t status; PJ_CHECK_STACK(); TRACE_((THIS_FILE, "Entering pjstun_get_mapped_addr()")); /* Create pool. */ pool = pj_pool_create(pf, "stun%p", 400, 400, NULL); if (!pool) return PJ_ENOMEM; /* Allocate client records */ rec = (struct query_rec*) pj_pool_calloc(pool, sock_cnt, sizeof(*rec)); if (!rec) { status = PJ_ENOMEM; goto on_error; } TRACE_((THIS_FILE, " Memory allocated.")); /* Create the outgoing BIND REQUEST message template */ status = pjstun_create_bind_req( pool, &out_msg, &out_msg_len, pj_rand(), pj_rand()); if (status != PJ_SUCCESS) goto on_error; TRACE_((THIS_FILE, " Binding request created.")); /* Resolve servers. */ status = pj_sockaddr_in_init(&srv_addr[0], srv1, (pj_uint16_t)port1); if (status != PJ_SUCCESS) goto on_error; srv_cnt = 1; if (srv2 && port2) { status = pj_sockaddr_in_init(&srv_addr[1], srv2, (pj_uint16_t)port2); if (status != PJ_SUCCESS) goto on_error; if (srv_addr[1].sin_addr.s_addr != srv_addr[0].sin_addr.s_addr && srv_addr[1].sin_port != srv_addr[0].sin_port) { srv_cnt++; } } TRACE_((THIS_FILE, " Server initialized, using %d server(s)", srv_cnt)); /* Init mapped addresses to zero */ pj_memset(mapped_addr, 0, sock_cnt * sizeof(pj_sockaddr_in)); /* We need these many responses */ wait_resp = sock_cnt * srv_cnt; TRACE_((THIS_FILE, " Done initialization.")); #if defined(PJ_SELECT_NEEDS_NFDS) && PJ_SELECT_NEEDS_NFDS!=0 nfds = -1; for (i=0; i<sock_cnt; ++i) { if (sock[i] > nfds) { nfds = sock[i]; } } #else nfds = FD_SETSIZE-1; #endif /* Main retransmission loop. */ for (send_cnt=0; send_cnt<MAX_REQUEST; ++send_cnt) { pj_time_val next_tx, now; pj_fd_set_t r; int select_rc; PJ_FD_ZERO(&r); /* Send messages to servers that has not given us response. */ for (i=0; i<sock_cnt && status==PJ_SUCCESS; ++i) { for (j=0; j<srv_cnt && status==PJ_SUCCESS; ++j) { pjstun_msg_hdr *msg_hdr = (pjstun_msg_hdr*) out_msg; pj_ssize_t sent_len; if (rec[i].srv[j].mapped_port != 0) continue; /* Modify message so that we can distinguish response. */ msg_hdr->tsx[2] = pj_htonl(i); msg_hdr->tsx[3] = pj_htonl(j); /* Send! */ sent_len = out_msg_len; status = pj_sock_sendto(sock[i], out_msg, &sent_len, 0, (pj_sockaddr_t*)&srv_addr[j], sizeof(pj_sockaddr_in)); } } /* All requests sent. * The loop below will wait for responses until all responses have * been received (i.e. wait_resp==0) or timeout occurs, which then * we'll go to the next retransmission iteration. */ TRACE_((THIS_FILE, " Request(s) sent, counter=%d", send_cnt)); /* Calculate time of next retransmission. */ pj_gettimeofday(&next_tx); next_tx.sec += (stun_timer[send_cnt]/1000); next_tx.msec += (stun_timer[send_cnt]%1000); pj_time_val_normalize(&next_tx); for (pj_gettimeofday(&now), select_rc=1; status==PJ_SUCCESS && select_rc>=1 && wait_resp>0 && PJ_TIME_VAL_LT(now, next_tx); pj_gettimeofday(&now)) { pj_time_val timeout; timeout = next_tx; PJ_TIME_VAL_SUB(timeout, now); for (i=0; i<sock_cnt; ++i) { PJ_FD_SET(sock[i], &r); } select_rc = pj_sock_select(nfds+1, &r, NULL, NULL, &timeout); TRACE_((THIS_FILE, " select() rc=%d", select_rc)); if (select_rc < 1) continue; for (i=0; i<sock_cnt; ++i) { int sock_idx, srv_idx; pj_ssize_t len; pjstun_msg msg; pj_sockaddr_in addr; int addrlen = sizeof(addr); pjstun_mapped_addr_attr *attr; char recv_buf[128]; if (!PJ_FD_ISSET(sock[i], &r)) continue; len = sizeof(recv_buf); status = pj_sock_recvfrom( sock[i], recv_buf, &len, 0, (pj_sockaddr_t*)&addr, &addrlen); if (status != PJ_SUCCESS) { char errmsg[PJ_ERR_MSG_SIZE]; PJ_LOG(4,(THIS_FILE, "recvfrom() error ignored: %s", pj_strerror(status, errmsg,sizeof(errmsg)).ptr)); /* Ignore non-PJ_SUCCESS status. * It possible that other SIP entity is currently * sending SIP request to us, and because SIP message * is larger than STUN, we could get EMSGSIZE when * we call recvfrom(). */ status = PJ_SUCCESS; continue; } status = pjstun_parse_msg(recv_buf, len, &msg); if (status != PJ_SUCCESS) { char errmsg[PJ_ERR_MSG_SIZE]; PJ_LOG(4,(THIS_FILE, "STUN parsing error ignored: %s", pj_strerror(status, errmsg,sizeof(errmsg)).ptr)); /* Also ignore non-successful parsing. This may not * be STUN response at all. See the comment above. */ status = PJ_SUCCESS; continue; } sock_idx = pj_ntohl(msg.hdr->tsx[2]); srv_idx = pj_ntohl(msg.hdr->tsx[3]); if (sock_idx<0 || sock_idx>=sock_cnt || sock_idx!=i || srv_idx<0 || srv_idx>=2) { status = PJLIB_UTIL_ESTUNININDEX; continue; } if (pj_ntohs(msg.hdr->type) != PJSTUN_BINDING_RESPONSE) { status = PJLIB_UTIL_ESTUNNOBINDRES; continue; } if (rec[sock_idx].srv[srv_idx].mapped_port != 0) { /* Already got response */ continue; } /* From this part, we consider the packet as a valid STUN * response for our request. */ --wait_resp; if (pjstun_msg_find_attr(&msg, PJSTUN_ATTR_ERROR_CODE) != NULL) { status = PJLIB_UTIL_ESTUNRECVERRATTR; continue; } attr = (pjstun_mapped_addr_attr*) pjstun_msg_find_attr(&msg, PJSTUN_ATTR_MAPPED_ADDR); if (!attr) { attr = (pjstun_mapped_addr_attr*) pjstun_msg_find_attr(&msg, PJSTUN_ATTR_XOR_MAPPED_ADDR); if (!attr || attr->family != 1) { status = PJLIB_UTIL_ESTUNNOMAP; continue; } } rec[sock_idx].srv[srv_idx].mapped_addr = attr->addr; rec[sock_idx].srv[srv_idx].mapped_port = attr->port; if (pj_ntohs(attr->hdr.type) == PJSTUN_ATTR_XOR_MAPPED_ADDR) { rec[sock_idx].srv[srv_idx].mapped_addr ^= pj_htonl(STUN_MAGIC); rec[sock_idx].srv[srv_idx].mapped_port ^= pj_htons(STUN_MAGIC >> 16); } } } /* The best scenario is if all requests have been replied. * Then we don't need to go to the next retransmission iteration. */ if (wait_resp <= 0) break; }
/* * pj_ioqueue_poll() * * Few things worth written: * * - we used to do only one callback called per poll, but it didn't go * very well. The reason is because on some situation, the write * callback gets called all the time, thus doesn't give the read * callback to get called. This happens, for example, when user * submit write operation inside the write callback. * As the result, we changed the behaviour so that now multiple * callbacks are called in a single poll. It should be fast too, * just that we need to be carefull with the ioqueue data structs. * * - to guarantee preemptiveness etc, the poll function must strictly * work on fd_set copy of the ioqueue (not the original one). */ PJ_DEF(int) pj_ioqueue_poll( pj_ioqueue_t *ioqueue, const pj_time_val *timeout) { pj_fd_set_t rfdset, wfdset, xfdset; int count, counter; pj_ioqueue_key_t *h; struct event { pj_ioqueue_key_t *key; enum ioqueue_event_type event_type; } event[PJ_IOQUEUE_MAX_EVENTS_IN_SINGLE_POLL]; PJ_ASSERT_RETURN(ioqueue, -PJ_EINVAL); /* Lock ioqueue before making fd_set copies */ pj_lock_acquire(ioqueue->lock); /* We will only do select() when there are sockets to be polled. * Otherwise select() will return error. */ if (PJ_FD_COUNT(&ioqueue->rfdset)==0 && PJ_FD_COUNT(&ioqueue->wfdset)==0 #if defined(PJ_HAS_TCP) && PJ_HAS_TCP!=0 && PJ_FD_COUNT(&ioqueue->xfdset)==0 #endif ) { #if PJ_IOQUEUE_HAS_SAFE_UNREG scan_closing_keys(ioqueue); #endif pj_lock_release(ioqueue->lock); TRACE__((THIS_FILE, " poll: no fd is set")); if (timeout) pj_thread_sleep(PJ_TIME_VAL_MSEC(*timeout)); return 0; } /* Copy ioqueue's pj_fd_set_t to local variables. */ pj_memcpy(&rfdset, &ioqueue->rfdset, sizeof(pj_fd_set_t)); pj_memcpy(&wfdset, &ioqueue->wfdset, sizeof(pj_fd_set_t)); #if PJ_HAS_TCP pj_memcpy(&xfdset, &ioqueue->xfdset, sizeof(pj_fd_set_t)); #else PJ_FD_ZERO(&xfdset); #endif #if VALIDATE_FD_SET validate_sets(ioqueue, &rfdset, &wfdset, &xfdset); #endif /* Unlock ioqueue before select(). */ pj_lock_release(ioqueue->lock); count = pj_sock_select(ioqueue->nfds+1, &rfdset, &wfdset, &xfdset, timeout); if (count == 0) return 0; else if (count < 0) return -pj_get_netos_error(); else if (count > PJ_IOQUEUE_MAX_EVENTS_IN_SINGLE_POLL) count = PJ_IOQUEUE_MAX_EVENTS_IN_SINGLE_POLL; /* Scan descriptor sets for event and add the events in the event * array to be processed later in this function. We do this so that * events can be processed in parallel without holding ioqueue lock. */ pj_lock_acquire(ioqueue->lock); counter = 0; /* Scan for writable sockets first to handle piggy-back data * coming with accept(). */ h = ioqueue->active_list.next; for ( ; h!=&ioqueue->active_list && counter<count; h = h->next) { if ( (key_has_pending_write(h) || key_has_pending_connect(h)) && PJ_FD_ISSET(h->fd, &wfdset) && !IS_CLOSING(h)) { #if PJ_IOQUEUE_HAS_SAFE_UNREG increment_counter(h); #endif event[counter].key = h; event[counter].event_type = WRITEABLE_EVENT; ++counter; } /* Scan for readable socket. */ if ((key_has_pending_read(h) || key_has_pending_accept(h)) && PJ_FD_ISSET(h->fd, &rfdset) && !IS_CLOSING(h) && counter<count) { #if PJ_IOQUEUE_HAS_SAFE_UNREG increment_counter(h); #endif event[counter].key = h; event[counter].event_type = READABLE_EVENT; ++counter; } #if PJ_HAS_TCP if (key_has_pending_connect(h) && PJ_FD_ISSET(h->fd, &xfdset) && !IS_CLOSING(h) && counter<count) { #if PJ_IOQUEUE_HAS_SAFE_UNREG increment_counter(h); #endif event[counter].key = h; event[counter].event_type = EXCEPTION_EVENT; ++counter; } #endif } pj_lock_release(ioqueue->lock); count = counter; /* Now process all events. The dispatch functions will take care * of locking in each of the key */ for (counter=0; counter<count; ++counter) { switch (event[counter].event_type) { case READABLE_EVENT: ioqueue_dispatch_read_event(ioqueue, event[counter].key); break; case WRITEABLE_EVENT: ioqueue_dispatch_write_event(ioqueue, event[counter].key); break; case EXCEPTION_EVENT: ioqueue_dispatch_exception_event(ioqueue, event[counter].key); break; case NO_EVENT: pj_assert(!"Invalid event!"); break; } #if PJ_IOQUEUE_HAS_SAFE_UNREG decrement_counter(event[counter].key); #endif } return count; }
/* * pj_ioqueue_create() * * Create select ioqueue. */ PJ_DEF(pj_status_t) pj_ioqueue_create( pj_pool_t *pool, pj_size_t max_fd, pj_ioqueue_t **p_ioqueue) { pj_ioqueue_t *ioqueue; pj_lock_t *lock; unsigned i; pj_status_t rc; /* Check that arguments are valid. */ PJ_ASSERT_RETURN(pool != NULL && p_ioqueue != NULL && max_fd > 0 && max_fd <= PJ_IOQUEUE_MAX_HANDLES, PJ_EINVAL); /* Check that size of pj_ioqueue_op_key_t is sufficient */ PJ_ASSERT_RETURN(sizeof(pj_ioqueue_op_key_t)-sizeof(void*) >= sizeof(union operation_key), PJ_EBUG); /* Create and init common ioqueue stuffs */ ioqueue = PJ_POOL_ALLOC_T(pool, pj_ioqueue_t); ioqueue_init(ioqueue); ioqueue->max = max_fd; ioqueue->count = 0; PJ_FD_ZERO(&ioqueue->rfdset); PJ_FD_ZERO(&ioqueue->wfdset); #if PJ_HAS_TCP PJ_FD_ZERO(&ioqueue->xfdset); #endif pj_list_init(&ioqueue->active_list); rescan_fdset(ioqueue); #if PJ_IOQUEUE_HAS_SAFE_UNREG /* When safe unregistration is used (the default), we pre-create * all keys and put them in the free list. */ /* Mutex to protect key's reference counter * We don't want to use key's mutex or ioqueue's mutex because * that would create deadlock situation in some cases. */ rc = pj_mutex_create_simple(pool, NULL, &ioqueue->ref_cnt_mutex); if (rc != PJ_SUCCESS) return rc; /* Init key list */ pj_list_init(&ioqueue->free_list); pj_list_init(&ioqueue->closing_list); /* Pre-create all keys according to max_fd */ for (i=0; i<max_fd; ++i) { pj_ioqueue_key_t *key; key = PJ_POOL_ALLOC_T(pool, pj_ioqueue_key_t); key->ref_count = 0; rc = pj_mutex_create_recursive(pool, NULL, &key->mutex); if (rc != PJ_SUCCESS) { key = ioqueue->free_list.next; while (key != &ioqueue->free_list) { pj_mutex_destroy(key->mutex); key = key->next; } pj_mutex_destroy(ioqueue->ref_cnt_mutex); return rc; } pj_list_push_back(&ioqueue->free_list, key); } #endif /* Create and init ioqueue mutex */ rc = pj_lock_create_simple_mutex(pool, "ioq%p", &lock); if (rc != PJ_SUCCESS) return rc; rc = pj_ioqueue_set_lock(ioqueue, lock, PJ_TRUE); if (rc != PJ_SUCCESS) return rc; PJ_LOG(4, ("pjlib", "select() I/O Queue created (%p)", ioqueue)); *p_ioqueue = ioqueue; return PJ_SUCCESS; }
static int thread_proc(void *data) { dupsock_t *p_dupsock = (dupsock_t *)data; pj_thread_t *thread; pj_thread_desc desc; struct pj_time_val tv; int ret; pj_ssize_t ntemp; int sock_len; // pj_bzero(desc, sizeof(desc)); // CHECK(__FILE__, pj_thread_register("dupsock", desc, &thread)); PJ_FD_ZERO(&(p_dupsock->rfds)); PJ_FD_ZERO(&(p_dupsock->wfds)); PJ_FD_SET(*(p_dupsock->p_sock), &(p_dupsock->rfds)); tv.sec = 0; tv.msec = 20; // MAIN LOOP p_dupsock->b_quit = 0; while( (!p_dupsock->b_quit) || (p_dupsock->wait_cnt > 0) || (p_dupsock->to_send != NULL) ) { if(p_dupsock->wait_cnt > 0) { p_dupsock->wait_cnt--; pj_event_pulse(p_dupsock->p_event); } pj_thread_sleep(10); PJ_FD_ZERO(&(p_dupsock->rfds)); PJ_FD_ZERO(&(p_dupsock->wfds)); PJ_FD_SET(*(p_dupsock->p_sock), &(p_dupsock->rfds)); if(p_dupsock->to_send != NULL) PJ_FD_SET(*(p_dupsock->p_sock), &(p_dupsock->wfds)); ret = pj_sock_select(*(p_dupsock->p_sock) + 1, &(p_dupsock->rfds), &(p_dupsock->wfds), NULL, &tv); if( ret < 0 ) { PJ_LOG(2, (__FILE__, "Error in select")); } else if (ret > 0) { if( PJ_FD_ISSET( *(p_dupsock->p_sock), &(p_dupsock->rfds)) ) { ntemp = sizeof(p_dupsock->in_buffer); sock_len = sizeof(p_dupsock->in_packet.addr); pj_sock_recvfrom(*(p_dupsock->p_sock), p_dupsock->in_packet.data, &ntemp, 0, (pj_sockaddr_t *)(&(p_dupsock->in_packet.addr)), &sock_len); p_dupsock->in_packet.len = ntemp; if(p_dupsock->recv_callback != NULL) { p_dupsock->recv_callback(p_dupsock); } p_dupsock->in_packet.len = 0; } if( PJ_FD_ISSET( *(p_dupsock->p_sock), &(p_dupsock->wfds)) ) { ntemp = p_dupsock->to_send->len - p_dupsock->to_send->sent; pj_sock_sendto(*(p_dupsock->p_sock), p_dupsock->to_send->data + p_dupsock->to_send->sent, &ntemp, 0, (pj_sockaddr_t *)(&(p_dupsock->to_send->addr)), sizeof(p_dupsock->to_send->addr)); p_dupsock->to_send->sent += ntemp; if(p_dupsock->to_send->len == p_dupsock->to_send->sent) { if(p_dupsock->send_callback != NULL) { p_dupsock->send_callback(p_dupsock); } p_dupsock->to_send = NULL; PJ_FD_CLR(*(p_dupsock->p_sock), &(p_dupsock->wfds)); } } } //PJ_LOG(5, (__FILE__, "end of a loop")); } pj_event_destroy(p_dupsock->p_event); pj_sock_close(*(p_dupsock->p_sock)); return 0; }
PJ_DECL(pj_status_t) pjstun_get_mapped_addr( pj_pool_factory *pf, int sock_cnt, pj_sock_t sock[], const pj_str_t *srv1, int port1, const pj_str_t *srv2, int port2, pj_sockaddr_in mapped_addr[]) { pj_sockaddr_in srv_addr[2]; int i, j, send_cnt = 0; pj_pool_t *pool; struct { struct { pj_uint32_t mapped_addr; pj_uint32_t mapped_port; } srv[2]; } *rec; void *out_msg; pj_size_t out_msg_len; int wait_resp = 0; pj_status_t status; PJ_CHECK_STACK(); /* Create pool. */ pool = pj_pool_create(pf, "stun%p", 1024, 1024, NULL); if (!pool) return PJ_ENOMEM; /* Allocate client records */ rec = pj_pool_calloc(pool, sock_cnt, sizeof(*rec)); if (!rec) { status = PJ_ENOMEM; goto on_error; } /* Create the outgoing BIND REQUEST message template */ status = pjstun_create_bind_req( pool, &out_msg, &out_msg_len, pj_rand(), pj_rand()); if (status != PJ_SUCCESS) goto on_error; /* Resolve servers. */ status = pj_sockaddr_in_init(&srv_addr[0], srv1, (pj_uint16_t)port1); if (status != PJ_SUCCESS) goto on_error; status = pj_sockaddr_in_init(&srv_addr[1], srv2, (pj_uint16_t)port2); if (status != PJ_SUCCESS) goto on_error; /* Init mapped addresses to zero */ pj_memset(mapped_addr, 0, sock_cnt * sizeof(pj_sockaddr_in)); /* Main retransmission loop. */ for (send_cnt=0; send_cnt<MAX_REQUEST; ++send_cnt) { pj_time_val next_tx, now; pj_fd_set_t r; int select_rc; PJ_FD_ZERO(&r); /* Send messages to servers that has not given us response. */ for (i=0; i<sock_cnt && status==PJ_SUCCESS; ++i) { for (j=0; j<2 && status==PJ_SUCCESS; ++j) { pjstun_msg_hdr *msg_hdr = out_msg; pj_ssize_t sent_len; if (rec[i].srv[j].mapped_port != 0) continue; /* Modify message so that we can distinguish response. */ msg_hdr->tsx[2] = pj_htonl(i); msg_hdr->tsx[3] = pj_htonl(j); /* Send! */ sent_len = out_msg_len; status = pj_sock_sendto(sock[i], out_msg, &sent_len, 0, (pj_sockaddr_t*)&srv_addr[j], sizeof(pj_sockaddr_in)); if (status == PJ_SUCCESS) ++wait_resp; } } /* All requests sent. * The loop below will wait for responses until all responses have * been received (i.e. wait_resp==0) or timeout occurs, which then * we'll go to the next retransmission iteration. */ /* Calculate time of next retransmission. */ pj_gettimeofday(&next_tx); next_tx.sec += (stun_timer[send_cnt]/1000); next_tx.msec += (stun_timer[send_cnt]%1000); pj_time_val_normalize(&next_tx); for (pj_gettimeofday(&now), select_rc=1; status==PJ_SUCCESS && select_rc==1 && wait_resp>0 && PJ_TIME_VAL_LT(now, next_tx); pj_gettimeofday(&now)) { pj_time_val timeout; timeout = next_tx; PJ_TIME_VAL_SUB(timeout, now); for (i=0; i<sock_cnt; ++i) { PJ_FD_SET(sock[i], &r); } select_rc = pj_sock_select(FD_SETSIZE, &r, NULL, NULL, &timeout); if (select_rc < 1) continue; for (i=0; i<sock_cnt; ++i) { int sock_idx, srv_idx; pj_ssize_t len; pjstun_msg msg; pj_sockaddr_in addr; int addrlen = sizeof(addr); pjstun_mapped_addr_attr *attr; char recv_buf[128]; if (!PJ_FD_ISSET(sock[i], &r)) continue; len = sizeof(recv_buf); status = pj_sock_recvfrom( sock[i], recv_buf, &len, 0, (pj_sockaddr_t*)&addr, &addrlen); --wait_resp; if (status != PJ_SUCCESS) continue; status = pjstun_parse_msg(recv_buf, len, &msg); if (status != PJ_SUCCESS) { continue; } sock_idx = pj_ntohl(msg.hdr->tsx[2]); srv_idx = pj_ntohl(msg.hdr->tsx[3]); if (sock_idx<0 || sock_idx>=sock_cnt || srv_idx<0 || srv_idx>=2) { status = PJLIB_UTIL_ESTUNININDEX; continue; } if (pj_ntohs(msg.hdr->type) != PJSTUN_BINDING_RESPONSE) { status = PJLIB_UTIL_ESTUNNOBINDRES; continue; } if (pjstun_msg_find_attr(&msg, PJSTUN_ATTR_ERROR_CODE) != NULL) { status = PJLIB_UTIL_ESTUNRECVERRATTR; continue; } attr = (void*)pjstun_msg_find_attr(&msg, PJSTUN_ATTR_MAPPED_ADDR); if (!attr) { status = PJLIB_UTIL_ESTUNNOMAP; continue; } rec[sock_idx].srv[srv_idx].mapped_addr = attr->addr; rec[sock_idx].srv[srv_idx].mapped_port = attr->port; } } /* The best scenario is if all requests have been replied. * Then we don't need to go to the next retransmission iteration. */ if (wait_resp <= 0) break; } for (i=0; i<sock_cnt && status==PJ_SUCCESS; ++i) { if (rec[i].srv[0].mapped_addr == rec[i].srv[1].mapped_addr && rec[i].srv[0].mapped_port == rec[i].srv[1].mapped_port) { mapped_addr[i].sin_family = PJ_AF_INET; mapped_addr[i].sin_addr.s_addr = rec[i].srv[0].mapped_addr; mapped_addr[i].sin_port = (pj_uint16_t)rec[i].srv[0].mapped_port; if (rec[i].srv[0].mapped_addr == 0 || rec[i].srv[0].mapped_port == 0) { status = PJLIB_UTIL_ESTUNNOTRESPOND; break; } } else { status = PJLIB_UTIL_ESTUNSYMMETRIC; break; } } pj_pool_release(pool); return status; on_error: if (pool) pj_pool_release(pool); return status; }
pj_status_t pj_open_tcp_serverport(pj_str_t *ip, pj_uint16_t port, pj_sock_t &sock) { pj_status_t status; status = pj_sock_socket(pj_AF_INET(), pj_SOCK_STREAM(), 0, &sock); RETURN_VAL_IF_FAIL( status == PJ_SUCCESS, status ); int enabled = 1; status = pj_sock_setsockopt(sock, pj_SOL_SOCKET(), pj_SO_REUSEADDR(), &enabled, sizeof(enabled)); RETURN_VAL_IF_FAIL( status == PJ_SUCCESS, (pj_sock_close(sock), status) ); pj_sockaddr_in addr; status = pj_sockaddr_in_init(&addr, ip, port); RETURN_VAL_IF_FAIL( status == PJ_SUCCESS, (pj_sock_close(sock), status) ); status = pj_sock_bind(sock, &addr, pj_sockaddr_get_len(&addr)); RETURN_VAL_IF_FAIL( status == PJ_SUCCESS, (pj_sock_close(sock), status) ); status = pj_sock_listen(sock, 5); RETURN_VAL_IF_FAIL( status == PJ_SUCCESS, (pj_sock_close(sock), status) ); u_long val = 1; #if defined(PJ_WIN32) && PJ_WIN32!=0 || \ defined(PJ_WIN64) && PJ_WIN64 != 0 || \ defined(PJ_WIN32_WINCE) && PJ_WIN32_WINCE!=0 if (ioctlsocket(sock, FIONBIO, &val)) { #else if (ioctl(new_sock, FIONBIO, &val)) { #endif pj_sock_close(sock); return -1; } return status; } pj_status_t pj_open_tcp_clientport(pj_str_t *ip, pj_uint16_t port, pj_sock_t &sock) { pj_status_t status; status = pj_sock_socket(pj_AF_INET(), pj_SOCK_STREAM(), 0, &sock); RETURN_VAL_IF_FAIL( status == PJ_SUCCESS, status ); pj_sockaddr_in addr; status = pj_sockaddr_in_init(&addr, ip, port); RETURN_VAL_IF_FAIL( status == PJ_SUCCESS, (pj_sock_close(sock), status) ); u_long val = 1; #if defined(PJ_WIN32) && PJ_WIN32!=0 || \ defined(PJ_WIN64) && PJ_WIN64 != 0 || \ defined(PJ_WIN32_WINCE) && PJ_WIN32_WINCE!=0 if (ioctlsocket(sock, FIONBIO, &val)) { #else if (ioctl(new_sock, FIONBIO, &val)) { #endif pj_sock_close(sock); return -1; } status = pj_sock_connect(sock, &addr, sizeof(addr)); pj_time_val timeout = {2, 0}; // connect³¬Ê±Ê±¼ä1Ãë pj_fd_set_t rset, wset; PJ_FD_ZERO(&rset); PJ_FD_ZERO(&wset); PJ_FD_SET(sock, &rset); PJ_FD_SET(sock, &wset); int selret = pj_sock_select(sock + 1, &rset, &wset, nullptr, &timeout); switch(selret) { case -1: return PJ_EINVAL; case 0: return PJ_ETIMEDOUT; default: { if(PJ_FD_ISSET(sock, &rset) || PJ_FD_ISSET(sock, &wset)) { return PJ_SUCCESS; } else { return PJ_EINVAL; } } } return PJ_EINVAL; } pj_status_t pj_open_udp_transport(pj_str_t *ip, pj_uint16_t port, pj_sock_t &sock) { pj_status_t status; status = pj_sock_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0, &sock); RETURN_VAL_IF_FAIL( status == PJ_SUCCESS, status ); int enabled = 1; status = pj_sock_setsockopt(sock, pj_SOL_SOCKET(), pj_SO_REUSEADDR(), &enabled, sizeof(enabled)); RETURN_VAL_IF_FAIL( status == PJ_SUCCESS, (pj_sock_close(sock), status) ); if ( ip != nullptr && port > 0 ) { pj_sockaddr_in addr; status = pj_sockaddr_in_init(&addr, ip, port); RETURN_VAL_IF_FAIL( status == PJ_SUCCESS, (pj_sock_close(sock), status) ); status = pj_sock_bind(sock, &addr, pj_sockaddr_get_len(&addr)); RETURN_VAL_IF_FAIL( status == PJ_SUCCESS, (pj_sock_close(sock), status) ); } u_long val = 1; #if defined(PJ_WIN32) && PJ_WIN32!=0 || \ defined(PJ_WIN64) && PJ_WIN64 != 0 || \ defined(PJ_WIN32_WINCE) && PJ_WIN32_WINCE!=0 if (ioctlsocket(sock, FIONBIO, &val)) { #else if (ioctl(new_sock, FIONBIO, &val)) { #endif pj_sock_close(sock); return -1; } return status; } pj_uint64_t pj_ntohll(pj_uint64_t netlonglong) { return ntohll(netlonglong); } pj_uint64_t pj_htonll(pj_uint64_t hostlonglong) { return htonll(hostlonglong); } static pj_oshandle_t g_log_handle; pj_status_t log_open(pj_pool_t *pool, const pj_str_t &file_name) { pj_log_set_log_func(log_writer); return pj_file_open(pool, file_name.ptr, PJ_O_WRONLY | PJ_O_APPEND, &g_log_handle); }
PJ_DEF(int) pj_ioqueue_poll( pj_ioqueue_t *ioque, const pj_time_val *timeout) { pj_fdset_t rfdset, wfdset, xfdset; int rc; pj_ioqueue_key_t *h; /* Copy ioqueue's fd_set to local variables. */ pj_mutex_lock(ioque->mutex); rfdset = ioque->rfdset; wfdset = ioque->wfdset; #if PJ_HAS_TCP xfdset = ioque->xfdset; #else PJ_FD_ZERO(&xfdset); #endif /* Unlock ioqueue before select(). */ pj_mutex_unlock(ioque->mutex); rc = pj_sock_select(FD_SETSIZE, &rfdset, &wfdset, &xfdset, timeout); if (rc <= 0) return rc; /* Lock ioqueue again before scanning for signalled sockets. */ pj_mutex_lock(ioque->mutex); #if PJ_HAS_TCP /* Scan for exception socket */ h = ioque->hlist.next; for ( ; h!=&ioque->hlist; h = h->next) { if ((h->op & PJ_IOQUEUE_OP_CONNECT) && PJ_FD_ISSET(h->fd, &xfdset)) break; } if (h != &ioque->hlist) { /* 'connect()' should be the only operation. */ pj_assert((h->op == PJ_IOQUEUE_OP_CONNECT)); /* Clear operation. */ h->op &= ~(PJ_IOQUEUE_OP_CONNECT); PJ_FD_CLR(h->fd, &ioque->wfdset); PJ_FD_CLR(h->fd, &ioque->xfdset); /* Unlock I/O queue before calling callback. */ pj_mutex_unlock(ioque->mutex); /* Call callback. */ (*h->cb.on_connect_complete)(h, -1); return 1; } #endif /* PJ_HAS_TCP */ /* Scan for writable socket */ h = ioque->hlist.next; for ( ; h!=&ioque->hlist; h = h->next) { if ((PJ_IOQUEUE_IS_WRITE_OP(h->op) || PJ_IOQUEUE_IS_CONNECT_OP(h->op)) && PJ_FD_ISSET(h->fd, &wfdset)) break; } if (h != &ioque->hlist) { pj_assert(PJ_IOQUEUE_IS_WRITE_OP(h->op) || PJ_IOQUEUE_IS_CONNECT_OP(h->op)); #if PJ_HAS_TCP if ((h->op & PJ_IOQUEUE_OP_CONNECT)) { /* Completion of connect() operation */ pj_ssize_t bytes_transfered; #if defined(PJ_LINUX) /* from connect(2): * On Linux, use getsockopt to read the SO_ERROR option at * level SOL_SOCKET to determine whether connect() completed * successfully (if SO_ERROR is zero). */ int value; socklen_t vallen = sizeof(value); int rc = getsockopt(h->fd, SOL_SOCKET, SO_ERROR, &value, &vallen); if (rc != 0) { /* Argh!! What to do now??? * Just indicate that the socket is connected. The * application will get error as soon as it tries to use * the socket to send/receive. */ PJ_PERROR(("ioqueue", "Unable to determine connect() status")); bytes_transfered = 0; } else { bytes_transfered = value; } #elif defined(PJ_WIN32) bytes_transfered = 0; /* success */ #else # error "Got to check this one!" #endif /* Clear operation. */ h->op &= (~PJ_IOQUEUE_OP_CONNECT); PJ_FD_CLR(h->fd, &ioque->wfdset); PJ_FD_CLR(h->fd, &ioque->xfdset); /* Unlock mutex before calling callback. */ pj_mutex_unlock(ioque->mutex); /* Call callback. */ (*h->cb.on_connect_complete)(h, bytes_transfered); return 1; } else #endif /* PJ_HAS_TCP */ { /* Completion of write(), send(), or sendto() operation. */ /* Clear operation. */ h->op &= ~(PJ_IOQUEUE_OP_WRITE | PJ_IOQUEUE_OP_SEND_TO); PJ_FD_CLR(h->fd, &ioque->wfdset); /* Unlock mutex before calling callback. */ pj_mutex_unlock(ioque->mutex); /* Call callback. */ /* All data must have been sent? */ (*h->cb.on_write_complete)(h, h->wr_buflen); return 1; } /* Unreached. */ } /* Scan for readable socket. */ h = ioque->hlist.next; for ( ; h!=&ioque->hlist; h = h->next) { if ((PJ_IOQUEUE_IS_READ_OP(h->op) || PJ_IOQUEUE_IS_ACCEPT_OP(h->op)) && PJ_FD_ISSET(h->fd, &rfdset)) break; } if (h != &ioque->hlist) { pj_assert(PJ_IOQUEUE_IS_READ_OP(h->op) || PJ_IOQUEUE_IS_ACCEPT_OP(h->op)); # if PJ_HAS_TCP if ((h->op & PJ_IOQUEUE_OP_ACCEPT)) { /* accept() must be the only operation specified on server socket */ pj_assert(h->op == PJ_IOQUEUE_OP_ACCEPT); *h->accept_fd = pj_sock_accept(h->fd, h->rmt_addr, h->rmt_addrlen); if (*h->accept_fd == PJ_INVALID_SOCKET) { rc = -1; } else if (h->local_addr) { rc = pj_sock_getsockname(*h->accept_fd, h->local_addr, h->local_addrlen); } else { rc = 0; } h->op &= ~(PJ_IOQUEUE_OP_ACCEPT); PJ_FD_CLR(h->fd, &ioque->rfdset); /* Unlock mutex before calling callback. */ pj_mutex_unlock(ioque->mutex); /* Call callback. */ (*h->cb.on_accept_complete)(h, rc); return 1; } else # endif if ((h->op & PJ_IOQUEUE_OP_RECV_FROM)) { rc = pj_sock_recvfrom(h->fd, h->rd_buf, h->rd_buflen, 0, h->rmt_addr, h->rmt_addrlen); } else { rc = pj_sock_recv(h->fd, h->rd_buf, h->rd_buflen, 0); } if (rc < 0) { pj_status_t sock_err = -1; # if defined(_WIN32) /* On Win32, for UDP, WSAECONNRESET on the receive side * indicates that previous sending has triggered ICMP Port * Unreachable message. * But we wouldn't know at this point which one of previous * key that has triggered the error, since UDP socket can * be shared! * So we'll just ignore it! */ sock_err = pj_sock_getlasterror(); if (sock_err == PJ_ECONNRESET) { pj_mutex_unlock(ioque->mutex); PJ_LOG(4,(THIS_FILE, "Received ICMP port unreachable on key=%p (ignored)!", h)); return 0; } # endif PJ_LOG(4, (THIS_FILE, "socket recv error on key %p, rc=%d, err=%d", h, rc, sock_err)); } h->op &= ~(PJ_IOQUEUE_OP_READ | PJ_IOQUEUE_OP_RECV_FROM); PJ_FD_CLR(h->fd, &ioque->rfdset); /* Unlock mutex before callback. */ pj_mutex_unlock(ioque->mutex); /* Call callback. */ (*h->cb.on_read_complete)(h, rc); return 1; } /* Shouldn't happen. */ /* For strange reason on WinXP select() can return 1 while there is no * fd_set signaled. */ /* pj_assert(0); */ rc = 0; pj_mutex_unlock(ioque->mutex); return rc; }
int $UPROTO$_secure_server_proc(void *param) { int ret; unsigned int len; int port; char *first, *second, *third; char cnt_str[30]; pj_sockaddr_in caddr; char *caddr_str; pj_time_val timeout; pj_fd_set_t read_fds; char buffer[USERVER_BUFSIZE]; $UPROTO$_request_t request; // For lvc parsing lvc_t lvc; int len1; char *val; uint32_t *ts; char sts[32]; char plain[USERVER_BUFSIZE]; char *pph; char otp[32]; pj_str_t pjstr; // End for lvc parsing $UPROTO$_server_t *userver = ($UPROTO$_server_t *)param; ansi_copy_str(cnt_str, userver->connect_str); first = cnt_str; second = strchr(first, ':'); EXIT_IF_TRUE(second == NULL, "Wrong connection string format\n"); *second = '\0'; second++; if(0 == strcmp(first, "udp")) { third = strchr(second, ':'); EXIT_IF_TRUE(third == NULL, "Wrong connection string format\n"); *third = '\0'; third++; port = atoi(third); open_udp_socket(userver, second, port); if (userver->on_open_socket_f != NULL) userver->on_open_socket_f(userver); userver->recv_f = &udp_recvfrom; userver->send_f = &udp_sendto; } else if( 0 == strcmp(first, "tty") ) { open_tty(userver, second); userver->recv_f = &tty_recvfrom; userver->send_f = &tty_sendto; } else { EXIT_IF_TRUE(1, "Unsuported protocol\n"); } // thread loop timeout.sec = 0; timeout.msec = 100; userver->is_end = 0; while( !userver->is_end ) { while (!userver->is_online) { SHOW_LOG(3, "Server is currently offline...\n"); pj_thread_sleep(1000); } PJ_FD_ZERO(&read_fds); PJ_FD_SET(userver->fd, &read_fds); pj_mutex_lock(userver->mutex); ret = pj_sock_select(userver->fd + 1, &read_fds, NULL, NULL, &timeout); pj_mutex_unlock(userver->mutex); EXIT_IF_TRUE(ret < 0, "Error on server socket\n"); if( PJ_FD_ISSET(userver->fd, &read_fds) ) { len = sizeof(caddr); pj_bzero(&caddr, len); pj_mutex_lock(userver->mutex); ret = userver->recv_f(userver->fd, buffer, USERVER_BUFSIZE, (void *)&caddr, &len); pj_mutex_unlock(userver->mutex); caddr_str = pj_inet_ntoa(caddr.sin_addr); if( ret > 0 ) { buffer[ret] = '\0'; lvc_init(&lvc, buffer, ret); lvc_unpack(&lvc, &len, &val); pj_strset(&pjstr, val, len); pph = userver->get_pph_f(&pjstr); if( pph != NULL ) { lvc_unpack(&lvc, &len, &val); ts = (uint32_t *)val; ts2str(*ts, sts); lvc_unpack(&lvc, &len, &val); generate_otp(otp, pph, sts); do_decrypt(val, len, plain, &len1, otp); if( pj_ansi_strncmp(sts, plain, len1) == 0 ) { lvc_unpack(&lvc, &len, &val); do_decrypt(val, len, plain, &len1, otp); plain[len1] = '\0'; $UPROTO$_parse_request(plain, len1, &request); userver->on_request_f(userver, &request, caddr_str); } } //else { //} } } pj_thread_sleep(100); } return 0; }
int $UPROTO$_server_proc(void *param) { int ret; unsigned int len; int port; char *first, *second, *third; char cnt_str[30]; pj_sockaddr_in caddr; char *caddr_str; pj_time_val timeout; pj_fd_set_t read_fds; char buffer[USERVER_BUFSIZE]; $UPROTO$_request_t request; $UPROTO$_server_t *userver = ($UPROTO$_server_t *)param; ansi_copy_str(cnt_str, userver->connect_str); first = cnt_str; second = strchr(first, ':'); EXIT_IF_TRUE(second == NULL, "Wrong connection string format\n"); *second = '\0'; second++; if(0 == strcmp(first, "udp")) { third = strchr(second, ':'); EXIT_IF_TRUE(third == NULL, "Wrong connection string format\n"); *third = '\0'; third++; port = atoi(third); open_udp_socket(userver, second, port); if (userver->on_open_socket_f != NULL) userver->on_open_socket_f(userver); userver->recv_f = &udp_recvfrom; userver->send_f = &udp_sendto; } else if( 0 == strcmp(first, "tty") ) { open_tty(userver, second); userver->recv_f = &tty_recvfrom; userver->send_f = &tty_sendto; } else { EXIT_IF_TRUE(1, "Unsuported protocol\n"); } // thread loop timeout.sec = 0; timeout.msec = 100; userver->is_end = 0; while( !userver->is_end ) { while (!userver->is_online) { SHOW_LOG(3, "Server is currently offline...\n"); //usleep(8*1000*1000); pj_thread_sleep(1000); } PJ_FD_ZERO(&read_fds); PJ_FD_SET(userver->fd, &read_fds); pj_mutex_lock(userver->mutex); ret = pj_sock_select(userver->fd + 1, &read_fds, NULL, NULL, &timeout); pj_mutex_unlock(userver->mutex); EXIT_IF_TRUE(ret < 0, "Error on server socket\n"); if( PJ_FD_ISSET(userver->fd, &read_fds) ) { len = sizeof(caddr); pj_bzero(&caddr, len); pj_mutex_lock(userver->mutex); ret = userver->recv_f(userver->fd, buffer, USERVER_BUFSIZE, (void *)&caddr, &len); pj_mutex_unlock(userver->mutex); caddr_str = pj_inet_ntoa(caddr.sin_addr); if( ret > 0 ) { buffer[ret] = '\0'; SHOW_LOG(5, "Received from client: %s\n", buffer); $UPROTO$_parse_request(buffer, ret, &request); userver->on_request_f(userver, &request, caddr_str); } } //usleep(100*1000); pj_thread_sleep(100); // if userver->fd is ready to write. When write finish, call userver->on_sent(); // else --> time out } return 0; }
PJ_DEF(int) pj_sock_select( int n, pj_fd_set_t *readfds, pj_fd_set_t *writefds, pj_fd_set_t *exceptfds, const pj_time_val *timeout) { CPjTimeoutTimer *pjTimer; unsigned i; PJ_UNUSED_ARG(n); PJ_UNUSED_ARG(writefds); PJ_UNUSED_ARG(exceptfds); if (timeout) { pjTimer = PjSymbianOS::Instance()->SelectTimeoutTimer(); pjTimer->StartTimer(timeout->sec*1000 + timeout->msec); } else { pjTimer = NULL; } /* Scan for readable sockets */ if (readfds) { symbian_fd_set *fds = (symbian_fd_set *)readfds; do { /* Scan sockets for readily available data */ for (i=0; i<fds->count; ++i) { CPjSocket *pjsock = fds->sock[i]; if (pjsock->Reader()) { if (pjsock->Reader()->HasData() && !pjsock->Reader()->IsActive()) { /* Found socket with data ready */ PJ_FD_ZERO(readfds); PJ_FD_SET((pj_sock_t)pjsock, readfds); /* Cancel timer, if any */ if (pjTimer) { pjTimer->Cancel(); } /* Clear writable and exception fd_set */ if (writefds) PJ_FD_ZERO(writefds); if (exceptfds) PJ_FD_ZERO(exceptfds); return 1; } else if (!pjsock->Reader()->IsActive()) pjsock->Reader()->StartRecvFrom(); } else { pjsock->CreateReader(); pjsock->Reader()->StartRecvFrom(); } } PjSymbianOS::Instance()->WaitForActiveObjects(); } while (pjTimer==NULL || !pjTimer->HasTimedOut()); } /* Timeout */ if (readfds) PJ_FD_ZERO(readfds); if (writefds) PJ_FD_ZERO(writefds); if (exceptfds) PJ_FD_ZERO(exceptfds); return 0; }