Home | History | Annotate | Download | only in test
      1 #ifdef __STRICT_ANSI__
      2 #define _BSD_SOURCE
      3 #endif
      4 #include <time.h>
      5 #include <stdarg.h>
      6 #include <rfb/rfb.h>
      7 #include <rfb/rfbclient.h>
      8 
      9 #ifndef LIBVNCSERVER_HAVE_LIBPTHREAD
     10 #error This test need pthread support (otherwise the client blocks the client)
     11 #endif
     12 
     13 #define ALL_AT_ONCE
     14 /*#define VERY_VERBOSE*/
     15 
     16 static MUTEX(frameBufferMutex);
     17 
     18 typedef struct { int id; char* str; } encoding_t;
     19 static encoding_t testEncodings[]={
     20         { rfbEncodingRaw, "raw" },
     21 	{ rfbEncodingRRE, "rre" },
     22 	{ rfbEncodingCoRRE, "corre" },
     23 	{ rfbEncodingHextile, "hextile" },
     24 	{ rfbEncodingUltra, "ultra" },
     25 #ifdef LIBVNCSERVER_HAVE_LIBZ
     26 	{ rfbEncodingZlib, "zlib" },
     27 	{ rfbEncodingZlibHex, "zlibhex" },
     28 	{ rfbEncodingZRLE, "zrle" },
     29 	{ rfbEncodingZYWRLE, "zywrle" },
     30 #ifdef LIBVNCSERVER_HAVE_LIBJPEG
     31 	{ rfbEncodingTight, "tight" },
     32 #endif
     33 #endif
     34 	{ 0, NULL }
     35 };
     36 
     37 #define NUMBER_OF_ENCODINGS_TO_TEST (sizeof(testEncodings)/sizeof(encoding_t)-1)
     38 /*#define NUMBER_OF_ENCODINGS_TO_TEST 1*/
     39 
     40 /* Here come the variables/functions to handle the test output */
     41 
     42 static const int width=400,height=300;
     43 static unsigned int statistics[2][NUMBER_OF_ENCODINGS_TO_TEST];
     44 static unsigned int totalFailed,totalCount;
     45 static unsigned int countGotUpdate;
     46 static MUTEX(statisticsMutex);
     47 
     48 static void initStatistics(void) {
     49 	memset(statistics[0],0,sizeof(int)*NUMBER_OF_ENCODINGS_TO_TEST);
     50 	memset(statistics[1],0,sizeof(int)*NUMBER_OF_ENCODINGS_TO_TEST);
     51 	totalFailed=totalCount=0;
     52 	INIT_MUTEX(statisticsMutex);
     53 }
     54 
     55 
     56 static void updateStatistics(int encodingIndex,rfbBool failed) {
     57 	LOCK(statisticsMutex);
     58 	if(failed) {
     59 		statistics[1][encodingIndex]++;
     60 		totalFailed++;
     61 	}
     62 	statistics[0][encodingIndex]++;
     63 	totalCount++;
     64 	countGotUpdate++;
     65 	UNLOCK(statisticsMutex);
     66 }
     67 
     68 /* Here begin the functions for the client. They will be called in a
     69  * pthread. */
     70 
     71 /* maxDelta=0 means they are expected to match exactly;
     72  * maxDelta>0 means that the average difference must be lower than maxDelta */
     73 static rfbBool doFramebuffersMatch(rfbScreenInfo* server,rfbClient* client,
     74 		int maxDelta)
     75 {
     76 	int i,j,k;
     77 	unsigned int total=0,diff=0;
     78 	if(server->width!=client->width || server->height!=client->height)
     79 		return FALSE;
     80 	LOCK(frameBufferMutex);
     81 	/* TODO: write unit test for colour transformation, use here, too */
     82 	for(i=0;i<server->width;i++)
     83 		for(j=0;j<server->height;j++)
     84 			for(k=0;k<3/*server->serverFormat.bitsPerPixel/8*/;k++) {
     85 				unsigned char s=server->frameBuffer[k+i*4+j*server->paddedWidthInBytes];
     86 				unsigned char cl=client->frameBuffer[k+i*4+j*client->width*4];
     87 
     88 				if(maxDelta==0 && s!=cl) {
     89 					UNLOCK(frameBufferMutex);
     90 					return FALSE;
     91 				} else {
     92 					total++;
     93 					diff+=(s>cl?s-cl:cl-s);
     94 				}
     95 			}
     96 	UNLOCK(frameBufferMutex);
     97 	if(maxDelta>0 && diff/total>=maxDelta)
     98 		return FALSE;
     99 	return TRUE;
    100 }
    101 
    102 static rfbBool resize(rfbClient* cl) {
    103 	if(cl->frameBuffer)
    104 		free(cl->frameBuffer);
    105 	cl->frameBuffer=malloc(cl->width*cl->height*cl->format.bitsPerPixel/8);
    106 	if(!cl->frameBuffer)
    107 		return FALSE;
    108 	SendFramebufferUpdateRequest(cl,0,0,cl->width,cl->height,FALSE);
    109 	return TRUE;
    110 }
    111 
    112 typedef struct clientData {
    113 	int encodingIndex;
    114 	rfbScreenInfo* server;
    115 	char* display;
    116 } clientData;
    117 
    118 static void update(rfbClient* client,int x,int y,int w,int h) {
    119 #ifndef VERY_VERBOSE
    120 
    121 	static const char* progress="|/-\\";
    122 	static int counter=0;
    123 
    124 	if(++counter>sizeof(progress)) counter=0;
    125 	fprintf(stderr,"%c\r",progress[counter]);
    126 #else
    127 	clientData* cd=(clientData*)client->clientData;
    128 	rfbClientLog("Got update (encoding=%s): (%d,%d)-(%d,%d)\n",
    129 			testEncodings[cd->encodingIndex].str,
    130 			x,y,x+w,y+h);
    131 #endif
    132 }
    133 
    134 static void update_finished(rfbClient* client) {
    135 	clientData* cd=(clientData*)client->clientData;
    136         int maxDelta=0;
    137 
    138 #ifdef LIBVNCSERVER_HAVE_LIBZ
    139 	if(testEncodings[cd->encodingIndex].id==rfbEncodingZYWRLE)
    140 		maxDelta=5;
    141 #ifdef LIBVNCSERVER_HAVE_LIBJPEG
    142 	if(testEncodings[cd->encodingIndex].id==rfbEncodingTight)
    143 		maxDelta=5;
    144 #endif
    145 #endif
    146 	updateStatistics(cd->encodingIndex,
    147 			!doFramebuffersMatch(cd->server,client,maxDelta));
    148 }
    149 
    150 
    151 static void* clientLoop(void* data) {
    152 	rfbClient* client=(rfbClient*)data;
    153 	clientData* cd=(clientData*)client->clientData;
    154 
    155 	client->appData.encodingsString=strdup(testEncodings[cd->encodingIndex].str);
    156 	client->appData.qualityLevel = 7; /* ZYWRLE fails the test with standard settings */
    157 
    158 	sleep(1);
    159 	rfbClientLog("Starting client (encoding %s, display %s)\n",
    160 			testEncodings[cd->encodingIndex].str,
    161 			cd->display);
    162 	if(!rfbInitClient(client,NULL,NULL)) {
    163 		rfbClientErr("Had problems starting client (encoding %s)\n",
    164 				testEncodings[cd->encodingIndex].str);
    165 		updateStatistics(cd->encodingIndex,TRUE);
    166 		return NULL;
    167 	}
    168 	while(1) {
    169 		if(WaitForMessage(client,50)>=0)
    170 			if(!HandleRFBServerMessage(client))
    171 				break;
    172 	}
    173 	free(((clientData*)client->clientData)->display);
    174 	free(client->clientData);
    175 	client->clientData = NULL;
    176 	if(client->frameBuffer)
    177 		free(client->frameBuffer);
    178 	rfbClientCleanup(client);
    179 	return NULL;
    180 }
    181 
    182 static pthread_t all_threads[NUMBER_OF_ENCODINGS_TO_TEST];
    183 static int thread_counter;
    184 
    185 static void startClient(int encodingIndex,rfbScreenInfo* server) {
    186 	rfbClient* client=rfbGetClient(8,3,4);
    187 	clientData* cd;
    188 
    189 	client->clientData=malloc(sizeof(clientData));
    190 	client->MallocFrameBuffer=resize;
    191 	client->GotFrameBufferUpdate=update;
    192 	client->FinishedFrameBufferUpdate=update_finished;
    193 
    194 	cd=(clientData*)client->clientData;
    195 	cd->encodingIndex=encodingIndex;
    196 	cd->server=server;
    197 	cd->display=(char*)malloc(6);
    198 	sprintf(cd->display,":%d",server->port-5900);
    199 
    200 	pthread_create(&all_threads[thread_counter++],NULL,clientLoop,(void*)client);
    201 }
    202 
    203 /* Here begin the server functions */
    204 
    205 static void idle(rfbScreenInfo* server)
    206 {
    207 	int c;
    208 	rfbBool goForward;
    209 
    210 	LOCK(statisticsMutex);
    211 #ifdef ALL_AT_ONCE
    212 	goForward=(countGotUpdate==NUMBER_OF_ENCODINGS_TO_TEST);
    213 #else
    214 	goForward=(countGotUpdate==1);
    215 #endif
    216 
    217 	UNLOCK(statisticsMutex);
    218 	if(!goForward)
    219 	  return;
    220 	countGotUpdate=0;
    221 
    222 	LOCK(frameBufferMutex);
    223 	{
    224 		int i,j;
    225 		int x1=(rand()%(server->width-1)),x2=(rand()%(server->width-1)),
    226 		y1=(rand()%(server->height-1)),y2=(rand()%(server->height-1));
    227 		if(x1>x2) { i=x1; x1=x2; x2=i; }
    228 		if(y1>y2) { i=y1; y1=y2; y2=i; }
    229 		x2++; y2++;
    230 		for(c=0;c<3;c++) {
    231 			for(i=x1;i<x2;i++)
    232 				for(j=y1;j<y2;j++)
    233 					server->frameBuffer[i*4+c+j*server->paddedWidthInBytes]=255*(i-x1+j-y1)/(x2-x1+y2-y1);
    234 		}
    235 		rfbMarkRectAsModified(server,x1,y1,x2,y2);
    236 
    237 #ifdef VERY_VERBOSE
    238 		rfbLog("Sent update (%d,%d)-(%d,%d)\n",x1,y1,x2,y2);
    239 #endif
    240 	}
    241 	UNLOCK(frameBufferMutex);
    242 }
    243 
    244 /* log function (to show what messages are from the client) */
    245 
    246 static void
    247 rfbTestLog(const char *format, ...)
    248 {
    249 	va_list args;
    250 	char buf[256];
    251 	time_t log_clock;
    252 
    253 	if(!rfbEnableClientLogging)
    254 		return;
    255 
    256 	va_start(args, format);
    257 
    258 	time(&log_clock);
    259 	strftime(buf, 255, "%d/%m/%Y %X (client) ", localtime(&log_clock));
    260 	fprintf(stderr,"%s",buf);
    261 
    262 	vfprintf(stderr, format, args);
    263 	fflush(stderr);
    264 
    265 	va_end(args);
    266 }
    267 
    268 /* the main function */
    269 
    270 int main(int argc,char** argv)
    271 {
    272 	int i,j;
    273 	time_t t;
    274 	rfbScreenInfoPtr server;
    275 
    276 	rfbClientLog=rfbTestLog;
    277 	rfbClientErr=rfbTestLog;
    278 
    279 	/* Initialize server */
    280 	server=rfbGetScreen(&argc,argv,width,height,8,3,4);
    281         if(!server)
    282           return 0;
    283 
    284 	server->frameBuffer=malloc(400*300*4);
    285 	server->cursor=NULL;
    286 	for(j=0;j<400*300*4;j++)
    287 		server->frameBuffer[j]=j;
    288 	rfbInitServer(server);
    289 	rfbProcessEvents(server,0);
    290 
    291 	initStatistics();
    292 
    293 #ifndef ALL_AT_ONCE
    294 	for(i=0;i<NUMBER_OF_ENCODINGS_TO_TEST;i++) {
    295 #else
    296 	/* Initialize clients */
    297 	for(i=0;i<NUMBER_OF_ENCODINGS_TO_TEST;i++)
    298 #endif
    299 		startClient(i,server);
    300 
    301 	t=time(NULL);
    302 	/* test 20 seconds */
    303 	while(time(NULL)-t<20) {
    304 
    305 		idle(server);
    306 
    307 		rfbProcessEvents(server,1);
    308 	}
    309 	rfbLog("%d failed, %d received\n",totalFailed,totalCount);
    310 #ifndef ALL_AT_ONCE
    311 	{
    312 		rfbClientPtr cl;
    313 		rfbClientIteratorPtr iter=rfbGetClientIterator(server);
    314 		while((cl=rfbClientIteratorNext(iter)))
    315 			rfbCloseClient(cl);
    316 		rfbReleaseClientIterator(iter);
    317 	}
    318 	}
    319 #endif
    320 
    321 	/* shut down server, disconnecting all clients */
    322 	rfbShutdownServer(server, TRUE);
    323 
    324 	for(i=0;i<thread_counter;i++)
    325 		pthread_join(all_threads[i], NULL);
    326 
    327 	free(server->frameBuffer);
    328 	rfbScreenCleanup(server);
    329 
    330 	rfbLog("Statistics:\n");
    331 	for(i=0;i<NUMBER_OF_ENCODINGS_TO_TEST;i++)
    332 		rfbLog("%s encoding: %d failed, %d received\n",
    333 				testEncodings[i].str,statistics[1][i],statistics[0][i]);
    334 	if(totalFailed)
    335 		return 1;
    336 	return(0);
    337 }
    338 
    339 
    340