• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
initStatistics(void)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 
updateStatistics(int encodingIndex,rfbBool failed)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 */
doFramebuffersMatch(rfbScreenInfo * server,rfbClient * client,int 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 
resize(rfbClient * cl)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 
update(rfbClient * client,int x,int y,int w,int h)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 
update_finished(rfbClient * client)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 
clientLoop(void * data)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 	if(client->frameBuffer)
176 		free(client->frameBuffer);
177 	rfbClientCleanup(client);
178 	return NULL;
179 }
180 
181 static pthread_t all_threads[NUMBER_OF_ENCODINGS_TO_TEST];
182 static int thread_counter;
183 
startClient(int encodingIndex,rfbScreenInfo * server)184 static void startClient(int encodingIndex,rfbScreenInfo* server) {
185 	rfbClient* client=rfbGetClient(8,3,4);
186 	clientData* cd;
187 
188 	client->clientData=malloc(sizeof(clientData));
189 	client->MallocFrameBuffer=resize;
190 	client->GotFrameBufferUpdate=update;
191 	client->FinishedFrameBufferUpdate=update_finished;
192 
193 	cd=(clientData*)client->clientData;
194 	cd->encodingIndex=encodingIndex;
195 	cd->server=server;
196 	cd->display=(char*)malloc(6);
197 	sprintf(cd->display,":%d",server->port-5900);
198 
199 	pthread_create(&all_threads[thread_counter++],NULL,clientLoop,(void*)client);
200 }
201 
202 /* Here begin the server functions */
203 
idle(rfbScreenInfo * server)204 static void idle(rfbScreenInfo* server)
205 {
206 	int c;
207 	rfbBool goForward;
208 
209 	LOCK(statisticsMutex);
210 #ifdef ALL_AT_ONCE
211 	goForward=(countGotUpdate==NUMBER_OF_ENCODINGS_TO_TEST);
212 #else
213 	goForward=(countGotUpdate==1);
214 #endif
215 
216 	UNLOCK(statisticsMutex);
217 	if(!goForward)
218 	  return;
219 	countGotUpdate=0;
220 
221 	LOCK(frameBufferMutex);
222 	{
223 		int i,j;
224 		int x1=(rand()%(server->width-1)),x2=(rand()%(server->width-1)),
225 		y1=(rand()%(server->height-1)),y2=(rand()%(server->height-1));
226 		if(x1>x2) { i=x1; x1=x2; x2=i; }
227 		if(y1>y2) { i=y1; y1=y2; y2=i; }
228 		x2++; y2++;
229 		for(c=0;c<3;c++) {
230 			for(i=x1;i<x2;i++)
231 				for(j=y1;j<y2;j++)
232 					server->frameBuffer[i*4+c+j*server->paddedWidthInBytes]=255*(i-x1+j-y1)/(x2-x1+y2-y1);
233 		}
234 		rfbMarkRectAsModified(server,x1,y1,x2,y2);
235 
236 #ifdef VERY_VERBOSE
237 		rfbLog("Sent update (%d,%d)-(%d,%d)\n",x1,y1,x2,y2);
238 #endif
239 	}
240 	UNLOCK(frameBufferMutex);
241 }
242 
243 /* log function (to show what messages are from the client) */
244 
245 static void
rfbTestLog(const char * format,...)246 rfbTestLog(const char *format, ...)
247 {
248 	va_list args;
249 	char buf[256];
250 	time_t log_clock;
251 
252 	if(!rfbEnableClientLogging)
253 		return;
254 
255 	va_start(args, format);
256 
257 	time(&log_clock);
258 	strftime(buf, 255, "%d/%m/%Y %X (client) ", localtime(&log_clock));
259 	fprintf(stderr,buf);
260 
261 	vfprintf(stderr, format, args);
262 	fflush(stderr);
263 
264 	va_end(args);
265 }
266 
267 /* the main function */
268 
main(int argc,char ** argv)269 int main(int argc,char** argv)
270 {
271 	int i,j;
272 	time_t t;
273 	rfbScreenInfoPtr server;
274 
275 	rfbClientLog=rfbTestLog;
276 	rfbClientErr=rfbTestLog;
277 
278 	/* Initialize server */
279 	server=rfbGetScreen(&argc,argv,width,height,8,3,4);
280         if(!server)
281           return 0;
282 
283 	server->frameBuffer=malloc(400*300*4);
284 	server->cursor=NULL;
285 	for(j=0;j<400*300*4;j++)
286 		server->frameBuffer[j]=j;
287 	rfbInitServer(server);
288 	rfbProcessEvents(server,0);
289 
290 	initStatistics();
291 
292 #ifndef ALL_AT_ONCE
293 	for(i=0;i<NUMBER_OF_ENCODINGS_TO_TEST;i++) {
294 #else
295 	/* Initialize clients */
296 	for(i=0;i<NUMBER_OF_ENCODINGS_TO_TEST;i++)
297 #endif
298 		startClient(i,server);
299 
300 	t=time(NULL);
301 	/* test 20 seconds */
302 	while(time(NULL)-t<20) {
303 
304 		idle(server);
305 
306 		rfbProcessEvents(server,1);
307 	}
308 	rfbLog("%d failed, %d received\n",totalFailed,totalCount);
309 #ifndef ALL_AT_ONCE
310 	{
311 		rfbClientPtr cl;
312 		rfbClientIteratorPtr iter=rfbGetClientIterator(server);
313 		while((cl=rfbClientIteratorNext(iter)))
314 			rfbCloseClient(cl);
315 		rfbReleaseClientIterator(iter);
316 	}
317 	}
318 #endif
319 
320 	/* shut down server, disconnecting all clients */
321 	rfbShutdownServer(server, TRUE);
322 
323 	for(i=0;i<thread_counter;i++)
324 		pthread_join(all_threads[i], NULL);
325 
326 	free(server->frameBuffer);
327 	rfbScreenCleanup(server);
328 
329 	rfbLog("Statistics:\n");
330 	for(i=0;i<NUMBER_OF_ENCODINGS_TO_TEST;i++)
331 		rfbLog("%s encoding: %d failed, %d received\n",
332 				testEncodings[i].str,statistics[1][i],statistics[0][i]);
333 	if(totalFailed)
334 		return 1;
335 	return(0);
336 }
337 
338 
339