1 #include "rfb_client.h"
6 #define CONNECTION_TIMEOUT 30
7 #define NORMAL_TIMEOUT 30
8 #define OUR_VERSION_STRING "RFB 003.000\n"
11 //#define WANT_RRE // seems to be broken on many servers
13 #define ENCODE_TYPE_RAW 0
14 #define ENCODE_TYPE_SCREENSIZE -223
15 #define ENCODE_TYPE_RRE 2
16 //#define ENCODE_TYPE_CORRE 3
17 //#define ENCODE_TYPE_HEXTILE 5
20 WDL_RFB_Client::WDL_RFB_Client(JNL_IConnection
*con
, const char *password
)
23 m_req_x
=m_req_y
=m_req_w
=m_req_h
=m_needref
=0;
27 m_password
.Set(password
?password
:"");
28 m_screen_w
=m_screen_h
=0;
31 DrawRectangleCallback
=0;
35 WDL_RFB_Client::~WDL_RFB_Client()
41 unsigned int WDL_RFB_Client::GetBE(int nb
, int queueoffs
, bool advance
)
43 unsigned char *buf
=m_msg_buf
.Get()+queueoffs
;
46 if (nb
==4) a
= (buf
[0]<<24) | (buf
[1]<<16) | (buf
[2]<<8) | buf
[3];
47 else if (nb
==3) a
=(buf
[0]<<16) | (buf
[1]<<8) | buf
[2];
48 else if (nb
==2) a
=(buf
[0]<<8) | (buf
[1]);
49 else if (nb
==1) a
=(buf
[0]);
51 if (advance
) m_msg_buf
.Advance(queueoffs
+nb
);
56 int WDL_RFB_Client::Run()
58 if (!m_con
||m_state
== ErrorState
) return -1;
62 while (m_state
!= ErrorState
)
65 int old_avail
= m_msg_buf
.Available();
70 if (m_msg_buf
.Available()>=12)
72 unsigned char *buf
= m_msg_buf
.Get();
74 if (memcmp(buf
,"RFB ",4) || buf
[7] != '.'||buf
[11] != '\n')
77 m_errstr
= "Server gave invalid line";
83 m_remote_ver
= atoi((char*)buf
+4)*1000 + atoi((char*)buf
+8);
84 if (m_remote_ver
< 3000 || m_remote_ver
>= 4000)
87 m_errstr
= "Server gave invalid version";
91 m_con
->send_bytes(OUR_VERSION_STRING
,strlen(OUR_VERSION_STRING
));
92 m_state
= AuthWaitState
;
95 m_msg_buf
.Advance(12);
100 if (m_msg_buf
.Available()>=4)
102 unsigned int type
= GetBE(4,0,false);
106 m_errstr
= "Server permission denied";
110 m_state
=ServerInitState
;
111 m_msg_buf
.Advance(4);
113 char c
=1; // allow sharing
114 m_con
->send_bytes(&c
,1);
118 if (m_msg_buf
.Available() >= 4+16)
120 m_msg_buf
.Advance(4);
121 unsigned char challenge
[16];
122 memcpy(challenge
,m_msg_buf
.Get(),16);
123 m_msg_buf
.Advance(16);
125 unsigned char buf
[8];
126 memset(buf
,0,sizeof(buf
));
127 memcpy(buf
,m_password
.Get(),wdl_min(strlen(m_password
.Get()),8));
129 des
.SetKey(buf
,true);
130 des
.Process8(challenge
);
131 des
.Process8(challenge
+8);
132 m_con
->send_bytes(challenge
,16);
133 m_state
=AuthWaitState2
;
135 else bytes_needed
=4+16;
140 m_errstr
= "Unknown authentication method";
146 if (m_msg_buf
.Available()>=4)
148 unsigned int type
= GetBE();
151 m_state
=ServerInitState
;
153 char c
=1; // allow sharing
154 m_con
->send_bytes(&c
,1);
159 m_errstr
= type
==1 ? "Auth failed" : type
==2 ? "Too many connections" : "Auth failed (unknown reason)";
164 case ServerInitState
:
166 if (m_msg_buf
.Available()>=2+2+16+4)
168 unsigned int nl
= GetBE(4,2+2+16,false);
169 if (m_msg_buf
.Available()>=2+2+16+4 + nl
)
171 m_screen_w
= GetBE(2);
172 m_screen_h
= GetBE(2);
174 m_msg_buf
.Advance(16+4); // skip color map and length
176 memcpy(m_namebuf
.Resize(nl
+1),m_msg_buf
.Get(),nl
);
177 m_msg_buf
.Advance(nl
);
178 m_namebuf
.Get()[nl
]=0;
180 // request our pixel format
183 unsigned char buf
[20]={0,};
184 buf
[0] = 0; // request pixel format
188 buf
[6] = 0; // always LE
189 buf
[7] = 1; // true-color
191 buf
[8] = 0; buf
[9]=255; // masks
192 buf
[10] = 0; buf
[11]=255;
193 buf
[12] = 0; buf
[13]=255;
195 buf
[14] = LICE_PIXEL_R
*8; // shifts
196 buf
[15] = LICE_PIXEL_G
*8;
197 buf
[16] = LICE_PIXEL_B
*8;
201 m_con
->send_bytes(buf
,sizeof(buf
));
209 ENCODE_TYPE_RAW
,ENCODE_TYPE_SCREENSIZE
,};
210 const int nencs
= sizeof(encs
)/sizeof(encs
[0]);
212 unsigned char buf
[4+nencs
*4]={0,};
213 buf
[0]=2; //encodings
214 buf
[2] = (nencs
>>8)&0xff;
219 buf
[4+x
*4] = (encs
[x
]>>24)&0xff;
220 buf
[4+x
*4+1] = (encs
[x
]>>16)&0xff;
221 buf
[4+x
*4+2] = (encs
[x
]>>8)&0xff;
222 buf
[4+x
*4+3] = (encs
[x
])&0xff;
224 m_con
->send_bytes(buf
,sizeof(buf
));
230 else bytes_needed
=2+2+16+4+nl
;
232 else bytes_needed
=2+2+16+4;
239 unsigned char buf
[10]={0,};
241 buf
[1]=(m_needref
& 2)?false:true;
242 if (!m_req_w
|| !m_req_h
)
244 buf
[6]=(m_screen_w
>>8)&0xff;
245 buf
[7]=m_screen_w
&0xff;
246 buf
[8]=(m_screen_h
>>8)&0xff;
247 buf
[9]=m_screen_h
&0xff;
251 buf
[2]=(m_req_x
>>8)&0xff;
253 buf
[4]=(m_req_x
>>8)&0xff;
255 buf
[6]=(m_req_w
>>8)&0xff;
257 buf
[8]=(m_req_h
>>8)&0xff;
261 m_con
->send_bytes(buf
,sizeof(buf
));
266 int a
= wdl_min(m_msg_buf
.Available(),m_skipdata
);
267 m_msg_buf
.Advance(a
);
271 if (m_msg_buf
.Available()>0)
274 unsigned char msg
= *(unsigned char *)m_msg_buf
.Get();
277 case 0: // framebuffer update
278 if (m_msg_buf
.Available() >= 4)
280 unsigned char *buf
=m_msg_buf
.Get();
281 m_msg_buf
.Advance(4);
283 m_msg_state
=(buf
[2]<<8)+buf
[3];
286 m_state
=RunState_GettingRects
;
291 case 1: // color map crap
292 if (m_msg_buf
.Available()>=6)
294 m_skipdata
= GetBE(2,4)*6; // skip 4 bytes, read 2, then skip that
297 case 2: // bell, skip
298 m_msg_buf
.Advance(1);
300 case 3: // copy text, skip
301 if (m_msg_buf
.Available()>=8)
303 m_skipdata
=GetBE(4,4); // skip 4 bytes, read 4
308 sprintf(tmperrbuf
,"Got unknown message: %d",msg
);
314 case RunState_GettingRects
:
317 if (m_msg_buf
.GetSize()>=12)
319 int xpos
= GetBE(2,0,false);
320 int ypos
= GetBE(2,2,false);
321 int w
=GetBE(2,4,false);
322 int h
=GetBE(2,6,false);
323 int enc
= GetBE(4,8,false);
327 case ENCODE_TYPE_SCREENSIZE
:
329 if (w
>m_screen_w
|| h
>m_screen_h
) m_needref
=2;
332 m_msg_buf
.Advance(12);
335 case ENCODE_TYPE_RRE
:
336 if (m_msg_buf
.GetSize()>=12+8)
338 unsigned int nr
= GetBE(4,12,false);
339 if (m_msg_buf
.GetSize()>=12+8 + nr
*12)
341 LICE_pixel bgc
= GetBE(4,12+4);
342 if (DrawRectangleCallback
)
345 LICE_FillRect(&m_bm
,0,0,w
,h
,bgc
,1.0f
,LICE_BLIT_MODE_COPY
);
354 LICE_FillRect(&m_bm
,lx
,ly
,lw
,lh
,bgc
,1.0f
,LICE_BLIT_MODE_COPY
);
357 DrawRectangleCallback(this,&m_bm
,xpos
,ypos
,w
,h
);
359 else m_msg_buf
.Advance(nr
*12);
363 else bytes_needed
= 12+8 + nr
*12;
365 else bytes_needed
=12+8;
367 case ENCODE_TYPE_RAW
: // raw
368 if (m_msg_buf
.GetSize()>=12+w
*h
*4) // we only support 32bpp for now
370 if (DrawRectangleCallback
)
372 LICE_pixel
*src
= (LICE_pixel
*)(m_msg_buf
.Get()+12);
374 LICE_pixel
*out
= m_bm
.getBits();
375 int rs
= m_bm
.getRowSpan();
379 memcpy(out
,src
,w
*sizeof(LICE_pixel
));
385 DrawRectangleCallback(this,&m_bm
,xpos
,ypos
,w
,h
);
388 m_msg_buf
.Advance(12 + w
*h
*4);
391 else bytes_needed
=12+w
*h
*4;
395 sprintf(tmperrbuf
,"Got unknown encoding: %d",enc
);
400 else bytes_needed
=12;
406 if (DrawRectangleCallback
) DrawRectangleCallback(this,NULL
,0,0,0,0);
411 if (old_avail
!= m_msg_buf
.Available()) cnt
=1;
415 while (m_msg_buf
.Available()<m_skipdata
+bytes_needed
)
417 int a
= m_con
->recv_bytes_available();
420 m_con
->recv_bytes(m_msg_buf
.Add(NULL
,a
),a
);
428 if (old_avail
== m_msg_buf
.Available()||
429 m_msg_buf
.Available()<m_skipdata
+bytes_needed
) break;
434 if (m_state
!= ErrorState
)
435 if (time(NULL
) > m_lastt
+(m_state
< RunState
? CONNECTION_TIMEOUT
: NORMAL_TIMEOUT
) || m_con
->get_state()==JNL_Connection::STATE_CLOSED
|| m_con
->get_state()==JNL_Connection::STATE_ERROR
)
438 m_errstr
= "Timed out";