X-Git-Url: https://git.sesse.net/?p=rdpsrv;a=blobdiff_plain;f=rdpsrv.c;h=c838fc7a60c711d7f7ec8434a9b9755ad8040feb;hp=43bf2a42d449faf1d11d2149355d92356e4134e6;hb=dbccf42e4424093cfc0f970d1fcfaad9ae60c954;hpb=8620fedb9b11c67f5eab4b07cbac9dce189f5858 diff --git a/rdpsrv.c b/rdpsrv.c index 43bf2a4..c838fc7 100644 --- a/rdpsrv.c +++ b/rdpsrv.c @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include @@ -58,12 +59,14 @@ int create_server_socket() return server_sock; } -void handle_input_pdu(STREAM s) +void handle_input_pdu(STREAM s, int vnc_sock) { uint32 time; uint16 message_type, device_flags, param1, param2; uint16 num_events; int i; + char buf[256]; + static int mouse1_down = 0, mouse2_down = 0; in_uint16_le(s, num_events); // number of events in_uint8s(s, 2); // pad @@ -90,8 +93,18 @@ void handle_input_pdu(STREAM s) printf("- Device flags: %x\n", device_flags); printf("- Position: (%u,%u)\n", param1, param2); - // debug - rdp_send_bitmap_update(param1, param2); + if (device_flags & MOUSE_FLAG_BUTTON1) + mouse1_down = (device_flags & MOUSE_FLAG_DOWN) ? 0x01 : 0; + if (device_flags & MOUSE_FLAG_BUTTON2) + mouse2_down = (device_flags & MOUSE_FLAG_DOWN) ? 0x02 : 0; + + buf[0] = 5; // message type + buf[1] = mouse1_down | mouse2_down; // button mask + buf[2] = param1 >> 8; + buf[3] = param1 & 0xff; + buf[4] = param2 >> 8; + buf[5] = param2 & 0xff; + write(vnc_sock, buf, 6); break; default: @@ -100,6 +113,20 @@ void handle_input_pdu(STREAM s) } printf("\n"); } + + // re-request the entire framebuffer + buf[0] = 3; // message type + buf[1] = 1; // incremental + buf[2] = 0; // xpos + buf[3] = 0; + buf[4] = 0; // ypos + buf[5] = 0; + buf[6] = 640 >> 8; // width + buf[7] = 640 & 0xff; + buf[8] = 480 >> 8; // height + buf[9] = 480 & 0xff; + + write(vnc_sock, buf, 10); } struct ServerInitialization { @@ -137,19 +164,121 @@ int vnc_init() printf("Server is %u x %u\n", ntohs(si.width), ntohs(si.height)); - if (read(vnc_sock, buf, si.name_len) != si.name_len) - error("short read on server name"); + if (read(vnc_sock, buf, ntohl(si.name_len)) != ntohl(si.name_len)) + error("short read on server name\n"); + +// printf("Server name is '%*s' (%u bytes)\n", ntohl(si.name_len), buf, ntohl(si.name_len)); - printf("Server name is '%*s'\n", si.name_len, buf); + // we can only accept raw encoding + buf[0] = 2; // message type + buf[1] = 0; // padding + buf[2] = 0; // number of encodings + buf[3] = 1; + buf[4] = 0; // raw encoding + buf[5] = 0; + buf[6] = 0; + buf[7] = 0; + + write(vnc_sock, buf, 8); + + // request the entire framebuffer + buf[0] = 3; // message type + buf[1] = 0; // incremental + buf[2] = 0; // xpos + buf[3] = 0; + buf[4] = 0; // ypos + buf[5] = 0; + buf[6] = 640 >> 8; // width + buf[7] = 640 & 0xff; + buf[8] = 480 >> 8; // height + buf[9] = 480 & 0xff; + + write(vnc_sock, buf, 10); printf("Connected to VNC!\n"); return vnc_sock; } +struct vnc_rectangle { + unsigned short x, y, width, height; + unsigned int encoding; +}; + +void handle_vnc_fbupdate(int vnc_sock) +{ + struct vnc_rectangle rect; + unsigned char *data, *ptr, *src, *dst; + unsigned short num_rect; + int ret, data_left, i, xt, yt; + unsigned char smallblock[64 * 64 * 3]; + + if (read(vnc_sock, &num_rect, 2) != 2) + error("short read on num_rect\n"); + + for (i = 0; i < ntohs(num_rect); ++i) { + int width, height; + + if (read(vnc_sock, &rect, sizeof(struct vnc_rectangle)) != sizeof(struct vnc_rectangle)) + error("short read on vnc_rectangle\n"); + + if (ntohl(rect.encoding) != 0) + error("unsupported encoding\n"); + + width = ntohs(rect.width); + height = ntohs(rect.height); + + printf("UPDATE: %ux%u at (%u,%u)\n", width, height, + ntohs(rect.x), ntohs(rect.y)); + + ptr = data = xmalloc(width * height * 4); + data_left = width * height * 4; + + while (data_left > 0) { + ret = read(vnc_sock, ptr, data_left); + if (ret <= 0) + error("error on data read\n"); + + ptr += ret; + data_left -= ret; + } + + // push our 32-bit RGB data into small enough chunks + // (64x64) so we are sure we can send them without + // everything crashing and stuff :-) + for (yt = 0; yt < (height + 63) / 64; ++yt) { + for (xt = 0; xt < (width + 63) / 64; ++xt) { + int x, y; + int bw = width - xt * 64; + int bh = height - yt * 64; + if (bw > 64) + bw = 64; + if (bh > 64) + bh = 64; + + dst = smallblock; + for (y = 0; y < bh; ++y) { + src = data + ((yt * 64 + (bh - 1 - y)) * width + (xt * 64)) * 4; + for (x = 0; x < bw; ++x) { + *dst++ = *src++; + *dst++ = *src++; + *dst++ = *src++; + ++src; + } + } + + rdp_send_bitmap_update(ntohs(rect.x) + xt * 64, ntohs(rect.y) + yt * 64, bw, bh, smallblock); + } + } + + xfree(data); + } +} + int serve_client() { int vnc_sock = vnc_init(); + int listen_on_vnc = 0; if (!mcs_recv_connect_initial()) error("MCS_CONNECT_INITIAL recv failed"); @@ -159,24 +288,60 @@ int serve_client() uint8 type, data_pdu_type; STREAM s; - while ((s = rdp_recv(&type)) != NULL) { - if (type != RDP_PDU_DATA) { - printf("Unknown RDP packet of type %u\n", type); - continue; + fd_set readfs; + FD_ZERO(&readfs); + FD_SET(tcp_get_socket(), &readfs); + FD_SET(vnc_sock, &readfs); + + select(FD_SETSIZE, &readfs, NULL, NULL, NULL); + + // activity on RDP socket? + if (FD_ISSET(tcp_get_socket(), &readfs)) { + if ((s = rdp_recv(&type)) != NULL) { + if (type != RDP_PDU_DATA) { + printf("Unknown RDP packet of type %u\n", type); + continue; + } + + in_uint8s(s, 8); /* shareid, pad, streamid, length */ + in_uint8(s, data_pdu_type); + in_uint8s(s, 3); /* compress_type, compress_len */ + + switch (data_pdu_type) { + case RDP_DATA_PDU_INPUT: + handle_input_pdu(s, vnc_sock); + listen_on_vnc = 1; + break; + default: + printf("Unknown data PDU type %u\n", data_pdu_type); + }; } + } - in_uint8s(s, 8); /* shareid, pad, streamid, length */ - in_uint8(s, data_pdu_type); - in_uint8s(s, 3); /* compress_type, compress_len */ + // activity on VNC socket? + if (FD_ISSET(vnc_sock, &readfs) && listen_on_vnc) { + unsigned char buf[256]; - switch (data_pdu_type) { - case RDP_DATA_PDU_INPUT: - printf("Input PDU\n"); - handle_input_pdu(s); + printf("Activity on VNC socket!\n"); + + if (read(vnc_sock, buf, 1) != 1) + error("short read on vnc_sock\n"); + + switch (buf[0]) { + case 0: + // frame buffer update! + printf("Framebuffer update\n"); + if (read(vnc_sock, buf, 1) != 1) + error("short read on vnc_sock\n"); + handle_vnc_fbupdate(vnc_sock); + break; + case 2: + printf("\n"); break; default: - printf("Unknown data PDU type %u\n", data_pdu_type); - }; + printf("Unknown VNC server message %x\n", buf[0]); + exit(1); + } } } }