Ejemplo n.º 1
0
	virtual bool Accept(const ByteString &key, const ByteString &value)
	{
		TEST_LOG("\"%.*s\": \"%.*s\"", key.length, key.buffer, value.length, value.buffer);
		
		if (strncmp(what.buffer, key.buffer, min(what.length, key.length)) == 0)
		{
			if (strncmp(where.buffer, value.buffer, min(where.length, value.length)) == 0)
			{
				TEST_LOG(" matched: \"%.*s\": \"%.*s\"", key.length, key.buffer, value.length, value.buffer);
			}
		}
		
		return true;
	}
Ejemplo n.º 2
0
static void check_widget_rect( LCUI_SysEvent ev, void *arg )
{
	int ret = 0;
	LCUI_RectF rectf;
	LCUI_Rect rect, old_rect;
	LCUI_Rect *paint_rect = &ev->paint.rect;

	rectf.x = self.x;
	rectf.y = self.y;
	rectf.width = WIDGET_WIDTH;
	rectf.height = WIDGET_WIDTH;
	LCUIMetrics_ComputeRectActual( &old_rect, &rectf );
	LCUIMetrics_ComputeRectActual( &rect, &self.widget->box.canvas );
	LCUIRect_MergeRect( &rect, &rect, &old_rect );
	CHECK2( check_rect_correct( &rect, paint_rect ) );
	if( ret != 0 ) {
		TEST_LOG( "[%d] correct: (%d, %d, %d, %d),"
			  " actual: (%d, %d, %d, %d)\n", self.step,
			  rect.x, rect.y, rect.width, rect.height,
			  paint_rect->x, paint_rect->y,
			  paint_rect->width, paint_rect->height );
	} else {
		self.pass += 1;
	}
	self.count += 1;
	self.x = self.widget->x;
	self.y = self.widget->y;
	LCUI_PostSimpleTask( test_move_widget, NULL, NULL );
}
Ejemplo n.º 3
0
int BasicLinkedListTest()
{
	LinkedList2<Elem, &Elem::nextA, &Elem::prevA>	listA;
	LinkedList2<Elem, &Elem::nextB, &Elem::prevB>	listB;
	LinkedList<Elem, &Elem::node> listC;
	LList<Elem, &Elem::llnode> llist;
	
	for (int i = 0; i < 3; i++)
	{
		Elem* elem;
		
		elem = new Elem;
		elem->buffer.Printf("%i", i);
		//listC.Append(*elem);
		llist.Add(*elem);
	}
	
	Elem* next = NULL;
	for (Elem* e = listC.Head(); e; e = next)
	{
		TEST_LOG("%.*s", e->buffer.length, e->buffer.data);
		next = listC.Remove(e);
		delete e;
	}
	
	return TEST_SUCCESS;
}
Ejemplo n.º 4
0
static void TestWorker_Thread( void *arg )
{
	TestWorker worker = arg;

	worker->active = TRUE;
	worker->data_count = 0;
	LCUIMutex_Lock( &worker->mutex );
	while( worker->active ) {
		TEST_LOG( "waiting...\n" );
		LCUICond_Wait( &worker->cond, &worker->mutex );
		TEST_LOG( "get data: %s\n", worker->data );
		worker->data_count += 1;
	}
	LCUIMutex_Unlock( &worker->mutex );
	TEST_LOG( "count: %lu\n", worker->data_count );
}
Ejemplo n.º 5
0
int test_widget_rect( void )
{
	int i, ret = 0;
	float values[3] = { 1.0f, 1.5f, 2.0f };

	for( i = 0; i < 3; ++i ) {
		memset( &self, 0, sizeof( self ) );

		TEST_LOG( "test widget rectagle in "
			  "%g%% scaling mode\n", values[i] * 100 );

		LCUI_Init();
#ifdef _WIN32
		Logger_SetHandler( LoggerHandler );
		Logger_SetHandlerW( LoggerHandlerW );
#endif
		self.widget = create_widget();
		LCUIMetrics_SetScale( values[i] );
		LCUIDisplay_SetSize( SCREEN_WIDTH, SCREEN_HEIGHT );
		/* 等一段时间后再开始测试,避免初始化 LCUI 时产生的脏矩形影响测试结果 */
		LCUITimer_Set( 100, start_test, NULL, FALSE );
		LCUIWidget_Update();
		if( LCUI_Main() != 0 ) {
			ret -= 1;
		}
	}
	return ret;
}
Ejemplo n.º 6
0
static void s_SingleBouncePrint
(CONN  conn,
 FILE* data_file)
{
    static const char write_str[] = "This is a s_*BouncePrint test string.\n";
    size_t     n_written, n_read;
    char       message[128];
    char       buf[8192];
    EIO_Status status;

    TEST_LOG(eIO_Success, "[s_SingleBouncePrint]  Starting...");

    /* WRITE */
    status = CONN_Write(conn, write_str, strlen(write_str),
                        &n_written, eIO_WritePersist);
    if (status != eIO_Success  ||  n_written != strlen(write_str)) {
        TEST_LOG(status,
                 "[s_SingleBouncePrint]  CONN_Write(persistent) failed");
    }
    assert(n_written == strlen(write_str));
    assert(status == eIO_Success);

    /* READ the "bounced" data from the connection */
    status = CONN_Read(conn, buf, sizeof(buf) - 1, &n_read, eIO_ReadPersist);
    sprintf(message, "[s_SingleBouncePrint]  CONN_Read(persistent)"
            " %lu byte%s read", (unsigned long) n_read, &"s"[n_read == 1]);
    TEST_LOG(status, message);

    /* Printout to data file, if any */
    if (data_file  &&  n_read) {
        fprintf(data_file, "\ns_SingleBouncePrint(BEGIN PRINT)\n");
        assert(fwrite(buf, n_read, 1, data_file) == 1);
        fprintf(data_file, "\ns_SingleBouncePrint(END PRINT)\n");
        fflush(data_file);
    }

    /* Check-up */
    assert(n_read >= n_written);
    buf[n_read] = '\0';
    assert(strstr(buf, write_str));

    TEST_LOG(eIO_Success, "[s_SingleBouncePrint]  ...finished");
}
static void TimeOfDayMessage(const char *msg, PRThread* me)
{
    char buffer[100];
    PRExplodedTime tod;
    PR_ExplodeTime(PR_Now(), PR_LocalTimeParameters, &tod);
    (void)PR_FormatTime(buffer, sizeof(buffer), "%H:%M:%S", &tod);

    TEST_LOG(
        cltsrv_log_file, TEST_LOG_ALWAYS,
        ("%s(0x%p): %s\n", msg, me, buffer));
}  /* TimeOfDayMessage */
Ejemplo n.º 8
0
int test_image_reader( void )
{
	LCUI_Graph img;
	int ret = 0, i, width, height;
	char file[256], *formats[] = { "png", "bmp", "jpg" };

	for( i = 0; i < 3; ++i ) {
		width = height = 0;
		Graph_Init( &img );
		snprintf( file, 255, "test_image_reader.%s", formats[i] );
		TEST_LOG( "image file: %s\n", file );
		CHECK( LCUI_ReadImageFile( file, &img ) == 0 );
		CHECK( img.width == 91 && img.height == 69 );
		CHECK( LCUI_GetImageSize( file, &width, &height ) == 0 );
		TEST_LOG( "image size: (%d, %d)\n", width, height );
		CHECK( width == 91 && height == 69 );
		Graph_Free( &img );
	}
	return ret;
}
Ejemplo n.º 9
0
static void s_MultiBouncePrint
(CONN  conn,
 FILE* data_file)
{
    int i;

    TEST_LOG(eIO_Success, "[s_MultiBouncePrint]  Starting...");
    if ( data_file ) {
        fprintf(data_file, "\ns_MultiBouncePrint(BEGIN)\n");
        fflush(data_file);
    }

    for (i = 0;  i < 5;  i++) {
        s_SingleBouncePrint(conn, data_file);
    }

    TEST_LOG(eIO_Success, "[s_MultiBouncePrint]  ...finished");
    if ( data_file ) {
        fprintf(data_file, "\ns_MultiBouncePrint(END)\n");
        fflush(data_file);
    }
}
Ejemplo n.º 10
0
/*static*/ void Pointer::axis(
	void *data, wl_pointer *wl_pointer, uint32_t time,
	uint32_t axis, wl_fixed_t value)
{
	Pointer* pointer = static_cast<Pointer*>(data);
	ASSERT(wl_pointer == *pointer);

	TEST_LOG(
		boost::format("%016p::Pointer::axis()  : axis=%d; value=%f")
			% pointer % axis
			% wl_fixed_to_double(value)
	);

	pointer->axis_ = axis;
	pointer->axisValue_ = wl_fixed_to_double(value);
}
Ejemplo n.º 11
0
/*static*/ void Pointer::leave(
	void *data, wl_pointer *wl_pointer, uint32_t serial,
	wl_surface *wl_surface)
{
	Pointer* pointer = static_cast<Pointer*>(data);
	ASSERT(wl_pointer == *pointer);

	TEST_LOG(
		boost::format("%016p::Pointer::leave() : %016p")
			% pointer % wl_surface
	);
	
	pointer->focus_ = NULL;
	pointer->x_ = -1;
	pointer->y_ = -1;
}
Ejemplo n.º 12
0
/*static*/ void Pointer::motion(
	void *data, wl_pointer *wl_pointer, uint32_t time,
	wl_fixed_t x, wl_fixed_t y)
{
	Pointer* pointer = static_cast<Pointer*>(data);
	ASSERT(wl_pointer == *pointer);

	TEST_LOG(
		boost::format("%016p::Pointer::motion(): %d,%d")
			% pointer % wl_fixed_to_int(x)
			% wl_fixed_to_int(y)
	);

	pointer->x_ = wl_fixed_to_int(x);
	pointer->y_ = wl_fixed_to_int(y);
}
Ejemplo n.º 13
0
/*static*/ void Pointer::enter(
	void *data, wl_pointer *wl_pointer, uint32_t serial,
	wl_surface *wl_surface, wl_fixed_t x, wl_fixed_t y)
{
	Pointer* pointer = static_cast<Pointer*>(data);
	ASSERT(wl_pointer == *pointer);

	TEST_LOG(
		boost::format("%016p::Pointer::enter() : %016p @ %d,%d")
			% pointer % wl_surface
			% wl_fixed_to_int(x) % wl_fixed_to_int(y)
	);
	
	pointer->focus_ = wl_surface;
	pointer->focusSerial_ = serial;
	pointer->x_ = wl_fixed_to_int(x);
	pointer->y_ = wl_fixed_to_int(y);
}
Ejemplo n.º 14
0
void update_throughput(double alpha, double buck_size, proxy_session_list_t* node, char *ip, struct timespec ts){
	double throughput, duration;
	LOG("Update throughput\n");
	chunk_tracker_list_t* tracker_list = search_seg(node);
	chunk_tracker_t *tracker;
	chunk_tracker_t *tmp_tracker = NULL;
	for(tracker = tracker_list->chunks; tracker->next !=NULL; tracker = tracker->next){
		tmp_tracker = tracker;
	}
	tracker_list->throughput = est_tp(alpha, tracker_list->throughput, ts, buck_size, &throughput, &duration);
	LOG("New throughput is %lf\n", tracker_list->throughput);
	printf("New throughput is %lf\n", tracker_list->throughput);
	if(tmp_tracker != NULL)
		tmp_tracker->next = NULL;
		
	TEST_LOG("%u %lf %lf %lf %d %s %s\n", 
		(unsigned)time(NULL), duration, throughput, tracker_list->throughput, tracker_list->bitrate, ip, tracker->file);
	LOG("free tracker\n");
	return;
}
static PRStatus CreateWorker(CSServer_t *server, CSPool_t *pool)
{
    CSWorker_t *worker = PR_NEWZAP(CSWorker_t);
    worker->server = server;
    PR_INIT_CLIST(&worker->element);
    worker->thread = PR_CreateThread(
        PR_USER_THREAD, Worker, worker,
        DEFAULT_SERVER_PRIORITY, thread_scope,
        PR_UNJOINABLE_THREAD, 0);
    if (NULL == worker->thread)
    {
        PR_DELETE(worker);
        return PR_FAILURE;
    }

    TEST_LOG(cltsrv_log_file, TEST_LOG_STATUS, 
        ("\tCreateWorker(0x%p): create new worker (0x%p)\n",
        PR_GetCurrentThread(), worker->thread));

    return PR_SUCCESS;
}  /* CreateWorker */
Ejemplo n.º 16
0
int BasicQueueTest()
{
	Buffer *buffer;
	Queue<Buffer, &Buffer::next> q;

	for (int i = 0; i < 3; i++)
	{
		buffer = new Buffer();
		buffer->Printf("%i", i);
		q.Append(buffer);
	}
	
	for (int  i = 0; i < 3; i++)
	{
		buffer = q.Get();
		TEST_LOG("%.*s", buffer->length, buffer->buffer);
		delete buffer;
	}

	return TEST_SUCCESS;
}
Ejemplo n.º 17
0
/*static*/ void Pointer::button(
	void *data, wl_pointer *wl_pointer, uint32_t serial,
	uint32_t time, uint32_t button, uint32_t state)
{
	Pointer* pointer = static_cast<Pointer*>(data);
	ASSERT(wl_pointer == *pointer);

	TEST_LOG(
		boost::format("%016p::Pointer::button(): button=%d; state=%d")
			% pointer % button % state
	);

	pointer->button_ = button;
	pointer->buttonState_ = state;

	ButtonEvent event;
	event.serial	= serial;
	event.time	= time;
	event.button	= button;
	event.state	= state;
	pointer->btnNotify_(*pointer, event);
}
Ejemplo n.º 18
0
int test_widget_inline_block_layout( void )
{
	int ret = 0;
	LCUI_Widget root, pack;

	LCUI_Init();
	TEST_LOG( "test widget inline block layout\n" );
	LCUIDisplay_SetSize( SCREEN_WIDTH, SCREEN_HEIGHT );
	root = LCUIWidget_GetRoot();
	CHECK( pack = LCUIBuilder_LoadFile( "test_widget_inline_block_layout.xml" ) );
	if( !pack ) {
		LCUI_Destroy();
		return ret;
	}
	Widget_UpdateStyle( root, TRUE );
	Widget_Append( root, pack );
	Widget_Unwrap( pack );
	LCUIWidget_Update();
	ret += check_layout();
	LCUI_Destroy();
	return ret;
}
Ejemplo n.º 19
0
int test_xml_parser( void )
{
	int ret = 0;
	LCUI_Widget root, pack;

	LCUI_Init();
	TEST_LOG( "test widget layout\n" );
	LCUIDisplay_SetSize( 960, 680 );
	root = LCUIWidget_GetRoot();
	CHECK( pack = LCUIBuilder_LoadFile( "test_xml_parser.xml" ) );
	if( !pack ) {
		LCUI_Destroy();
		return ret;
	}
	Widget_UpdateStyle( root, TRUE );
	Widget_Append( root, pack );
	Widget_Unwrap( pack );
	LCUIWidget_Update();
	ret += check_widget_attribute();
	LCUI_Destroy();
	return ret;
}
Ejemplo n.º 20
0
	virtual bool Accept(const ByteString &key, const ByteString &value)
	{
		TEST_LOG("\"%.*s\": \"%.*s\"", key.length, key.buffer, value.length, value.buffer);
		return true;
	}
int main(int argc, char** argv)
{
    PRUintn index;
    PRBool boolean;
    CSClient_t *client;
    PRStatus rv, joinStatus;
    CSServer_t *server = NULL;

    PRUintn backlog = DEFAULT_BACKLOG;
    PRUintn clients = DEFAULT_CLIENTS;
    const char *serverName = DEFAULT_SERVER;
    PRBool serverIsLocal = PR_TRUE;
    PRUintn accepting = ALLOWED_IN_ACCEPT;
    PRUintn workersMin = DEFAULT_WORKERS_MIN;
    PRUintn workersMax = DEFAULT_WORKERS_MAX;
    PRIntn execution = DEFAULT_EXECUTION_TIME;
    PRIntn low = DEFAULT_LOW, high = DEFAULT_HIGH;

    /*
     * -G           use global threads
     * -a <n>       threads allowed in accept
     * -b <n>       backlock for listen
     * -c <threads> number of clients to create
     * -f <low>     low water mark for caching FDs
     * -F <high>    high water mark for caching FDs
     * -w <threads> minimal number of server threads
     * -W <threads> maximum number of server threads
     * -e <seconds> duration of the test in seconds
     * -s <string>  dsn name of server (implies no server here)
     * -v           verbosity
     */

    PLOptStatus os;
    PLOptState *opt = PL_CreateOptState(argc, argv, "GX6b:a:c:f:F:w:W:e:s:vdhp");

    debug_out = PR_GetSpecialFD(PR_StandardError);

    while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
    {
        if (PL_OPT_BAD == os) continue;
        switch (opt->option)
        {
        case 'G':  /* use global threads */
            thread_scope = PR_GLOBAL_THREAD;
            break;
        case 'X':  /* use XTP as transport */
            protocol = 36;
            break;
        case '6':  /* Use IPv6 */
            domain = PR_AF_INET6;
            break;
        case 'a':  /* the value for accepting */
            accepting = atoi(opt->value);
            break;
        case 'b':  /* the value for backlock */
            backlog = atoi(opt->value);
            break;
        case 'c':  /* number of client threads */
            clients = atoi(opt->value);
            break;
        case 'f':  /* low water fd cache */
            low = atoi(opt->value);
            break;
        case 'F':  /* low water fd cache */
            high = atoi(opt->value);
            break;
        case 'w':  /* minimum server worker threads */
            workersMin = atoi(opt->value);
            break;
        case 'W':  /* maximum server worker threads */
            workersMax = atoi(opt->value);
            break;
        case 'e':  /* program execution time in seconds */
            execution = atoi(opt->value);
            break;
        case 's':  /* server's address */
            serverName = opt->value;
            break;
        case 'v':  /* verbosity */
            verbosity = IncrementVerbosity();
            break;
        case 'd':  /* debug mode */
            debug_mode = PR_TRUE;
            break;
        case 'p':  /* pthread mode */
            pthread_stats = PR_TRUE;
            break;
        case 'h':
        default:
            Help();
            return 2;
        }
    }
    PL_DestroyOptState(opt);

    if (0 != PL_strcmp(serverName, DEFAULT_SERVER)) serverIsLocal = PR_FALSE;
    if (0 == execution) execution = DEFAULT_EXECUTION_TIME;
    if (0 == workersMax) workersMax = DEFAULT_WORKERS_MAX;
    if (0 == workersMin) workersMin = DEFAULT_WORKERS_MIN;
    if (0 == accepting) accepting = ALLOWED_IN_ACCEPT;
    if (0 == backlog) backlog = DEFAULT_BACKLOG;

    if (workersMin > accepting) accepting = workersMin;

    PR_STDIO_INIT();
    TimeOfDayMessage("Client/Server started at", PR_GetCurrentThread());

    cltsrv_log_file = PR_NewLogModule("cltsrv_log");
    MY_ASSERT(NULL != cltsrv_log_file);
    boolean = PR_SetLogFile("cltsrv.log");
    MY_ASSERT(boolean);

    rv = PR_SetFDCacheSize(low, high);
    PR_ASSERT(PR_SUCCESS == rv);

    if (serverIsLocal)
    {
        /* Establish the server */
        TEST_LOG(
            cltsrv_log_file, TEST_LOG_INFO,
            ("main(0x%p): starting server\n", PR_GetCurrentThread()));

        server = PR_NEWZAP(CSServer_t);
        PR_INIT_CLIST(&server->list);
        server->state = cs_init;
        server->ml = PR_NewLock();
        server->backlog = backlog;
        server->port = DEFAULT_PORT;
        server->workers.minimum = workersMin;
        server->workers.maximum = workersMax;
        server->workers.accepting = accepting;
        server->stateChange = PR_NewCondVar(server->ml);
        server->pool.exiting = PR_NewCondVar(server->ml);
        server->pool.acceptComplete = PR_NewCondVar(server->ml);

        TEST_LOG(
            cltsrv_log_file, TEST_LOG_NOTICE,
            ("main(0x%p): creating server thread\n", PR_GetCurrentThread()));

        server->thread = PR_CreateThread(
            PR_USER_THREAD, Server, server, PR_PRIORITY_HIGH,
            thread_scope, PR_JOINABLE_THREAD, 0);
        TEST_ASSERT(NULL != server->thread);

        TEST_LOG(
            cltsrv_log_file, TEST_LOG_VERBOSE,
            ("main(0x%p): waiting for server init\n", PR_GetCurrentThread()));

        PR_Lock(server->ml);
        while (server->state == cs_init)
            PR_WaitCondVar(server->stateChange, PR_INTERVAL_NO_TIMEOUT);
        PR_Unlock(server->ml);

        TEST_LOG(
            cltsrv_log_file, TEST_LOG_VERBOSE,
            ("main(0x%p): server init complete (port #%d)\n",
            PR_GetCurrentThread(), server->port));
    }

    if (clients != 0)
    {
        /* Create all of the clients */
        PRHostEnt host;
        char buffer[BUFFER_SIZE];
        client = (CSClient_t*)PR_CALLOC(clients * sizeof(CSClient_t));

        TEST_LOG(
            cltsrv_log_file, TEST_LOG_VERBOSE,
            ("main(0x%p): creating %d client threads\n",
            PR_GetCurrentThread(), clients));
        
        if (!serverIsLocal)
        {
            rv = PR_GetHostByName(serverName, buffer, BUFFER_SIZE, &host);
            if (PR_SUCCESS != rv)
            {
                PL_FPrintError(PR_STDERR, "PR_GetHostByName");
                return 2;
            }
        }

        for (index = 0; index < clients; ++index)
        {
            client[index].state = cs_init;
            client[index].ml = PR_NewLock();
            if (serverIsLocal)
            {
				if (PR_AF_INET6 != domain)
                	(void)PR_InitializeNetAddr(
                    	PR_IpAddrLoopback, DEFAULT_PORT,
                    	&client[index].serverAddress);
				else
					rv = PR_SetNetAddr(PR_IpAddrLoopback, PR_AF_INET6,
							DEFAULT_PORT, &client[index].serverAddress);
            }
            else
            {
                (void)PR_EnumerateHostEnt(
                    0, &host, DEFAULT_PORT, &client[index].serverAddress);
            }
            client[index].stateChange = PR_NewCondVar(client[index].ml);
            TEST_LOG(
                cltsrv_log_file, TEST_LOG_INFO,
                ("main(0x%p): creating client threads\n", PR_GetCurrentThread()));
            client[index].thread = PR_CreateThread(
                PR_USER_THREAD, Client, &client[index], PR_PRIORITY_NORMAL,
                thread_scope, PR_JOINABLE_THREAD, 0);
            TEST_ASSERT(NULL != client[index].thread);
            PR_Lock(client[index].ml);
            while (cs_init == client[index].state)
                PR_WaitCondVar(client[index].stateChange, PR_INTERVAL_NO_TIMEOUT);
            PR_Unlock(client[index].ml);
        }
    }

    /* Then just let them go at it for a bit */
    TEST_LOG(
        cltsrv_log_file, TEST_LOG_ALWAYS,
        ("main(0x%p): waiting for execution interval (%d seconds)\n",
        PR_GetCurrentThread(), execution));

    WaitForCompletion(execution);

    TimeOfDayMessage("Shutting down", PR_GetCurrentThread());

    if (clients != 0)
    {
        for (index = 0; index < clients; ++index)
        {
            TEST_LOG(cltsrv_log_file, TEST_LOG_STATUS, 
                ("main(0x%p): notifying client(0x%p) to stop\n",
                PR_GetCurrentThread(), client[index].thread));

            PR_Lock(client[index].ml);
            if (cs_run == client[index].state)
            {
                client[index].state = cs_stop;
                PR_Interrupt(client[index].thread);
                while (cs_stop == client[index].state)
                    PR_WaitCondVar(
                        client[index].stateChange, PR_INTERVAL_NO_TIMEOUT);
            }
            PR_Unlock(client[index].ml);

            TEST_LOG(cltsrv_log_file, TEST_LOG_VERBOSE, 
                ("main(0x%p): joining client(0x%p)\n",
                PR_GetCurrentThread(), client[index].thread));

		    joinStatus = PR_JoinThread(client[index].thread);
		    TEST_ASSERT(PR_SUCCESS == joinStatus);
            PR_DestroyCondVar(client[index].stateChange);
            PR_DestroyLock(client[index].ml);
        }
        PR_DELETE(client);
    }

    if (NULL != server)
    {
        /* All clients joined - retrieve the server */
        TEST_LOG(
            cltsrv_log_file, TEST_LOG_NOTICE, 
            ("main(0x%p): notifying server(0x%p) to stop\n",
            PR_GetCurrentThread(), server->thread));

        PR_Lock(server->ml);
        server->state = cs_stop;
        PR_Interrupt(server->thread);
        while (cs_exit != server->state)
            PR_WaitCondVar(server->stateChange, PR_INTERVAL_NO_TIMEOUT);
        PR_Unlock(server->ml);

        TEST_LOG(
            cltsrv_log_file, TEST_LOG_NOTICE, 
            ("main(0x%p): joining server(0x%p)\n",
            PR_GetCurrentThread(), server->thread));
        joinStatus = PR_JoinThread(server->thread);
        TEST_ASSERT(PR_SUCCESS == joinStatus);

        PR_DestroyCondVar(server->stateChange);
        PR_DestroyCondVar(server->pool.exiting);
        PR_DestroyCondVar(server->pool.acceptComplete);
        PR_DestroyLock(server->ml);
        PR_DELETE(server);
    }

    TEST_LOG(
        cltsrv_log_file, TEST_LOG_ALWAYS, 
        ("main(0x%p): test complete\n", PR_GetCurrentThread()));

    PT_FPrintStats(debug_out, "\nPThread Statistics\n");

    TimeOfDayMessage("Test exiting at", PR_GetCurrentThread());
    PR_Cleanup();
    return 0;
}  /* main */
Ejemplo n.º 22
0
static void s_SingleBounceCheck
(CONN            conn,
 const STimeout* timeout,
 FILE*           data_file)
{
    static const char sym[] = {
        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'
    };
    EIO_Status status;
    char message[128];

#define TEST_N_LINES 200
#define TEST_BUF_SIZE (TEST_N_LINES * (TEST_N_LINES + 3) / 2)
    char  buf[TEST_BUF_SIZE];

    TEST_LOG(eIO_Success, "[s_SingleBounceCheck]  Starting...");

    /* WRITE to the connection:  "0\n12\n345\n6789\n01234\n........"
     */
    {{
        size_t k = 0, j = 0;
        size_t i;
        for (i = 0;  k != sizeof(buf);  i++) {
            /* prepare output data */
            size_t n_write, n_written;
            for (n_write = 0;  n_write < i;  n_write++, k++) {
                assert(k < sizeof(buf));
                buf[n_write] = sym[j++ % sizeof(sym)];
            }
            assert(k < sizeof(buf));
            if ( n_write ) {
                buf[n_write++] = '\n';  k++;
            }
            buf[n_write] = '\0';

            do { /* persistently */
                /* WAIT... sometimes */
                if (n_write % 5 == 3) {
                    status = CONN_Wait(conn, eIO_Write, timeout);
                    if (status != eIO_Success) {
                        TEST_LOG(status,
                                 "[s_SingleBounceCheck]  CONN_Wait(write)"
                                 " failed, retrying...");
                        assert(status == eIO_Timeout);
                    }
                }

                /* WRITE */
                status = CONN_Write(conn, buf, n_write,
                                    &n_written, eIO_WritePersist);
                if (status != eIO_Success) {
                    TEST_LOG(status,
                             "[s_SingleBounceCheck]  CONN_Write(persistent)"
                             " failed, retrying...");
                    assert(n_written < n_write);
                    assert(status == eIO_Timeout);
                } else {
                    assert(n_written == n_write);
                }
            } while (status != eIO_Success);
        }
    }}

    /* READ the "bounced" data from the connection, the first TEST_BUF_SIZE
     * bytes must be:  "0\n12\n345\n6789\n01234\n........"
     */
    {{
        char* x_buf;
        size_t n_read, n_to_read;

        memset(buf, '\0', TEST_BUF_SIZE);

        /* PEEK until the 1st 1/3 of the "bounced" data is available */
        x_buf = buf;
        n_to_read = TEST_BUF_SIZE/3;

        do {
            TEST_LOG(eIO_Success, "[s_SingleBounceCheck]  1/3 PEEK...");
            status = CONN_Read(conn, x_buf, n_to_read, &n_read, eIO_ReadPeek);
            if (status != eIO_Success) {
                TEST_LOG(status,
                         "[s_SingleBounceCheck]  1/3 CONN_Read(peek)"
                         " failed, retrying...");
                assert(n_read < n_to_read);
                assert(status == eIO_Timeout);
            }
            if (n_read < n_to_read) {
                sprintf(message, "[s_SingleBounceCheck]  1/3 CONN_Read(peek)"
                        " %lu byte%s peeked out of %lu byte%s, continuing...",
                        (unsigned long) n_read,    &"s"[n_read    == 1],
                        (unsigned long) n_to_read, &"s"[n_to_read == 1]);
                TEST_LOG(status, message);
            }
        } while (n_read != n_to_read);

        /* READ 1st 1/3 of "bounced" data, compare it with the PEEKed data */
        TEST_LOG(eIO_Success, "[s_SingleBounceCheck]  1/3 READ...");
        status = CONN_Read(conn, x_buf + n_to_read, n_to_read, &n_read,
                           eIO_ReadPlain);
        if (status != eIO_Success) {
            TEST_LOG(status,
                     "[s_SingleBounceCheck]  1/3 CONN_Read(plain) failed");
        }
        assert(status == eIO_Success);
        assert(n_read == n_to_read);
        assert(memcmp(x_buf, x_buf + n_to_read, n_to_read) == 0);
        memset(x_buf + n_to_read, '\0', n_to_read);

        /* WAIT on read */
        status = CONN_Wait(conn, eIO_Read, timeout);
        if (status != eIO_Success) {
            TEST_LOG(status,
                     "[s_SingleBounceCheck]  CONN_Wait(read) failed");
            assert(status == eIO_Timeout);
        }

        /* READ the 2nd 1/3 of "bounced" data */
        x_buf = buf + TEST_BUF_SIZE/3;
        n_to_read = TEST_BUF_SIZE/3;

        while ( n_to_read ) {
            TEST_LOG(eIO_Success, "[s_SingleBounceCheck]  2/3 READ...");
            status = CONN_Read(conn, x_buf, n_to_read, &n_read, eIO_ReadPlain);
            if (status != eIO_Success) {
                sprintf(message, "[s_SingleBounceCheck]  2/3 CONN_Read(plain)"
                        " %lu byte%s read out of %lu byte%s, retrying...",
                        (unsigned long) n_read,    &"s"[n_read    == 1],
                        (unsigned long) n_to_read, &"s"[n_to_read == 1]);
                TEST_LOG(status, message);
                assert(n_read < n_to_read);
                assert(status == eIO_Timeout);
            } else {
                assert(n_read <= n_to_read);
            }
            n_to_read -= n_read;
            x_buf     += n_read;
        }
        assert(status == eIO_Success);

        /* Persistently READ the 3rd 1/3 of "bounced" data */
        n_to_read = TEST_BUF_SIZE - (x_buf - buf);

        TEST_LOG(eIO_Success, "[s_SingleBounceCheck]  3/3 READ...");
        status = CONN_Read(conn, x_buf, n_to_read, &n_read, eIO_ReadPersist);
        if (status != eIO_Success) {
            sprintf(message, "[s_SingleBounceCheck]  3/3 CONN_Read(persistent)"
                    " %lu byte%s read",
                    (unsigned long) n_read, &"s"[n_read == 1]);
            TEST_LOG(status, message);
            assert(n_read < n_to_read);
            assert(0);
        } else {
            assert(n_read == n_to_read);
        }
    }}

    /* Check for the received "bounced" data is identical to the sent data
     */
    {{
        const char* x_buf = buf;
        size_t k = 0, j = 0;
        size_t i;
        for (i = 1;  k != sizeof(buf);  i++) {
            size_t n;
            for (n = 0;  n < i;  n++, k++) {
                if (k == sizeof(buf))
                    break;
                assert(*x_buf++ == sym[j++ % sizeof(sym)]);
            }
            assert(*x_buf++ == '\n');  k++;
        }
    }}

    /* Now when the "bounced" data is read and tested, READ an arbitrary extra
     * data sent in by the peer and print it out to LOG file
     */
    if ( data_file ) {
        fprintf(data_file, "\ns_SingleBounceCheck(BEGIN EXTRA DATA)\n");
        fflush(data_file);
        for (;;) {
            size_t n;

            TEST_LOG(eIO_Success,
                     "[s_SingleBounceCheck]  EXTRA READ...");
            status = CONN_Read(conn, buf, sizeof(buf), &n, eIO_ReadPersist);
            TEST_LOG(status,
                     "[s_SingleBounceCheck]  EXTRA CONN_Read(persistent)");
            if ( n ) {
                assert(fwrite(buf, n, 1, data_file) == 1);
                fflush(data_file);
            }
            if (status == eIO_Closed  ||  status == eIO_Timeout)
                break; /* okay */

            assert(status == eIO_Success);
        }
        fprintf(data_file, "\ns_SingleBounceCheck(END EXTRA DATA)\n\n");
        fflush(data_file);
    }

    TEST_LOG(eIO_Success, "[s_SingleBounceCheck]  ...finished");
}
static void PR_CALLBACK Server(void *arg)
{
    PRStatus rv;
    PRNetAddr serverAddress;
    PRThread *me = PR_GetCurrentThread();
    CSServer_t *server = (CSServer_t*)arg;
    PRSocketOptionData sockOpt;

    server->listener = PR_Socket(domain, SOCK_STREAM, protocol);

    sockOpt.option = PR_SockOpt_Reuseaddr;
    sockOpt.value.reuse_addr = PR_TRUE;
    rv = PR_SetSocketOption(server->listener, &sockOpt);
    TEST_ASSERT(PR_SUCCESS == rv);

    memset(&serverAddress, 0, sizeof(serverAddress));
	if (PR_AF_INET6 != domain)
		rv = PR_InitializeNetAddr(PR_IpAddrAny, DEFAULT_PORT, &serverAddress);
	else
		rv = PR_SetNetAddr(PR_IpAddrAny, PR_AF_INET6, DEFAULT_PORT,
													&serverAddress);
    rv = PR_Bind(server->listener, &serverAddress);
    TEST_ASSERT(PR_SUCCESS == rv);

    rv = PR_Listen(server->listener, server->backlog);
    TEST_ASSERT(PR_SUCCESS == rv);

    server->started = PR_IntervalNow();
    TimeOfDayMessage("Server started at", me);

    PR_Lock(server->ml);
    server->state = cs_run;
    PR_NotifyCondVar(server->stateChange);
    PR_Unlock(server->ml);

    /*
    ** Create the first worker (actually, a thread that accepts
    ** connections and then processes the work load as needed).
    ** From this point on, additional worker threads are created
    ** as they are needed by existing worker threads.
    */
    rv = CreateWorker(server, &server->pool);
    TEST_ASSERT(PR_SUCCESS == rv);

    /*
    ** From here on this thread is merely hanging around as the contact
    ** point for the main test driver. It's just waiting for the driver
    ** to declare the test complete.
    */
    TEST_LOG(
        cltsrv_log_file, TEST_LOG_VERBOSE,
        ("\tServer(0x%p): waiting for state change\n", me));

    PR_Lock(server->ml);
    while ((cs_run == server->state) && !Aborted(rv))
    {
        rv = PR_WaitCondVar(server->stateChange, PR_INTERVAL_NO_TIMEOUT);
    }
    PR_Unlock(server->ml);
    PR_ClearInterrupt();

    TEST_LOG(
        cltsrv_log_file, TEST_LOG_INFO,
        ("\tServer(0x%p): shutting down workers\n", me));

    /*
    ** Get all the worker threads to exit. They know how to
    ** clean up after themselves, so this is just a matter of
    ** waiting for clorine in the pool to take effect. During
    ** this stage we're ignoring interrupts.
    */
    server->workers.minimum = server->workers.maximum = 0;

    PR_Lock(server->ml);
    while (!PR_CLIST_IS_EMPTY(&server->list))
    {
        PRCList *head = PR_LIST_HEAD(&server->list);
        CSWorker_t *worker = (CSWorker_t*)head;
        TEST_LOG(
            cltsrv_log_file, TEST_LOG_VERBOSE,
            ("\tServer(0x%p): interrupting worker(0x%p)\n", me, worker));
        rv = PR_Interrupt(worker->thread);
        TEST_ASSERT(PR_SUCCESS == rv);
        PR_REMOVE_AND_INIT_LINK(head);
    }

    while (server->pool.workers > 0)
    {
        TEST_LOG(
            cltsrv_log_file, TEST_LOG_NOTICE,
            ("\tServer(0x%p): waiting for %u workers to exit\n",
            me, server->pool.workers));
        (void)PR_WaitCondVar(server->pool.exiting, PR_INTERVAL_NO_TIMEOUT);
    }

    server->state = cs_exit;
    PR_NotifyCondVar(server->stateChange);
    PR_Unlock(server->ml);

    TEST_LOG(
        cltsrv_log_file, TEST_LOG_ALWAYS,
        ("\tServer(0x%p): stopped after %u operations and %u bytes\n",
        me, server->operations, server->bytesTransferred));

    if (NULL != server->listener) PR_Close(server->listener);
    server->stopped = PR_IntervalNow();

}  /* Server */
static void PR_CALLBACK Worker(void *arg)
{
    PRStatus rv;
    PRNetAddr from;
    PRFileDesc *fd = NULL;
    PRThread *me = PR_GetCurrentThread();
    CSWorker_t *worker = (CSWorker_t*)arg;
    CSServer_t *server = worker->server;
    CSPool_t *pool = &server->pool;

    TEST_LOG(
        cltsrv_log_file, TEST_LOG_NOTICE,
        ("\t\tWorker(0x%p): started [%u]\n", me, pool->workers + 1));

    PR_Lock(server->ml);
    PR_APPEND_LINK(&worker->element, &server->list);
    pool->workers += 1;  /* define our existance */

    while (cs_run == server->state)
    {
        while (pool->accepting >= server->workers.accepting)
        {
            TEST_LOG(
                cltsrv_log_file, TEST_LOG_VERBOSE,
                ("\t\tWorker(0x%p): waiting for accept slot[%d]\n",
                me, pool->accepting));
            rv = PR_WaitCondVar(pool->acceptComplete, PR_INTERVAL_NO_TIMEOUT);
            if (Aborted(rv) || (cs_run != server->state))
            {
                TEST_LOG(
                    cltsrv_log_file, TEST_LOG_NOTICE,
                    ("\tWorker(0x%p): has been %s\n",
                    me, (Aborted(rv) ? "interrupted" : "stopped")));
                goto exit;
            }
        } 
        pool->accepting += 1;  /* how many are really in accept */
        PR_Unlock(server->ml);

        TEST_LOG(
            cltsrv_log_file, TEST_LOG_VERBOSE,
            ("\t\tWorker(0x%p): calling accept\n", me));
        fd = PR_Accept(server->listener, &from, PR_INTERVAL_NO_TIMEOUT);

        PR_Lock(server->ml);        
        pool->accepting -= 1;
        PR_NotifyCondVar(pool->acceptComplete);

        if ((NULL == fd) && Aborted(PR_FAILURE))
        {
            if (NULL != server->listener)
            {
                PR_Close(server->listener);
                server->listener = NULL;
            }
            goto exit;
        }

        if (NULL != fd)
        {
            /*
            ** Create another worker of the total number of workers is
            ** less than the minimum specified or we have none left in
            ** accept() AND we're not over the maximum.
            ** This sort of presumes that the number allowed in accept
            ** is at least as many as the minimum. Otherwise we'll keep
            ** creating new threads and deleting them soon after.
            */
            PRBool another =
                ((pool->workers < server->workers.minimum) ||
                ((0 == pool->accepting)
                    && (pool->workers < server->workers.maximum))) ?
                    PR_TRUE : PR_FALSE;
            pool->active += 1;
            PR_Unlock(server->ml);

            if (another) (void)CreateWorker(server, pool);

            rv = ProcessRequest(fd, server);
            if (PR_SUCCESS != rv)
                TEST_LOG(
                    cltsrv_log_file, TEST_LOG_ERROR,
                    ("\t\tWorker(0x%p): server process ended abnormally\n", me));
            (void)PR_Close(fd); fd = NULL;

            PR_Lock(server->ml);
            pool->active -= 1;
        }
    }

exit:
    PR_ClearInterrupt();    
    PR_Unlock(server->ml);

    if (NULL != fd)
    {
        (void)PR_Shutdown(fd, PR_SHUTDOWN_BOTH);
        (void)PR_Close(fd);
    }

    TEST_LOG(
        cltsrv_log_file, TEST_LOG_NOTICE,
        ("\t\tWorker(0x%p): exiting [%u]\n", PR_GetCurrentThread(), pool->workers));

    PR_Lock(server->ml);
    pool->workers -= 1;  /* undefine our existance */
    PR_REMOVE_AND_INIT_LINK(&worker->element);
    PR_NotifyCondVar(pool->exiting);
    PR_Unlock(server->ml);

    PR_DELETE(worker);  /* destruction of the "worker" object */

}  /* Worker */
Ejemplo n.º 25
0
void CONN_TestConnector
(CONNECTOR       connector,
 const STimeout* timeout,
 FILE*           data_file,
 TTestConnFlags  flags)
{
    EIO_Status status;
    SConnector dummy;
    CONN       conn;

    memset(&dummy, 0, sizeof(dummy));

    TEST_LOG(eIO_Success, "[CONN_TestConnector]  Starting...");

    /* Fool around with dummy connector / connection
     */
    assert(CONN_Create(0,      &conn) != eIO_Success  &&  !conn);
    assert(CONN_Create(&dummy, &conn) != eIO_Success  &&  !conn);
    dummy.setup = s_DummySetup;
    assert(CONN_Create(&dummy, &conn) == eIO_Success);
    assert(CONN_Flush (conn)          != eIO_Success);
    assert(CONN_ReInit(conn, 0)       == eIO_Success);
    assert(CONN_ReInit(conn, 0)       != eIO_Success);
    assert(CONN_ReInit(conn, &dummy)  == eIO_Success);
    assert(CONN_Flush (conn)          != eIO_Success);
    assert(CONN_ReInit(conn, &dummy)  == eIO_Success);
    assert(CONN_ReInit(conn, 0)       == eIO_Success);
    assert(CONN_Close (conn)          == eIO_Success);

    /* CREATE new connection on the base of the connector, set
     * TIMEOUTs, try to RECONNECT, WAIT for the connection is writable
     */
    assert(CONN_Create(connector, &conn) == eIO_Success);

    assert(CONN_SetTimeout(conn, eIO_Open,      timeout) == eIO_Success);
    assert(CONN_SetTimeout(conn, eIO_ReadWrite, timeout) == eIO_Success);
    assert(CONN_SetTimeout(conn, eIO_Close,     timeout) == eIO_Success);

    assert(CONN_ReInit(conn, connector) == eIO_Success);

    status = CONN_Wait(conn, eIO_Write, timeout);
    if (status != eIO_Success) {
        TEST_LOG(status, "[CONN_TestConnector]  CONN_Wait(write) failed");
        assert(status == eIO_Timeout);
    }

    /* Run the specified TESTs
     */
    if ( !flags ) {
        flags = fTC_Everything;
    }
    if (flags & fTC_SingleBouncePrint) {
        s_SingleBouncePrint(conn, data_file);
    }
    if (flags & fTC_MultiBouncePrint) {
        s_MultiBouncePrint(conn, data_file);
    }
    if (flags & fTC_SingleBounceCheck) {
        s_SingleBounceCheck(conn, timeout, data_file);
    }

    /* And CLOSE the connection...
     */
    assert(CONN_Close(conn) == eIO_Success);

    TEST_LOG(eIO_Success, "[CONN_TestConnector]  Completed");
}
static PRStatus ProcessRequest(PRFileDesc *fd, CSServer_t *server)
{
    PRStatus drv, rv;
    char buffer[1024];
    PRFileDesc *file = NULL;
    PRThread * me = PR_GetCurrentThread();
    PRInt32 bytes, descbytes, netbytes, filebytes = 0;
    CSDescriptor_t *descriptor = PR_NEW(CSDescriptor_t);
    PRIntervalTime timeout = PR_MillisecondsToInterval(DEFAULT_SERVER_TIMEOUT);

    TEST_LOG(
        cltsrv_log_file, TEST_LOG_VERBOSE,
        ("\tProcessRequest(0x%p): receiving desciptor\n", me));
    bytes = PR_Recv(
        fd, descriptor, sizeof(*descriptor), RECV_FLAGS, timeout);
    if (-1 == bytes)
    {
        rv = PR_FAILURE;
        if (Aborted(rv)) goto exit;
        if (PR_IO_TIMEOUT_ERROR == PR_GetError())
        {
            TEST_LOG(
                cltsrv_log_file, TEST_LOG_ERROR,
                ("\tProcessRequest(0x%p): receive timeout\n", me));
        }
        goto exit;
    }
    if (0 == bytes)
    {
        rv = PR_FAILURE;
        TEST_LOG(
            cltsrv_log_file, TEST_LOG_ERROR,
            ("\tProcessRequest(0x%p): unexpected end of file\n", me));
        goto exit;
    }
    descbytes = PR_ntohl(descriptor->size);
    TEST_ASSERT(sizeof(*descriptor) == bytes);

    TEST_LOG(
        cltsrv_log_file, TEST_LOG_VERBOSE, 
        ("\t\tProcessRequest(0x%p): read descriptor {%d, %s}\n",
        me, descbytes, descriptor->filename));

    file = PR_Open(
        descriptor->filename, (PR_CREATE_FILE | PR_WRONLY), 0666);
    if (NULL == file)
    {
        rv = PR_FAILURE;
        if (Aborted(rv)) goto aborted;
        if (PR_IO_TIMEOUT_ERROR == PR_GetError())
        {
            TEST_LOG(
                cltsrv_log_file, TEST_LOG_ERROR,
                ("\tProcessRequest(0x%p): open file timeout\n", me));
            goto aborted;
        }
    }
    TEST_ASSERT(NULL != file);

    filebytes = 0;
    while (filebytes < descbytes)
    {
        netbytes = sizeof(buffer);
        if ((descbytes - filebytes) < netbytes)
            netbytes = descbytes - filebytes;
        TEST_LOG(
            cltsrv_log_file, TEST_LOG_VERBOSE,
            ("\tProcessRequest(0x%p): receive %d bytes\n", me, netbytes));
        bytes = PR_Recv(fd, buffer, netbytes, RECV_FLAGS, timeout);
        if (-1 == bytes)
        {
            rv = PR_FAILURE;
            if (Aborted(rv)) goto aborted;
            if (PR_IO_TIMEOUT_ERROR == PR_GetError())
            {
                TEST_LOG(
                    cltsrv_log_file, TEST_LOG_ERROR,
                    ("\t\tProcessRequest(0x%p): receive data timeout\n", me));
                goto aborted;
            }
            /*
             * XXX: I got (PR_CONNECT_RESET_ERROR, ERROR_NETNAME_DELETED)
             * on NT here.  This is equivalent to ECONNRESET on Unix.
             *     -wtc
             */
            TEST_LOG(
                cltsrv_log_file, TEST_LOG_WARNING,
                ("\t\tProcessRequest(0x%p): unexpected error (%d, %d)\n",
                me, PR_GetError(), PR_GetOSError()));
            goto aborted;
        }
        if(0 == bytes)
        {
            TEST_LOG(
                cltsrv_log_file, TEST_LOG_WARNING,
                ("\t\tProcessRequest(0x%p): unexpected end of stream\n", me));
            rv = PR_FAILURE;
            goto aborted;
        }
        filebytes += bytes;
        netbytes = bytes;
        /* The byte count for PR_Write should be positive */
        MY_ASSERT(netbytes > 0);
        TEST_LOG(
            cltsrv_log_file, TEST_LOG_VERBOSE,
            ("\tProcessRequest(0x%p): write %d bytes to file\n", me, netbytes));
        bytes = PR_Write(file, buffer, netbytes);
        if (netbytes != bytes)
        {
            rv = PR_FAILURE;
            if (Aborted(rv)) goto aborted;
            if (PR_IO_TIMEOUT_ERROR == PR_GetError())
            {
                TEST_LOG(
                    cltsrv_log_file, TEST_LOG_ERROR,
                    ("\t\tProcessRequest(0x%p): write file timeout\n", me));
                goto aborted;
            }
        }
        TEST_ASSERT(bytes > 0);
    }

    PR_Lock(server->ml);
    server->operations += 1;
    server->bytesTransferred += filebytes;
    PR_Unlock(server->ml);

    rv = PR_Close(file);
    if (Aborted(rv)) goto aborted;
    TEST_ASSERT(PR_SUCCESS == rv);
    file = NULL;

    TEST_LOG(
        cltsrv_log_file, TEST_LOG_VERBOSE,
        ("\t\tProcessRequest(0x%p): opening %s\n", me, descriptor->filename));
    file = PR_Open(descriptor->filename, PR_RDONLY, 0);
    if (NULL == file)
    {
        rv = PR_FAILURE;
        if (Aborted(rv)) goto aborted;
        if (PR_IO_TIMEOUT_ERROR == PR_GetError())
        {
            TEST_LOG(
                cltsrv_log_file, TEST_LOG_ERROR,
                ("\t\tProcessRequest(0x%p): open file timeout\n",
                PR_GetCurrentThread()));
            goto aborted;
        }
        TEST_LOG(
            cltsrv_log_file, TEST_LOG_ERROR,
            ("\t\tProcessRequest(0x%p): other file open error (%u, %u)\n",
            me, PR_GetError(), PR_GetOSError()));
        goto aborted;
    }
    TEST_ASSERT(NULL != file);

    netbytes = 0;
    while (netbytes < descbytes)
    {
        filebytes = sizeof(buffer);
        if ((descbytes - netbytes) < filebytes)
            filebytes = descbytes - netbytes;
        TEST_LOG(
            cltsrv_log_file, TEST_LOG_VERBOSE,
            ("\tProcessRequest(0x%p): read %d bytes from file\n", me, filebytes));
        bytes = PR_Read(file, buffer, filebytes);
        if (filebytes != bytes)
        {
            rv = PR_FAILURE;
            if (Aborted(rv)) goto aborted;
            if (PR_IO_TIMEOUT_ERROR == PR_GetError())
                TEST_LOG(
                    cltsrv_log_file, TEST_LOG_ERROR,
                    ("\t\tProcessRequest(0x%p): read file timeout\n", me));
            else
                TEST_LOG(
                    cltsrv_log_file, TEST_LOG_ERROR,
                    ("\t\tProcessRequest(0x%p): other file error (%d, %d)\n",
                    me, PR_GetError(), PR_GetOSError()));
            goto aborted;
        }
        TEST_ASSERT(bytes > 0);
        netbytes += bytes;
        filebytes = bytes;
        TEST_LOG(
            cltsrv_log_file, TEST_LOG_VERBOSE,
            ("\t\tProcessRequest(0x%p): sending %d bytes\n", me, filebytes));
        bytes = PR_Send(fd, buffer, filebytes, SEND_FLAGS, timeout);
        if (filebytes != bytes)
        {
            rv = PR_FAILURE;
            if (Aborted(rv)) goto aborted;
            if (PR_IO_TIMEOUT_ERROR == PR_GetError())
            {
                TEST_LOG(
                    cltsrv_log_file, TEST_LOG_ERROR,
                    ("\t\tProcessRequest(0x%p): send data timeout\n", me));
                goto aborted;
            }
            break;
        }
       TEST_ASSERT(bytes > 0);
    }
    
    PR_Lock(server->ml);
    server->bytesTransferred += filebytes;
    PR_Unlock(server->ml);

    rv = PR_Shutdown(fd, PR_SHUTDOWN_BOTH);
    if (Aborted(rv)) goto aborted;

    rv = PR_Close(file);
    if (Aborted(rv)) goto aborted;
    TEST_ASSERT(PR_SUCCESS == rv);
    file = NULL;

aborted:
    PR_ClearInterrupt();
    if (NULL != file) PR_Close(file);
    drv = PR_Delete(descriptor->filename);
    TEST_ASSERT(PR_SUCCESS == drv);
exit:
    TEST_LOG(
        cltsrv_log_file, TEST_LOG_VERBOSE,
        ("\t\tProcessRequest(0x%p): Finished\n", me));

    PR_DELETE(descriptor);

#if defined(WIN95)
    PR_Sleep(PR_MillisecondsToInterval(200)); /* lth. see note [1] */
#endif
    return rv;
}  /* ProcessRequest */
static void PR_CALLBACK Client(void *arg)
{
    PRStatus rv;
    PRIntn index;
    char buffer[1024];
    PRFileDesc *fd = NULL;
    PRUintn clipping = DEFAULT_CLIPPING;
    PRThread *me = PR_GetCurrentThread();
    CSClient_t *client = (CSClient_t*)arg;
    CSDescriptor_t *descriptor = PR_NEW(CSDescriptor_t);
    PRIntervalTime timeout = PR_MillisecondsToInterval(DEFAULT_CLIENT_TIMEOUT);


    for (index = 0; index < sizeof(buffer); ++index)
        buffer[index] = (char)index;

    client->started = PR_IntervalNow();

    PR_Lock(client->ml);
    client->state = cs_run;
    PR_NotifyCondVar(client->stateChange);
    PR_Unlock(client->ml);

    TimeOfDayMessage("Client started at", me);

    while (cs_run == client->state)
    {
        PRInt32 bytes, descbytes, filebytes, netbytes;

        (void)PR_NetAddrToString(&client->serverAddress, buffer, sizeof(buffer));
        TEST_LOG(cltsrv_log_file, TEST_LOG_INFO, 
            ("\tClient(0x%p): connecting to server at %s\n", me, buffer));

        fd = PR_Socket(domain, SOCK_STREAM, protocol);
        TEST_ASSERT(NULL != fd);
        rv = PR_Connect(fd, &client->serverAddress, timeout);
        if (PR_FAILURE == rv)
        {
            TEST_LOG(
                cltsrv_log_file, TEST_LOG_ERROR,
                ("\tClient(0x%p): conection failed (%d, %d)\n",
                me, PR_GetError(), PR_GetOSError()));
            goto aborted;
        }

        memset(descriptor, 0, sizeof(*descriptor));
        descriptor->size = PR_htonl(descbytes = rand() % clipping);
        PR_snprintf(
            descriptor->filename, sizeof(descriptor->filename),
            "CS%p%p-%p.dat", client->started, me, client->operations);
        TEST_LOG(
            cltsrv_log_file, TEST_LOG_VERBOSE,
            ("\tClient(0x%p): sending descriptor for %u bytes\n", me, descbytes));
        bytes = PR_Send(
            fd, descriptor, sizeof(*descriptor), SEND_FLAGS, timeout);
        if (sizeof(CSDescriptor_t) != bytes)
        {
            if (Aborted(PR_FAILURE)) goto aborted;
            if (PR_IO_TIMEOUT_ERROR == PR_GetError())
            {
                TEST_LOG(
                    cltsrv_log_file, TEST_LOG_ERROR,
                    ("\tClient(0x%p): send descriptor timeout\n", me));
                goto retry;
            }
        }
        TEST_ASSERT(sizeof(*descriptor) == bytes);

        netbytes = 0;
        while (netbytes < descbytes)
        {
            filebytes = sizeof(buffer);
            if ((descbytes - netbytes) < filebytes)
                filebytes = descbytes - netbytes;
            TEST_LOG(
                cltsrv_log_file, TEST_LOG_VERBOSE,
                ("\tClient(0x%p): sending %d bytes\n", me, filebytes));
            bytes = PR_Send(fd, buffer, filebytes, SEND_FLAGS, timeout);
            if (filebytes != bytes)
            {
                if (Aborted(PR_FAILURE)) goto aborted;
                if (PR_IO_TIMEOUT_ERROR == PR_GetError())
                {
                    TEST_LOG(
                        cltsrv_log_file, TEST_LOG_ERROR,
                        ("\tClient(0x%p): send data timeout\n", me));
                    goto retry;
                }
            }
            TEST_ASSERT(bytes == filebytes);
            netbytes += bytes;
        }
        filebytes = 0;
        while (filebytes < descbytes)
        {
            netbytes = sizeof(buffer);
            if ((descbytes - filebytes) < netbytes)
                netbytes = descbytes - filebytes;
            TEST_LOG(
                cltsrv_log_file, TEST_LOG_VERBOSE,
                ("\tClient(0x%p): receiving %d bytes\n", me, netbytes));
            bytes = PR_Recv(fd, buffer, netbytes, RECV_FLAGS, timeout);
            if (-1 == bytes)
            {
                if (Aborted(PR_FAILURE))
                {
                    TEST_LOG(
                        cltsrv_log_file, TEST_LOG_ERROR,
                        ("\tClient(0x%p): receive data aborted\n", me));
                    goto aborted;
                }
                else if (PR_IO_TIMEOUT_ERROR == PR_GetError())
                    TEST_LOG(
                        cltsrv_log_file, TEST_LOG_ERROR,
                        ("\tClient(0x%p): receive data timeout\n", me));
				else
                    TEST_LOG(
                        cltsrv_log_file, TEST_LOG_ERROR,
                        ("\tClient(0x%p): receive error (%d, %d)\n",
						me, PR_GetError(), PR_GetOSError()));
                goto retry;
           }
            if (0 == bytes)
            {
                TEST_LOG(
                    cltsrv_log_file, TEST_LOG_ERROR,
                    ("\t\tClient(0x%p): unexpected end of stream\n",
                    PR_GetCurrentThread()));
                break;
            }
            filebytes += bytes;
        }

        rv = PR_Shutdown(fd, PR_SHUTDOWN_BOTH);
        if (Aborted(rv)) goto aborted;
        TEST_ASSERT(PR_SUCCESS == rv);
retry:
        (void)PR_Close(fd); fd = NULL;
        TEST_LOG(
            cltsrv_log_file, TEST_LOG_INFO,
            ("\tClient(0x%p): disconnected from server\n", me));

        PR_Lock(client->ml);
        client->operations += 1;
        client->bytesTransferred += 2 * descbytes;
        rv = PR_WaitCondVar(client->stateChange, rand() % clipping);
        PR_Unlock(client->ml);
        if (Aborted(rv)) break;
    }

aborted:
    client->stopped = PR_IntervalNow();

    PR_ClearInterrupt();
    if (NULL != fd) rv = PR_Close(fd);

    PR_Lock(client->ml);
    client->state = cs_exit;
    PR_NotifyCondVar(client->stateChange);
    PR_Unlock(client->ml);
    PR_DELETE(descriptor);
    TEST_LOG(
        cltsrv_log_file, TEST_LOG_ALWAYS,
        ("\tClient(0x%p): stopped after %u operations and %u bytes\n",
        PR_GetCurrentThread(), client->operations, client->bytesTransferred));

}  /* Client */