7 #include <rfb/rfbclient.h>
9 #ifndef LIBVNCSERVER_HAVE_LIBPTHREAD
10 #error This test need pthread support (otherwise the client blocks the client)
14 /*#define VERY_VERBOSE*/
16 static MUTEX(frameBufferMutex
);
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" },
37 #define NUMBER_OF_ENCODINGS_TO_TEST (sizeof(testEncodings)/sizeof(encoding_t)-1)
38 /*#define NUMBER_OF_ENCODINGS_TO_TEST 1*/
40 /* Here come the variables/functions to handle the test output */
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
);
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
);
56 static void updateStatistics(int encodingIndex
,rfbBool failed
) {
57 LOCK(statisticsMutex
);
59 statistics
[1][encodingIndex
]++;
62 statistics
[0][encodingIndex
]++;
65 UNLOCK(statisticsMutex
);
68 /* Here begin the functions for the client. They will be called in a
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
,
77 unsigned int total
=0,diff
=0;
78 if(server
->width
!=client
->width
|| server
->height
!=client
->height
)
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];
88 if(maxDelta
==0 && s
!=cl
) {
89 UNLOCK(frameBufferMutex
);
93 diff
+=(s
>cl
?s
-cl
:cl
-s
);
96 UNLOCK(frameBufferMutex
);
97 if(maxDelta
>0 && diff
/total
>=maxDelta
)
102 static rfbBool
resize(rfbClient
* cl
) {
104 free(cl
->frameBuffer
);
105 cl
->frameBuffer
=malloc(cl
->width
*cl
->height
*cl
->format
.bitsPerPixel
/8);
108 SendFramebufferUpdateRequest(cl
,0,0,cl
->width
,cl
->height
,FALSE
);
112 typedef struct clientData
{
114 rfbScreenInfo
* server
;
118 static void update(rfbClient
* client
,int x
,int y
,int w
,int h
) {
121 static const char* progress
="|/-\\";
122 static int counter
=0;
124 if(++counter
>sizeof(progress
)) counter
=0;
125 fprintf(stderr
,"%c\r",progress
[counter
]);
127 clientData
* cd
=(clientData
*)client
->clientData
;
128 rfbClientLog("Got update (encoding=%s): (%d,%d)-(%d,%d)\n",
129 testEncodings
[cd
->encodingIndex
].str
,
134 static void update_finished(rfbClient
* client
) {
135 clientData
* cd
=(clientData
*)client
->clientData
;
138 #ifdef LIBVNCSERVER_HAVE_LIBZ
139 if(testEncodings
[cd
->encodingIndex
].id
==rfbEncodingZYWRLE
)
141 #ifdef LIBVNCSERVER_HAVE_LIBJPEG
142 if(testEncodings
[cd
->encodingIndex
].id
==rfbEncodingTight
)
146 updateStatistics(cd
->encodingIndex
,
147 !doFramebuffersMatch(cd
->server
,client
,maxDelta
));
151 static void* clientLoop(void* data
) {
152 rfbClient
* client
=(rfbClient
*)data
;
153 clientData
* cd
=(clientData
*)client
->clientData
;
155 client
->appData
.encodingsString
=strdup(testEncodings
[cd
->encodingIndex
].str
);
156 client
->appData
.qualityLevel
= 7; /* ZYWRLE fails the test with standard settings */
159 rfbClientLog("Starting client (encoding %s, display %s)\n",
160 testEncodings
[cd
->encodingIndex
].str
,
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
);
169 if(WaitForMessage(client
,50)>=0)
170 if(!HandleRFBServerMessage(client
))
173 free(((clientData
*)client
->clientData
)->display
);
174 free(client
->clientData
);
175 if(client
->frameBuffer
)
176 free(client
->frameBuffer
);
177 rfbClientCleanup(client
);
181 static pthread_t all_threads
[NUMBER_OF_ENCODINGS_TO_TEST
];
182 static int thread_counter
;
184 static void startClient(int encodingIndex
,rfbScreenInfo
* server
) {
185 rfbClient
* client
=rfbGetClient(8,3,4);
188 client
->clientData
=malloc(sizeof(clientData
));
189 client
->MallocFrameBuffer
=resize
;
190 client
->GotFrameBufferUpdate
=update
;
191 client
->FinishedFrameBufferUpdate
=update_finished
;
193 cd
=(clientData
*)client
->clientData
;
194 cd
->encodingIndex
=encodingIndex
;
196 cd
->display
=(char*)malloc(6);
197 sprintf(cd
->display
,":%d",server
->port
-5900);
199 pthread_create(&all_threads
[thread_counter
++],NULL
,clientLoop
,(void*)client
);
202 /* Here begin the server functions */
204 static void idle(rfbScreenInfo
* server
)
209 LOCK(statisticsMutex
);
211 goForward
=(countGotUpdate
==NUMBER_OF_ENCODINGS_TO_TEST
);
213 goForward
=(countGotUpdate
==1);
216 UNLOCK(statisticsMutex
);
221 LOCK(frameBufferMutex
);
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
; }
232 server
->frameBuffer
[i
*4+c
+j
*server
->paddedWidthInBytes
]=255*(i
-x1
+j
-y1
)/(x2
-x1
+y2
-y1
);
234 rfbMarkRectAsModified(server
,x1
,y1
,x2
,y2
);
237 rfbLog("Sent update (%d,%d)-(%d,%d)\n",x1
,y1
,x2
,y2
);
240 UNLOCK(frameBufferMutex
);
243 /* log function (to show what messages are from the client) */
246 rfbTestLog(const char *format
, ...)
252 if(!rfbEnableClientLogging
)
255 va_start(args
, format
);
258 strftime(buf
, 255, "%d/%m/%Y %X (client) ", localtime(&log_clock
));
259 fprintf(stderr
,"%s",buf
);
261 vfprintf(stderr
, format
, args
);
267 /* the main function */
269 int main(int argc
,char** argv
)
273 rfbScreenInfoPtr server
;
275 rfbClientLog
=rfbTestLog
;
276 rfbClientErr
=rfbTestLog
;
278 /* Initialize server */
279 server
=rfbGetScreen(&argc
,argv
,width
,height
,8,3,4);
283 server
->frameBuffer
=malloc(400*300*4);
285 for(j
=0;j
<400*300*4;j
++)
286 server
->frameBuffer
[j
]=j
;
287 rfbInitServer(server
);
288 rfbProcessEvents(server
,0);
293 for(i
=0;i
<NUMBER_OF_ENCODINGS_TO_TEST
;i
++) {
295 /* Initialize clients */
296 for(i
=0;i
<NUMBER_OF_ENCODINGS_TO_TEST
;i
++)
298 startClient(i
,server
);
301 /* test 20 seconds */
302 while(time(NULL
)-t
<20) {
306 rfbProcessEvents(server
,1);
308 rfbLog("%d failed, %d received\n",totalFailed
,totalCount
);
312 rfbClientIteratorPtr iter
=rfbGetClientIterator(server
);
313 while((cl
=rfbClientIteratorNext(iter
)))
315 rfbReleaseClientIterator(iter
);
320 /* shut down server, disconnecting all clients */
321 rfbShutdownServer(server
, TRUE
);
323 for(i
=0;i
<thread_counter
;i
++)
324 pthread_join(all_threads
[i
], NULL
);
326 free(server
->frameBuffer
);
327 rfbScreenCleanup(server
);
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
]);