static void rf_client_ptrevent(void) { CL_SLOT *cl = (CL_SLOT *)cur_slot; CARD16 x, y; CARD8 msg[6]; if (!cl->readonly) { msg[0] = 5; /* PointerEvent */ msg[1] = cur_slot->readbuf[0]; x = buf_get_CARD16(&cur_slot->readbuf[1]); y = buf_get_CARD16(&cur_slot->readbuf[3]); /* Pointer position should fit in the host screen */ if (x >= g_screen_info.width) x = g_screen_info.width - 1; if (y >= g_screen_info.height) y = g_screen_info.height - 1; buf_put_CARD16(&msg[2], x); buf_put_CARD16(&msg[4], y); pass_msg_to_host(msg, sizeof(msg)); } aio_setread(rf_client_msg, NULL, 1); }
void buf_put_pixfmt(void *buf, RFB_PIXEL_FORMAT *format) { CARD8 *bbuf = buf; memcpy(buf, format, SZ_RFB_PIXEL_FORMAT); buf_put_CARD16(&bbuf[4], format->r_max); buf_put_CARD16(&bbuf[6], format->g_max); buf_put_CARD16(&bbuf[8], format->b_max); }
int put_rect_header(CARD8 *buf, FB_RECT *r) { buf_put_CARD16(buf, r->x); buf_put_CARD16(&buf[2], r->y); buf_put_CARD16(&buf[4], r->w); buf_put_CARD16(&buf[6], r->h); buf_put_CARD32(&buf[8], r->enc); return 12; /* 12 bytes written */ }
AIO_BLOCK *rfb_encode_copyrect_block(CL_SLOT *cl, FB_RECT *r) { AIO_BLOCK *block; block = malloc(sizeof(AIO_BLOCK) + 12 + 4); if (block) { put_rect_header(block->data, r); buf_put_CARD16(&block->data[12], r->src_x); buf_put_CARD16(&block->data[14], r->src_y); block->data_size = 12 + 4; } return block; }
static void send_new_cliprects(void) { CL_SLOT *cl = (CL_SLOT *)cur_slot; CARD8 msg_hdr[4] = { 0, 0, 0, 1 }; CARD8 rect_hdr[12]; FB_RECT rect; crDebug("Sending new cliprects to proxy: %d, %d .. %d, %d", cl->new_clip_bounds.x1, cl->new_clip_bounds.y1, cl->new_clip_bounds.x2, cl->new_clip_bounds.y2); log_write(LL_DEBUG, "Sending NewCliprects (%dx%d) to %s", (int)cl->fb_width, (int)cl->fb_height, cur_slot->name); buf_put_CARD16(&msg_hdr[2], 1); /* one rect */ aio_write(NULL, msg_hdr, 4); rect.x = cl->new_clip_bounds.x1; rect.y = cl->new_clip_bounds.y1; rect.w = cl->new_clip_bounds.x2 - cl->new_clip_bounds.x1; rect.h = cl->new_clip_bounds.y2 - cl->new_clip_bounds.y1; rect.enc = RFB_ENCODING_CLIPRECTS; put_rect_header(rect_hdr, &rect); aio_write(wf_client_update_finished, rect_hdr, 12); /* Something has been queued for sending. */ cl->update_in_progress = 1; cl->update_requested = 0; }
static void send_newfbsize(void) { CL_SLOT *cl = (CL_SLOT *)cur_slot; CARD8 msg_hdr[4] = { 0, 0, 0, 1 }; CARD8 rect_hdr[12]; FB_RECT rect; log_write(LL_DEBUG, "Sending NewFBSize update (%dx%d) to %s", (int)cl->fb_width, (int)cl->fb_height, cur_slot->name); buf_put_CARD16(&msg_hdr[2], 1); aio_write(NULL, msg_hdr, 4); rect.x = 0; rect.y = 0; rect.w = cl->fb_width; rect.h = cl->fb_height; rect.enc = RFB_ENCODING_NEWFBSIZE; put_rect_header(rect_hdr, &rect); aio_write(wf_client_update_finished, rect_hdr, 12); /* Something has been queued for sending. */ cl->update_in_progress = 1; cl->update_requested = 0; }
static void request_update(int incr) { HOST_SLOT *hs = (HOST_SLOT *)cur_slot; unsigned char fbupdatereq_msg[] = { 3, /* Message id */ 0, /* Incremental if 1 */ 0, 0, 0, 0, /* X position, Y position */ 0, 0, 0, 0 /* Width, height */ }; fbupdatereq_msg[1] = (incr) ? 1 : 0; buf_put_CARD16(&fbupdatereq_msg[6], hs->fb_width); buf_put_CARD16(&fbupdatereq_msg[8], hs->fb_height); log_write(LL_DEBUG, "Sending FramebufferUpdateRequest message"); aio_write(NULL, fbupdatereq_msg, sizeof(fbupdatereq_msg)); }
static void rf_client_initmsg(void) { CL_SLOT *cl = (CL_SLOT *)cur_slot; unsigned char msg_server_init[24]; if (cur_slot->readbuf[0] == 0) { log_write(LL_WARN, "Non-shared session requested by %s", cur_slot->name); aio_close(0); } /* Save initial desktop geometry for this client */ cl->fb_width = g_screen_info.width; cl->fb_height = g_screen_info.height; cl->enable_newfbsize = 0; cl->enable_cliprects_enc = 0; /* Send ServerInitialisation message */ buf_put_CARD16(msg_server_init, cl->fb_width); buf_put_CARD16(msg_server_init + 2, cl->fb_height); buf_put_pixfmt(msg_server_init + 4, &g_screen_info.pixformat); buf_put_CARD32(msg_server_init + 20, g_screen_info.name_length); aio_write(NULL, msg_server_init, 24); aio_write(NULL, g_screen_info.name, g_screen_info.name_length); aio_setread(rf_client_msg, NULL, 1); /* Set up initial pixel format and encoders' parameters */ memcpy(&cl->format, &g_screen_info.pixformat, sizeof(RFB_PIXEL_FORMAT)); cl->trans_func = transfunc_null; cl->bgr233_f = 0; cl->compress_level = 6; /* default compression level */ cl->jpeg_quality = -1; /* disable JPEG by default */ /* The client did not request framebuffer updates yet */ cl->update_requested = 0; cl->update_in_progress = 0; REGION_INIT(&cl->pending_region, NullBox, 16); REGION_INIT(&cl->copy_region, NullBox, 8); cl->newfbsize_pending = 0; cl->new_cliprects = 0; /* We are connected. */ cl->connected = 1; }
void ScreenEncoder::sendUpdate(OutputStream& out) { ScopedLock s(rectLock); sendCount++; CL_SLOT *cl = &slot; // BoxRec fb_rect; // RegionRec fb_region, clip_region, outer_region; CARD8 msg_hdr[4] = { 0, 0, 0, 1 }; CARD8 rect_hdr[12]; ScreenRectangle rect; int num_penging_rects = pendingRectList.size(); //if(num_penging_rects == 0){ return; } buf_put_CARD16(&msg_hdr[2], 0xFFFF); if(num_penging_rects > 0) { out.write(msg_hdr, 4); } else { return; } //DDSS_VERBOSE("ScreenShareApp")<<"(sub) Pending Rects : "<<pendingRects.size()<<std::endl; /* For each of the usual pending rectangles: */ while(pendingRectList.size() > 0) { ScreenRectangle rect = pendingRectList[0]; pendingRectList.erase(pendingRectList.begin()); if(rect.enc == RFB_ENCODING_COPYRECT) { DDSS_VERBOSE("ScreenShareApp")<<"CopyRect : "<<rect<<std::endl; CARD8 tmp[16]; RFBHelper::put_rect_copy(tmp,&rect); out.write(tmp,16); } else if(rect.enc == RFB_ENCODING_CURSOR_POSITION) { CARD8 tmp[12]; RFBHelper::put_rect_header(tmp,&rect); out.write(tmp,12); DDSS_VERBOSE("Enc")<<"Sending Cursor update "<<rect<<" to sub!!!"<<std::endl; } else if(rect.enc == RFB_ENCODING_TIGHT)// || rect.enc == RFB_ENCODING_COPYRECT) { rect.enc = RFB_ENCODING_TIGHT; if(tightEncoder) { ByteBufferOutputStream& bos = (ByteBufferOutputStream&)out; size_t l1 = bos.get()->getLength(); tightEncoder->encode(out, &rect); size_t l2 = bos.get()->getLength(); DDSS_VERBOSE("[SUB-ENC]")<<"("<< (l2-l1)<<" bytes / "<<(rect.w * rect.h * 3)<<" bytes)"<<rect<<std::endl; } } else if(rect.enc == RFB_ENCODING_NEWFBSIZE) { CARD8 tmp[12]; RFBHelper::put_rect_header(tmp,&rect); out.write(tmp,12); } else { //DDSS_VERBOSE("ScreenShareApp")<<"[SUB-ENC] UNKNOWN ENCODED RECT : "<<rect<<std::endl; } size_t len = ((ByteBufferOutputStream&)out).get()->getLength(); if(len >= maxSize) { break; } } size_t len = ((ByteBufferOutputStream&)out).get()->getLength(); if(len > maxSize) { overflowCount++; } else { underflowCount++; } /* Send LastRect marker. */ if(num_penging_rects > 0) { rect.x = rect.y = rect.w = rect.h = 0; rect.enc = RFB_ENCODING_LASTRECT; RFBHelper::put_rect_header(rect_hdr, &rect); out.write(rect_hdr, 12); } }
static void send_update(void) { CL_SLOT *cl = (CL_SLOT *)cur_slot; BoxRec fb_rect; RegionRec fb_region, clip_region, outer_region; CARD8 msg_hdr[4] = { 0, 0, 0, 1 }; CARD8 rect_hdr[12]; int num_copy_rects, num_pending_rects, num_all_rects; int raw_bytes = 0, hextile_bytes = 0; int i, idx, rev_order; static int counter = 0; #ifdef NETLOGGER aio_set_serial_number(&cl->s, cl->serial_number); #endif counter++; vncspuLog(1, "Begin send update %d", counter); CRASSERT(vnc_spu.serverBuffer); /*crDebug("Enter send_update to %s", cur_slot->name);*/ /* check if clipping has changed since we got the pixels and update * the pending region if needed. */ if (NewClip) { /*crDebug("Getting updated cliprects");*/ vncspuGetScreenRects(&cl->pending_region); num_pending_rects = REGION_NUM_RECTS(&cl->pending_region); /*crDebug("Now, %d rects", num_pending_rects);*/ if (num_pending_rects == 0 && cl->enable_frame_sync) { /* always need to send _something_ for framesync to work */ BoxRec b; b.x1 = 0; b.y1 = 0; b.x2 = 1; b.y2 = 1; REGION_UNINIT(&cl->pending_region); REGION_INIT(&cl->pending_region, &b, 1); } NewClip = 0; } /*PrintRegion("Sending", &cl->pending_region);*/ /* Process framebuffer size change. */ if (cl->newfbsize_pending) { /* Update framebuffer size, clear newfbsize_pending flag. */ cl->fb_width = g_screen_info.width; cl->fb_height = g_screen_info.height; cl->newfbsize_pending = 0; log_write(LL_DEBUG, "Applying new framebuffer size (%dx%d) to %s", (int)cl->fb_width, (int)cl->fb_height, cur_slot->name); /* In any case, mark all the framebuffer contents as changed. */ fb_rect.x1 = 0; fb_rect.y1 = 0; fb_rect.x2 = cl->fb_width; fb_rect.y2 = cl->fb_height; REGION_INIT(&fb_region, &fb_rect, 1); REGION_COPY(&cl->pending_region, &fb_region); REGION_UNINIT(&fb_region); REGION_EMPTY(&cl->copy_region); /* If NewFBSize is supported by the client, send only NewFBSize pseudo-rectangle, pixel data will be sent in the next update. */ if (cl->enable_newfbsize) { send_newfbsize(); vncspuUnlockFrameBuffer(); return; } } else { /* Exclude CopyRect areas covered by pending_region. */ REGION_SUBTRACT(&cl->copy_region, &cl->copy_region, &cl->pending_region); } #if 00 if (cl->enable_cliprects_enc && cl->new_cliprects) { send_new_cliprects(); vncspuUnlockFrameBuffer(); cl->new_cliprects = 0; return; } #endif /* Clip regions to the rectangle requested by the client. */ REGION_INIT(&clip_region, &cl->update_rect, 1); REGION_INTERSECT(&cl->pending_region, &cl->pending_region, &clip_region); if (REGION_NOTEMPTY(&cl->copy_region)) { REGION_INTERSECT(&cl->copy_region, &cl->copy_region, &clip_region); REGION_INIT(&outer_region, NullBox, 8); REGION_COPY(&outer_region, &cl->copy_region); REGION_TRANSLATE(&clip_region, cl->copy_dx, cl->copy_dy); REGION_INTERSECT(&cl->copy_region, &cl->copy_region, &clip_region); REGION_SUBTRACT(&outer_region, &outer_region, &cl->copy_region); REGION_UNION(&cl->pending_region, &cl->pending_region, &outer_region); REGION_UNINIT(&outer_region); } REGION_UNINIT(&clip_region); /* Reduce the number of rectangles if possible. */ if (cl->enc_prefer == RFB_ENCODING_TIGHT && cl->enable_lastrect) { region_pack(&cl->pending_region, 32); } else { region_pack(&cl->pending_region, 12); } /* Compute the number of rectangles in regions. */ num_pending_rects = REGION_NUM_RECTS(&cl->pending_region); num_copy_rects = REGION_NUM_RECTS(&cl->copy_region); num_all_rects = num_pending_rects + num_copy_rects; if (num_all_rects == 0) { vncspuUnlockFrameBuffer(); return; } log_write(LL_DEBUG, "Sending framebuffer update (min %d rects) to %s", num_all_rects, cur_slot->name); /* Prepare and send FramebufferUpdate message header. */ /* FIXME: Enable Tight encoding even if LastRect is not supported. */ /* FIXME: Do not send LastRect if all the rectangles are CopyRect. */ if (cl->enc_prefer == RFB_ENCODING_TIGHT && cl->enable_lastrect) { buf_put_CARD16(&msg_hdr[2], 0xFFFF); } else { buf_put_CARD16(&msg_hdr[2], num_all_rects); } aio_write(NULL, msg_hdr, 4); /* Determine the order in which CopyRect rectangles should be sent. */ rev_order = (cl->copy_dy > 0 || (cl->copy_dy == 0 && cl->copy_dx > 0)); /* For each CopyRect rectangle: */ for (i = 0; i < num_copy_rects; i++) { FB_RECT rect; AIO_BLOCK *block; idx = (rev_order) ? num_copy_rects - i - 1 : i; rect.x = REGION_RECTS(&cl->copy_region)[idx].x1; rect.y = REGION_RECTS(&cl->copy_region)[idx].y1; rect.w = REGION_RECTS(&cl->copy_region)[idx].x2 - rect.x; rect.h = REGION_RECTS(&cl->copy_region)[idx].y2 - rect.y; rect.src_x = rect.x - cl->copy_dx; rect.src_y = rect.y - cl->copy_dy; rect.enc = RFB_ENCODING_COPYRECT; log_write(LL_DEBUG, "Sending CopyRect rectangle %dx%d at %d,%d to %s", (int)rect.w, (int)rect.h, (int)rect.x, (int)rect.y, cur_slot->name); /* Prepare the CopyRect rectangle. */ block = rfb_encode_copyrect_block(cl, &rect); /* Send the rectangle. FIXME: Check for block == NULL? */ aio_write_nocopy(NULL, block); } if (cl->enc_prefer == RFB_ENCODING_TIGHT) { /* needed for successful caching of zlib-compressed data (tight) */ rfb_reset_tight_encoder(cl); } if (num_pending_rects) { /* Lock around fb access so other thread doesn't change contents while * we're encoding. */ #ifdef NETLOGGER if (vnc_spu.netlogger_url) { NL_info("vncspu", "spu.encode.begin", "NODE=s NUMBER=i", vnc_spu.hostname, cl->serial_number); } #endif /* For each of the usual pending rectangles: */ for (i = 0; i < num_pending_rects; i++) { FB_RECT rect; AIO_BLOCK *block; /* crDebug("sending rect %d of %d: %d, %d .. %d, %d", i, num_pending_rects, REGION_RECTS(&cl->pending_region)[i].x1, REGION_RECTS(&cl->pending_region)[i].y1, REGION_RECTS(&cl->pending_region)[i].x2, REGION_RECTS(&cl->pending_region)[i].y2); */ rect.x = REGION_RECTS(&cl->pending_region)[i].x1; rect.y = REGION_RECTS(&cl->pending_region)[i].y1; rect.w = REGION_RECTS(&cl->pending_region)[i].x2 - rect.x; rect.h = REGION_RECTS(&cl->pending_region)[i].y2 - rect.y; log_write(LL_DEBUG, "Sending rectangle %dx%d at %d,%d to %s enc 0x%x", (int)rect.w, (int)rect.h, (int)rect.x, (int)rect.y, cur_slot->name, cl->enc_prefer); if (cl->enc_prefer == RFB_ENCODING_TIGHT && cl->enable_lastrect) { /* Use Tight encoding */ rect.enc = RFB_ENCODING_TIGHT; /* lock to prevent glReadPixels in other thread changing data */ rfb_encode_tight(cl, &rect); continue; /* Important! */ } else if (cl->enc_prefer == RFB_ENCODING_RAW24) { rect.enc = RFB_ENCODING_RAW24; block = rfb_encode_raw24_block(cl, &rect); } else if ( cl->enc_prefer != RFB_ENCODING_RAW && cl->enc_enable[RFB_ENCODING_HEXTILE] ) { /* Use Hextile encoding */ rect.enc = RFB_ENCODING_HEXTILE; block = rfb_encode_hextile_block(cl, &rect); if (block != NULL) { hextile_bytes += block->data_size; raw_bytes += rect.w * rect.h * (cl->format.bits_pixel / 8); } } else { /* Use Raw encoding */ rect.enc = RFB_ENCODING_RAW; if (vnc_spu.half_rez) { block = rfb_encode_raw_block_halfrez(cl, &rect); } else { block = rfb_encode_raw_block(cl, &rect); } } /* Send the rectangle. FIXME: Check for block == NULL? */ aio_write_nocopy(NULL, block); } } /* if num_pending_rects */ REGION_EMPTY(&cl->pending_region); REGION_EMPTY(&cl->copy_region); /* Send LastRect marker. */ if (cl->enc_prefer == RFB_ENCODING_TIGHT && cl->enable_lastrect) { FB_RECT rect; rect.x = rect.y = rect.w = rect.h = 0; rect.enc = RFB_ENCODING_LASTRECT; put_rect_header(rect_hdr, &rect); aio_write(NULL, rect_hdr, 12); } /* Set the last block's callback function */ /* All prev blocks had NULL callbacks */ assert(cur_slot->outqueue_last); if (cur_slot->outqueue_last) { cur_slot->outqueue_last->func = wf_client_update_finished; } /* Something has been queued for sending. */ cl->update_in_progress = 1; cl->update_requested = 0; #ifdef NETLOGGER if (vnc_spu.netlogger_url) { NL_info("vncspu", "spu.encode.end", "NODE=s NUMBER=i", vnc_spu.hostname, cl->serial_number); } aio_set_serial_number(&cl->s, 0); #endif vncspuUnlockFrameBuffer(); /* encoder done with buffer */ /*crDebug("Leave send_update");*/ vncspuLog(1, "End send update %d", counter); }