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