Create FUNDING.yml
[wdl/wdl-ol.git] / WDL / rfb_client.cpp
blob910a88d70e1e184dcfa4833c3e3502528df80647
1 #include "rfb_client.h"
2 #include "lice/lice.h"
4 #include "des.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)
22 m_skipdata=0;
23 m_req_x=m_req_y=m_req_w=m_req_h=m_needref=0;
24 m_errstr=0;
25 m_state=InitialState;
26 m_con=con;
27 m_password.Set(password?password:"");
28 m_screen_w=m_screen_h=0;
29 m_remote_ver=0;
30 instance_data=0;
31 DrawRectangleCallback=0;
32 time(&m_lastt);
35 WDL_RFB_Client::~WDL_RFB_Client()
37 delete m_con;
41 unsigned int WDL_RFB_Client::GetBE(int nb, int queueoffs, bool advance)
43 unsigned char *buf=m_msg_buf.Get()+queueoffs;
45 unsigned int a=0;
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);
53 return a;
56 int WDL_RFB_Client::Run()
58 if (!m_con||m_state == ErrorState) return -1;
60 int cnt=0;
62 while (m_state != ErrorState)
64 int bytes_needed=1;
65 int old_avail = m_msg_buf.Available();
67 switch (m_state)
69 case InitialState:
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')
76 m_state=ErrorState;
77 m_errstr = "Server gave invalid line";
79 else
81 buf[7]=0;
82 buf[11]=0;
83 m_remote_ver = atoi((char*)buf+4)*1000 + atoi((char*)buf+8);
84 if (m_remote_ver < 3000 || m_remote_ver >= 4000)
86 m_state=ErrorState;
87 m_errstr = "Server gave invalid version";
89 else
91 m_con->send_bytes(OUR_VERSION_STRING,strlen(OUR_VERSION_STRING));
92 m_state = AuthWaitState;
95 m_msg_buf.Advance(12);
97 else bytes_needed=12;
98 break;
99 case AuthWaitState:
100 if (m_msg_buf.Available()>=4)
102 unsigned int type = GetBE(4,0,false);
103 if (type==0)
105 m_state=ErrorState;
106 m_errstr = "Server permission denied";
108 else if (type==1)
110 m_state=ServerInitState;
111 m_msg_buf.Advance(4);
113 char c=1; // allow sharing
114 m_con->send_bytes(&c,1);
116 else if (type == 2)
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));
128 WDL_DES des;
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;
137 else
139 m_state=ErrorState;
140 m_errstr = "Unknown authentication method";
143 else bytes_needed=4;
144 break;
145 case AuthWaitState2:
146 if (m_msg_buf.Available()>=4)
148 unsigned int type = GetBE();
149 if (type==0)
151 m_state=ServerInitState;
153 char c=1; // allow sharing
154 m_con->send_bytes(&c,1);
156 else
158 m_state=ErrorState;
159 m_errstr = type==1 ? "Auth failed" : type==2 ? "Too many connections" : "Auth failed (unknown reason)";
162 else bytes_needed=4;
163 break;
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
185 // 3 bytes padding
186 buf[4] = 32;
187 buf[5] = 24;
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;
199 // 3 bytes padding
201 m_con->send_bytes(buf,sizeof(buf));
203 // request encodings
205 const int encs[]={
206 #ifdef WANT_RRE
207 ENCODE_TYPE_RRE,
208 #endif
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;
215 buf[3] = nencs&0xff;
216 int x;
217 for(x=0;x<nencs;x++)
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));
227 m_state=RunState;
228 m_needref=2;
230 else bytes_needed=2+2+16+4+nl;
232 else bytes_needed=2+2+16+4;
234 break;
235 case RunState:
237 if (m_needref)
239 unsigned char buf[10]={0,};
240 buf[0]=3;
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;
249 else
251 buf[2]=(m_req_x>>8)&0xff;
252 buf[3]=m_req_x&0xff;
253 buf[4]=(m_req_x>>8)&0xff;
254 buf[5]=m_req_x&0xff;
255 buf[6]=(m_req_w>>8)&0xff;
256 buf[7]=m_req_w&0xff;
257 buf[8]=(m_req_h>>8)&0xff;
258 buf[9]=m_req_h&0xff;
260 m_needref=0;
261 m_con->send_bytes(buf,sizeof(buf));
264 if (m_skipdata>0)
266 int a= wdl_min(m_msg_buf.Available(),m_skipdata);
267 m_msg_buf.Advance(a);
268 m_skipdata-=a;
271 if (m_msg_buf.Available()>0)
273 m_skipdata=0;
274 unsigned char msg = *(unsigned char *)m_msg_buf.Get();
275 switch (msg)
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];
284 if (m_msg_state>0)
286 m_state=RunState_GettingRects;
289 else bytes_needed=4;
290 break;
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
296 break;
297 case 2: // bell, skip
298 m_msg_buf.Advance(1);
299 break;
300 case 3: // copy text, skip
301 if (m_msg_buf.Available()>=8)
303 m_skipdata=GetBE(4,4); // skip 4 bytes, read 4
305 break;
306 default:
307 m_state=ErrorState;
308 sprintf(tmperrbuf,"Got unknown message: %d",msg);
309 m_errstr=tmperrbuf;
310 break;
313 break;
314 case RunState_GettingRects:
315 if (m_msg_state>0)
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);
325 switch (enc)
327 case ENCODE_TYPE_SCREENSIZE:
329 if (w>m_screen_w || h>m_screen_h) m_needref=2;
330 m_screen_w = w;
331 m_screen_h = h;
332 m_msg_buf.Advance(12);
334 break;
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)
344 m_bm.resize(w,h);
345 LICE_FillRect(&m_bm,0,0,w,h,bgc,1.0f,LICE_BLIT_MODE_COPY);
347 while (nr-->0)
349 bgc=GetBE();
350 int lx=GetBE(2);
351 int ly=GetBE(2);
352 int lw=GetBE(2);
353 int lh=GetBE(2);
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);
361 --m_msg_state;
363 else bytes_needed = 12+8 + nr*12;
365 else bytes_needed=12+8;
366 break;
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);
373 m_bm.resize(w,h);
374 LICE_pixel *out = m_bm.getBits();
375 int rs = m_bm.getRowSpan();
376 int a;
377 for (a=0;a<h;a++)
379 memcpy(out,src,w*sizeof(LICE_pixel));
380 src+=w;
381 out+=rs;
385 DrawRectangleCallback(this,&m_bm,xpos,ypos,w,h);
388 m_msg_buf.Advance(12 + w*h*4);
389 --m_msg_state;
391 else bytes_needed=12+w*h*4;
392 break;
393 default:
394 m_state=ErrorState;
395 sprintf(tmperrbuf,"Got unknown encoding: %d",enc);
396 m_errstr=tmperrbuf;
397 break;
400 else bytes_needed=12;
403 if (m_msg_state<=0)
405 m_state = RunState;
406 if (DrawRectangleCallback) DrawRectangleCallback(this,NULL,0,0,0,0);
408 break;
411 if (old_avail != m_msg_buf.Available()) cnt=1;
413 m_con->run();
415 while (m_msg_buf.Available()<m_skipdata+bytes_needed)
417 int a = m_con->recv_bytes_available();
418 if (a>0)
420 m_con->recv_bytes(m_msg_buf.Add(NULL,a),a);
421 time(&m_lastt);
423 else break;
425 m_con->run();
428 if (old_avail == m_msg_buf.Available()||
429 m_msg_buf.Available()<m_skipdata+bytes_needed) break;
432 m_msg_buf.Compact();
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)
437 m_state=ErrorState;
438 m_errstr = "Timed out";
441 return cnt>0;