Пример #1
0
    //
    // receive data.
    //
    pj_ssize_t recv(void *buf, pj_size_t len, int flag = 0)
    {
        pj_ssize_t bytes = len;
	if (pj_sock_recv(sock_, buf, &bytes, flag) != PJ_SUCCESS)
            return -1;
        return bytes;
    }
Пример #2
0
/*
 * pj_ioqueue_recv()
 *
 * Start asynchronous recv() from the socket.
 */
PJ_DEF(pj_status_t) pj_ioqueue_recv(  pj_ioqueue_key_t *key,
                                      pj_ioqueue_op_key_t *op_key,
				      void *buffer,
				      pj_ssize_t *length,
				      unsigned flags )
{
    struct read_operation *read_op;

    PJ_ASSERT_RETURN(key && op_key && buffer && length, PJ_EINVAL);
    PJ_CHECK_STACK();

    /* Check if key is closing (need to do this first before accessing
     * other variables, since they might have been destroyed. See ticket
     * #469).
     */
    if (IS_CLOSING(key))
	return PJ_ECANCELLED;

    read_op = (struct read_operation*)op_key;
    read_op->op = PJ_IOQUEUE_OP_NONE;

    /* Try to see if there's data immediately available. 
     */
    if ((flags & PJ_IOQUEUE_ALWAYS_ASYNC) == 0) {
	pj_status_t status;
	pj_ssize_t size;

	size = *length;
	status = pj_sock_recv(key->fd, buffer, &size, flags);
	if (status == PJ_SUCCESS) {
	    /* Yes! Data is available! */
	    *length = size;
	    return PJ_SUCCESS;
	} else {
	    /* If error is not EWOULDBLOCK (or EAGAIN on Linux), report
	     * the error to caller.
	     */
	    if (status != PJ_STATUS_FROM_OS(PJ_BLOCKING_ERROR_VAL))
		return status;
	}
    }

    flags &= ~(PJ_IOQUEUE_ALWAYS_ASYNC);

    /*
     * No data is immediately available.
     * Must schedule asynchronous operation to the ioqueue.
     */
    read_op->op = PJ_IOQUEUE_OP_RECV;
    read_op->buf = buffer;
    read_op->size = *length;
    read_op->flags = flags;

    pj_mutex_lock(key->mutex);
    pj_list_insert_before(&key->read_list, read_op);
    ioqueue_add_to_set(key->ioqueue, key, READABLE_EVENT);
    pj_mutex_unlock(key->mutex);

    return PJ_EPENDING;
}
Пример #3
0
int main() {
    pj_sock_t sock;
    pj_sockaddr_in to_addr;
    char *s = "Cong hoa xa hoi chu nghia VietNam";

    char buffer[100];
    pj_ssize_t len;

    struct timeval tv_begin, tv_end, tv_diff;

    pj_log_set_level(3);
    CHECK(__FILE__, pj_init());
    pj_bzero(buffer, sizeof(buffer));
    CHECK_R( __FILE__, pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &sock) );
    //udp_socket(12345, &sock);
    setup_addr_with_host_and_port(&to_addr, "127.0.0.1", 33333);

    len = strlen(s);
    gettimeofday(&tv_begin, NULL);
    pj_sock_sendto(sock, s, &len, 0, &to_addr, sizeof(to_addr));
    
    PJ_LOG(3, (__FILE__, "Sent: %s", s));
    len = 100;
    pj_sock_recv(sock, buffer, &len, 0);
    gettimeofday(&tv_end, NULL);
    int diff = timeval_subtract(&tv_diff, &tv_end, &tv_begin);
    PJ_LOG(3, (__FILE__, "Received: %s %0.2f msec", buffer, diff*1.0/1000));
    pj_shutdown();
    return 0;
}
Пример #4
0
/*
 * select_test()
 *
 * Test main entry.
 */
int select_test()
{
    pj_sock_t udp1=PJ_INVALID_SOCKET, udp2=PJ_INVALID_SOCKET;
    pj_sockaddr_in udp_addr;
    int status;
    int setcount[3];
    pj_str_t s;
    const char data[] = "hello";
    const int datalen = 5;
    pj_ssize_t sent, received;
    char buf[10];
    pj_status_t rc;

    PJ_LOG(3, (THIS_FILE, "...Testing simple UDP select()"));
    
    // Create two UDP sockets.
    rc = pj_sock_socket( pj_AF_INET(), pj_SOCK_DGRAM(), 0, &udp1);
    if (rc != PJ_SUCCESS) {
        app_perror("...error: unable to create socket", rc);
	status=-10; goto on_return;
    }
    rc = pj_sock_socket( pj_AF_INET(), pj_SOCK_DGRAM(), 0, &udp2);
    if (udp2 == PJ_INVALID_SOCKET) {
        app_perror("...error: unable to create socket", rc);
	status=-20; goto on_return;
    }

    // Bind one of the UDP socket.
    pj_bzero(&udp_addr, sizeof(udp_addr));
    udp_addr.sin_family = pj_AF_INET();
    udp_addr.sin_port = UDP_PORT;
    udp_addr.sin_addr = pj_inet_addr(pj_cstr(&s, "127.0.0.1"));

    if (pj_sock_bind(udp2, &udp_addr, sizeof(udp_addr))) {
	status=-30; goto on_return;
    }

    // Send data.
    sent = datalen;
    rc = pj_sock_sendto(udp1, data, &sent, 0, &udp_addr, sizeof(udp_addr));
    if (rc != PJ_SUCCESS || sent != datalen) {
        app_perror("...error: sendto() error", rc);
	status=-40; goto on_return;
    }

    // Sleep a bit. See http://trac.pjsip.org/repos/ticket/890
    pj_thread_sleep(10);

    // Check that socket is marked as reable.
    // Note that select() may also report that sockets are writable.
    status = do_select(udp1, udp2, setcount);
    if (status < 0) {
	char errbuf[128];
        pj_strerror(pj_get_netos_error(), errbuf, sizeof(errbuf));
	PJ_LOG(1,(THIS_FILE, "...error: %s", errbuf));
	status=-50; goto on_return;
    }
    if (status == 0) {
	status=-60; goto on_return;
    }

    if (setcount[READ_FDS] != 1) {
	status=-70; goto on_return;
    }
    if (setcount[WRITE_FDS] != 0) {
	if (setcount[WRITE_FDS] == 2) {
	    PJ_LOG(3,(THIS_FILE, "...info: system reports writable sockets"));
	} else {
	    status=-80; goto on_return;
	}
    } else {
	PJ_LOG(3,(THIS_FILE, 
		  "...info: system doesn't report writable sockets"));
    }
    if (setcount[EXCEPT_FDS] != 0) {
	status=-90; goto on_return;
    }

    // Read the socket to clear readable sockets.
    received = sizeof(buf);
    rc = pj_sock_recv(udp2, buf, &received, 0);
    if (rc != PJ_SUCCESS || received != 5) {
	status=-100; goto on_return;
    }
    
    status = 0;

    // Test timeout on the read part.
    // This won't necessarily return zero, as select() may report that
    // sockets are writable.
    setcount[0] = setcount[1] = setcount[2] = 0;
    status = do_select(udp1, udp2, setcount);
    if (status != 0 && status != setcount[WRITE_FDS]) {
	PJ_LOG(3,(THIS_FILE, "...error: expecting timeout but got %d sks set",
			     status));
	PJ_LOG(3,(THIS_FILE, "          rdset: %d, wrset: %d, exset: %d",
			     setcount[0], setcount[1], setcount[2]));
	status = -110; goto on_return;
    }
    if (setcount[READ_FDS] != 0) {
	PJ_LOG(3,(THIS_FILE, "...error: readable socket not expected"));
	status = -120; goto on_return;
    }

    status = 0;

on_return:
    if (udp1 != PJ_INVALID_SOCKET)
	pj_sock_close(udp1);
    if (udp2 != PJ_INVALID_SOCKET)
	pj_sock_close(udp2);
    return status;
}
Пример #5
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;
}
Пример #6
0
static int send_recv_test(int sock_type,
                          pj_sock_t ss, pj_sock_t cs,
			  pj_sockaddr_in *dstaddr, pj_sockaddr_in *srcaddr, 
			  int addrlen)
{
    enum { DATA_LEN = 16 };
    char senddata[DATA_LEN+4], recvdata[DATA_LEN+4];
    pj_ssize_t sent, received, total_received;
    pj_status_t rc;

    TRACE_(("test", "....create_random_string()"));
    pj_create_random_string(senddata, DATA_LEN);
    senddata[DATA_LEN-1] = '\0';

    /*
     * Test send/recv small data.
     */
    TRACE_(("test", "....sendto()"));
    if (dstaddr) {
        sent = DATA_LEN;
	rc = pj_sock_sendto(cs, senddata, &sent, 0, dstaddr, addrlen);
	if (rc != PJ_SUCCESS || sent != DATA_LEN) {
	    app_perror("...sendto error", rc);
	    rc = -140; goto on_error;
	}
    } else {
        sent = DATA_LEN;
	rc = pj_sock_send(cs, senddata, &sent, 0);
	if (rc != PJ_SUCCESS || sent != DATA_LEN) {
	    app_perror("...send error", rc);
	    rc = -145; goto on_error;
	}
    }

    TRACE_(("test", "....recv()"));
    if (srcaddr) {
	pj_sockaddr_in addr;
	int srclen = sizeof(addr);
	
	pj_bzero(&addr, sizeof(addr));

        received = DATA_LEN;
	rc = pj_sock_recvfrom(ss, recvdata, &received, 0, &addr, &srclen);
	if (rc != PJ_SUCCESS || received != DATA_LEN) {
	    app_perror("...recvfrom error", rc);
	    rc = -150; goto on_error;
	}
	if (srclen != addrlen)
	    return -151;
	if (pj_sockaddr_cmp(&addr, srcaddr) != 0) {
	    char srcaddr_str[32], addr_str[32];
	    strcpy(srcaddr_str, pj_inet_ntoa(srcaddr->sin_addr));
	    strcpy(addr_str, pj_inet_ntoa(addr.sin_addr));
	    PJ_LOG(3,("test", "...error: src address mismatch (original=%s, "
			      "recvfrom addr=%s)", 
			      srcaddr_str, addr_str));
	    return -152;
	}
	
    } else {
        /* Repeat recv() until all data is received.
         * This applies only for non-UDP of course, since for UDP
         * we would expect all data to be received in one packet.
         */
        total_received = 0;
        do {
            received = DATA_LEN-total_received;
	    rc = pj_sock_recv(ss, recvdata+total_received, &received, 0);
	    if (rc != PJ_SUCCESS) {
	        app_perror("...recv error", rc);
	        rc = -155; goto on_error;
	    }
            if (received <= 0) {
                PJ_LOG(3,("", "...error: socket has closed! (received=%d)",
                          received));
                rc = -156; goto on_error;
            }
	    if (received != DATA_LEN-total_received) {
                if (sock_type != pj_SOCK_STREAM()) {
	            PJ_LOG(3,("", "...error: expecting %u bytes, got %u bytes",
                              DATA_LEN-total_received, received));
	            rc = -157; goto on_error;
                }
	    }
            total_received += received;
        } while (total_received < DATA_LEN);
    }

    TRACE_(("test", "....memcmp()"));
    if (pj_memcmp(senddata, recvdata, DATA_LEN) != 0) {
	PJ_LOG(3,("","...error: received data mismatch "
		     "(got:'%s' expecting:'%s'",
		     recvdata, senddata));
	rc = -160; goto on_error;
    }

    /*
     * Test send/recv big data.
     */
    TRACE_(("test", "....sendto()"));
    if (dstaddr) {
        sent = BIG_DATA_LEN;
	rc = pj_sock_sendto(cs, bigdata, &sent, 0, dstaddr, addrlen);
	if (rc != PJ_SUCCESS || sent != BIG_DATA_LEN) {
	    app_perror("...sendto error", rc);
	    rc = -161; goto on_error;
	}
    } else {
        sent = BIG_DATA_LEN;
	rc = pj_sock_send(cs, bigdata, &sent, 0);
	if (rc != PJ_SUCCESS || sent != BIG_DATA_LEN) {
	    app_perror("...send error", rc);
	    rc = -165; goto on_error;
	}
    }

    TRACE_(("test", "....recv()"));

    /* Repeat recv() until all data is received.
     * This applies only for non-UDP of course, since for UDP
     * we would expect all data to be received in one packet.
     */
    total_received = 0;
    do {
        received = BIG_DATA_LEN-total_received;
	rc = pj_sock_recv(ss, bigbuffer+total_received, &received, 0);
	if (rc != PJ_SUCCESS) {
	    app_perror("...recv error", rc);
	    rc = -170; goto on_error;
	}
        if (received <= 0) {
            PJ_LOG(3,("", "...error: socket has closed! (received=%d)",
                      received));
            rc = -173; goto on_error;
        }
	if (received != BIG_DATA_LEN-total_received) {
            if (sock_type != pj_SOCK_STREAM()) {
	        PJ_LOG(3,("", "...error: expecting %u bytes, got %u bytes",
                          BIG_DATA_LEN-total_received, received));
	        rc = -176; goto on_error;
            }
	}
        total_received += received;
    } while (total_received < BIG_DATA_LEN);

    TRACE_(("test", "....memcmp()"));
    if (pj_memcmp(bigdata, bigbuffer, BIG_DATA_LEN) != 0) {
        PJ_LOG(3,("", "...error: received data has been altered!"));
	rc = -180; goto on_error;
    }
    
    rc = 0;

on_error:
    return rc;
}
Пример #7
0
void ioqueue_dispatch_read_event( pj_ioqueue_t *ioqueue, pj_ioqueue_key_t *h )
{
    pj_status_t rc;

    /* Lock the key. */
    pj_mutex_lock(h->mutex);

    if (IS_CLOSING(h)) {
	pj_mutex_unlock(h->mutex);
	return;
    }

#   if PJ_HAS_TCP
    if (!pj_list_empty(&h->accept_list)) {

        struct accept_operation *accept_op;
	pj_bool_t has_lock;
	
        /* Get one accept operation from the list. */
	accept_op = h->accept_list.next;
        pj_list_erase(accept_op);
        accept_op->op = PJ_IOQUEUE_OP_NONE;

	/* Clear bit in fdset if there is no more pending accept */
        if (pj_list_empty(&h->accept_list))
            ioqueue_remove_from_set(ioqueue, h, READABLE_EVENT);

	rc=pj_sock_accept(h->fd, accept_op->accept_fd, 
                          accept_op->rmt_addr, accept_op->addrlen);
	if (rc==PJ_SUCCESS && accept_op->local_addr) {
	    rc = pj_sock_getsockname(*accept_op->accept_fd, 
                                     accept_op->local_addr,
				     accept_op->addrlen);
	}

	/* Unlock; from this point we don't need to hold key's mutex
	 * (unless concurrency is disabled, which in this case we should
	 * hold the mutex while calling the callback) */
	if (h->allow_concurrent) {
	    /* concurrency may be changed while we're in the callback, so
	     * save it to a flag.
	     */
	    has_lock = PJ_FALSE;
	    pj_mutex_unlock(h->mutex);
	} else {
	    has_lock = PJ_TRUE;
	}

	/* Call callback. */
        if (h->cb.on_accept_complete && !IS_CLOSING(h)) {
	    (*h->cb.on_accept_complete)(h, 
                                        (pj_ioqueue_op_key_t*)accept_op,
                                        *accept_op->accept_fd, rc);
	}

	if (has_lock) {
	    pj_mutex_unlock(h->mutex);
	}
    }
    else
#   endif
    if (key_has_pending_read(h)) {
        struct read_operation *read_op;
        pj_ssize_t bytes_read;
	pj_bool_t has_lock;

        /* Get one pending read operation from the list. */
        read_op = h->read_list.next;
        pj_list_erase(read_op);

        /* Clear fdset if there is no pending read. */
        if (pj_list_empty(&h->read_list))
            ioqueue_remove_from_set(ioqueue, h, READABLE_EVENT);

        bytes_read = read_op->size;

	if ((read_op->op == PJ_IOQUEUE_OP_RECV_FROM)) {
	    read_op->op = PJ_IOQUEUE_OP_NONE;
	    rc = pj_sock_recvfrom(h->fd, read_op->buf, &bytes_read, 
				  read_op->flags,
				  read_op->rmt_addr, 
                                  read_op->rmt_addrlen);
	} else if ((read_op->op == PJ_IOQUEUE_OP_RECV)) {
	    read_op->op = PJ_IOQUEUE_OP_NONE;
	    rc = pj_sock_recv(h->fd, read_op->buf, &bytes_read, 
			      read_op->flags);
        } else {
            pj_assert(read_op->op == PJ_IOQUEUE_OP_READ);
	    read_op->op = PJ_IOQUEUE_OP_NONE;
            /*
             * User has specified pj_ioqueue_read().
             * On Win32, we should do ReadFile(). But because we got
             * here because of select() anyway, user must have put a
             * socket descriptor on h->fd, which in this case we can
             * just call pj_sock_recv() instead of ReadFile().
             * On Unix, user may put a file in h->fd, so we'll have
             * to call read() here.
             * This may not compile on systems which doesn't have 
             * read(). That's why we only specify PJ_LINUX here so
             * that error is easier to catch.
             */
#	    if defined(PJ_WIN32) && PJ_WIN32 != 0 || \
	       defined(PJ_WIN32_WINCE) && PJ_WIN32_WINCE != 0
                rc = pj_sock_recv(h->fd, read_op->buf, &bytes_read, 
				  read_op->flags);
                //rc = ReadFile((HANDLE)h->fd, read_op->buf, read_op->size,
                //              &bytes_read, NULL);
#           elif (defined(PJ_HAS_UNISTD_H) && PJ_HAS_UNISTD_H != 0)
                bytes_read = read(h->fd, read_op->buf, bytes_read);
                rc = (bytes_read >= 0) ? PJ_SUCCESS : pj_get_os_error();
#	    elif defined(PJ_LINUX_KERNEL) && PJ_LINUX_KERNEL != 0
                bytes_read = sys_read(h->fd, read_op->buf, bytes_read);
                rc = (bytes_read >= 0) ? PJ_SUCCESS : -bytes_read;
#           else
#               error "Implement read() for this platform!"
#           endif
        }
	
	if (rc != PJ_SUCCESS) {
#	    if defined(PJ_WIN32) && PJ_WIN32 != 0
	    /* 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!
	     */

	    if (rc == PJ_STATUS_FROM_OS(WSAECONNRESET)) {
		//PJ_LOG(4,(THIS_FILE, 
                //          "Ignored ICMP port unreach. on key=%p", h));
	    }
#	    endif

            /* In any case we would report this to caller. */
            bytes_read = -rc;
	}

	/* Unlock; from this point we don't need to hold key's mutex
	 * (unless concurrency is disabled, which in this case we should
	 * hold the mutex while calling the callback) */
	if (h->allow_concurrent) {
	    /* concurrency may be changed while we're in the callback, so
	     * save it to a flag.
	     */
	    has_lock = PJ_FALSE;
	    pj_mutex_unlock(h->mutex);
	} else {
	    has_lock = PJ_TRUE;
	}

	/* Call callback. */
        if (h->cb.on_read_complete && !IS_CLOSING(h)) {
	    (*h->cb.on_read_complete)(h, 
                                      (pj_ioqueue_op_key_t*)read_op,
                                      bytes_read);
        }

	if (has_lock) {
	    pj_mutex_unlock(h->mutex);
	}

    } else {
        /*
         * This is normal; execution may fall here when multiple threads
         * are signalled for the same event, but only one thread eventually
         * able to process the event.
         */
        pj_mutex_unlock(h->mutex);
    }
}
Пример #8
0
/*
 * sock_producer_consumer()
 *
 * Simple producer-consumer benchmarking. Send loop number of
 * buf_size size packets as fast as possible.
 */
static int sock_producer_consumer(int sock_type,
                                  unsigned buf_size,
                                  unsigned loop, 
                                  unsigned *p_bandwidth)
{
    pj_sock_t consumer, producer;
    pj_pool_t *pool;
    char *outgoing_buffer, *incoming_buffer;
    pj_timestamp start, stop;
    unsigned i;
    pj_highprec_t elapsed, bandwidth;
    pj_size_t total_received;
    pj_status_t rc;

    /* Create pool. */
    pool = pj_pool_create(mem, NULL, 4096, 4096, NULL);
    if (!pool)
        return -10;

    /* Create producer-consumer pair. */
    rc = app_socketpair(PJ_AF_INET, sock_type, 0, &consumer, &producer);
    if (rc != PJ_SUCCESS) {
        app_perror("...error: create socket pair", rc);
        return -20;
    }

    /* Create buffers. */
    outgoing_buffer = pj_pool_alloc(pool, buf_size);
    incoming_buffer = pj_pool_alloc(pool, buf_size);

    /* Start loop. */
    pj_get_timestamp(&start);
    total_received = 0;
    for (i=0; i<loop; ++i) {
        pj_ssize_t sent, part_received, received;
	pj_time_val delay;

        sent = buf_size;
        rc = pj_sock_send(producer, outgoing_buffer, &sent, 0);
        if (rc != PJ_SUCCESS || sent != (pj_ssize_t)buf_size) {
            app_perror("...error: send()", rc);
            return -61;
        }

        /* Repeat recv() until all data is part_received.
         * This applies only for non-UDP of course, since for UDP
         * we would expect all data to be part_received in one packet.
         */
        received = 0;
        do {
            part_received = buf_size-received;
	    rc = pj_sock_recv(consumer, incoming_buffer+received, 
			      &part_received, 0);
	    if (rc != PJ_SUCCESS) {
	        app_perror("...recv error", rc);
	        return -70;
	    }
            if (part_received <= 0) {
                PJ_LOG(3,("", "...error: socket has closed (part_received=%d)!",
                          part_received));
                return -73;
            }
	    if ((pj_size_t)part_received != buf_size-received) {
                if (sock_type != PJ_SOCK_STREAM) {
	            PJ_LOG(3,("", "...error: expecting %u bytes, got %u bytes",
                              buf_size-received, part_received));
	            return -76;
                }
	    }
            received += part_received;
        } while ((pj_size_t)received < buf_size);

	total_received += received;

	/* Stop test if it's been runnign for more than 10 secs. */
	pj_get_timestamp(&stop);
	delay = pj_elapsed_time(&start, &stop);
	if (delay.sec > 10)
	    break;
    }

    /* Stop timer. */
    pj_get_timestamp(&stop);

    elapsed = pj_elapsed_usec(&start, &stop);

    /* bandwidth = total_received * 1000 / elapsed */
    bandwidth = total_received;
    pj_highprec_mul(bandwidth, 1000);
    pj_highprec_div(bandwidth, elapsed);
    
    *p_bandwidth = (pj_uint32_t)bandwidth;

    /* Close sockets. */
    pj_sock_close(consumer);
    pj_sock_close(producer);

    /* Done */
    pj_pool_release(pool);

    return 0;
}
Пример #9
0
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;
}