diff options
author | Benjamin Franzke <benjaminfranzke@googlemail.com> | 2013-03-07 17:00:01 +0100 |
---|---|---|
committer | Benjamin Franzke <benjaminfranzke@googlemail.com> | 2013-03-07 17:01:12 +0100 |
commit | c377f001e2f19aba95b89affd71592cc8e5866bc (patch) | |
tree | 553c73042d6b639c8d08e263eac910259d23aa29 | |
download | econ-c377f001e2f19aba95b89affd71592cc8e5866bc.tar.gz econ-c377f001e2f19aba95b89affd71592cc8e5866bc.tar.bz2 econ-c377f001e2f19aba95b89affd71592cc8e5866bc.zip |
Init econproxy: Support retrieving a frame from x11vnc & write to ppm
-rw-r--r-- | econproto.h | 220 | ||||
-rw-r--r-- | econproxy.c | 294 | ||||
-rwxr-xr-x | launch_x11vnc | 3 |
3 files changed, 517 insertions, 0 deletions
diff --git a/econproto.h b/econproto.h new file mode 100644 index 0000000..5fc99ab --- /dev/null +++ b/econproto.h @@ -0,0 +1,220 @@ +/* + Copyright (C) SEIKO EPSON CORPORATION 2002-2003. All Rights Reserved. + + 3-3-5, Owa, Suwa-shi Nagano-ken, 392-8502 Japan + Phone: +81-266-52-3131 + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License aint with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + + +#if !defined(__ECONPROTOCOL__) +#define __ECONPROTOCOL__ + +#include <stdint.h> + +#define ECON_PORTNUMBER 3620 +#define ECON_MAGICNUM_SIZE 4 +#define ECON_IPADDRESS_SIZE 4 +#define ECON_UNIQINFO_LENGTH 6 +#define ECON_PROJNAME_MAXLEN 32 +#define ECON_KEYWORD_MAXLEN 16 +#define ECON_ENCRYPTION_MAXLEN 8 + + +#ifdef LITTLE_ENDIAN_HOST + +#define Swap16IfLE(s) \ + ((CARD16) ((((s) & 0xff) << 8) | (((s) >> 8) & 0xff))) +#define Swap32IfLE(l) \ + ((CARD32) ((((l) & 0xff000000) >> 24) | \ + (((l) & 0x00ff0000) >> 8) | \ + (((l) & 0x0000ff00) << 8) | \ + (((l) & 0x000000ff) << 24))) + +#else + +#define Swap16IfLE(s) (s) +#define Swap32IfLE(l) (l) + +#endif + + + +#define ECON_MAGIC_NUMBER "EEMP" +#define ECON_PROTO_VERSION "0100" +#define ECON_PROTOVER_MAXLEN 4 + + +enum e_proj_state { + E_PSTAT_NOUSE = 1, + E_PSTAT_USING = 2, + E_PSTAT_APPUSING = 3 +}; + +enum _e_EmpCommand { + E_CMD_EASYSEARCH = 1, + E_CMD_IPSEARCH = 2, + E_CMD_CLIENTINFO = 3, + E_CMD_REQCONNECT = 4, + E_CMD_CONNECTED = 5, + E_CMD_REQRESTART = 6, + E_CMD_FINISHRESTART = 7, + E_CMD_DISCONCLIENT = 8, + E_CMD_INTERRUPT = 9, + E_CMD_KEEPALIVE = 10, + + E_CMD_SENDREQUESTS = 12, + E_CMD_CLIENTERROR = 13, + E_CMD_RESENDFULLSCRID = 14, + E_CMD_DISPLAYWAIT = 15, + E_CMD_SENDKEY = 16 +}; + +enum _e_ProjType { + e_ptype_IM_X = 1, + e_ptype_IM_XP1 = 2, + e_pType_IM_XP4 = 3 +}; + +enum _e_SendReq { + e_sendreq_OK = 1, + e_sendreq_NG = 2 +}; + + +enum _e_Keyword { + e_keyword_nouse = 0, + e_keyword_use = 1 +}; + + + +enum _e_Encryption { + e_encrypt_nouse = 0, + e_encrypt_use = 1 +}; + + + +enum _e_Error { + e_error_keyword = 0 +}; + + +typedef struct { + uint8_t bitsPerPixel; + uint8_t depth; + uint8_t bigEndian; + uint8_t trueColour; + + uint16_t redMax; + uint16_t greenMax; + uint16_t blueMax; + uint8_t redShift; + uint8_t greenShift; + uint8_t blueShift; + uint8_t pad1; + uint16_t pad2; +} rfbPixelFormat; + + +typedef struct { + uint16_t framebufferWidth; + uint16_t framebufferHeight; + rfbPixelFormat format; + uint32_t nameLength; +} rfbServerInitMsg; + + +typedef struct { + char projName[ECON_PROJNAME_MAXLEN]; + uint8_t projState; + uint8_t useKeyword; + uint8_t displayType; +} e_command_clientinfo; + + +typedef struct { + uint8_t useEncryption; + uint8_t EncPassword[ECON_ENCRYPTION_MAXLEN]; + uint8_t subnetMask[ECON_IPADDRESS_SIZE]; + uint8_t gateAddress[ECON_IPADDRESS_SIZE]; + rfbServerInitMsg vnesInitMsg; +} e_command_reqconnect; + + +typedef struct { + char projName[ECON_PROJNAME_MAXLEN]; + uint8_t projState; +} e_command_connected; + + + +typedef struct { + uint8_t errorNo; +} e_command_clienterror; + + + +typedef struct { + uint32_t resendID; +} e_command_resendfullscrid; + + + +typedef struct { + uint32_t keyID; +} e_command_sendkey; + +typedef struct { + uint16_t unknown_field1; + uint16_t unknown_field2; + uint16_t width; + uint16_t height; +} e_command_cmd22; + + +struct econ_header{ + char magicnum[ECON_MAGICNUM_SIZE]; + char version[ECON_PROTOVER_MAXLEN]; + uint8_t IPaddress[ECON_IPADDRESS_SIZE]; + uint32_t commandID; + uint32_t datasize; +}; + +struct econ_command{ + uint8_t recordCount; + uint8_t implicit_padding[3]; + union e_commands { + e_command_clientinfo clientinfo; + e_command_reqconnect reqconnect; + e_command_connected connected; + e_command_clienterror clienterror; + e_command_resendfullscrid resendid; + e_command_sendkey sendkey; + + e_command_cmd22 cmd22; + } command; +}; + +struct econ_record { + uint8_t projUniqInfo[ECON_UNIQINFO_LENGTH]; + uint8_t projKeyword[ECON_KEYWORD_MAXLEN]; + uint8_t IPaddress[ECON_IPADDRESS_SIZE]; +}; + +#endif diff --git a/econproxy.c b/econproxy.c new file mode 100644 index 0000000..41dceb5 --- /dev/null +++ b/econproxy.c @@ -0,0 +1,294 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stddef.h> +#include <stdint.h> +#include <assert.h> +#include <errno.h> + +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/ioctl.h> +#include <sys/select.h> +#include <sys/uio.h> +#include <unistd.h> +#include <netdb.h> +#include <net/if.h> +#include <net/if_arp.h> +#include <netinet/in.h> + +#include <poll.h> + +#include "econproto.h" + +#define MAX(a, b) (((a) > (b)) ? (a) : (b)) +#define ARRAY_SIZE(arr) (sizeof (arr) / sizeof ((arr)[0])) + +struct ep { + int vnc_mfd; + int vnc_fd; + + struct iovec iov[3]; +}; + + +/* From systemd:src/shared/util.c */ + +static ssize_t +loop_read(int fd, void *buf, size_t nbytes, uint8_t do_poll) { + uint8_t *p; + ssize_t n = 0; + + assert(fd >= 0); + assert(buf); + + p = buf; + + while (nbytes > 0) { + ssize_t k; + + if ((k = read(fd, p, nbytes)) <= 0) { + + if (k < 0 && errno == EINTR) + continue; + + if (k < 0 && errno == EAGAIN && do_poll) { + struct pollfd pollfd; + + memset(&pollfd, 0, sizeof pollfd); + pollfd.fd = fd; + pollfd.events = POLLIN; + + if (poll(&pollfd, 1, -1) < 0) { + if (errno == EINTR) + continue; + + return n > 0 ? n : -errno; + } + + if (pollfd.revents != POLLIN) + return n > 0 ? n : -EIO; + + continue; + } + + return n > 0 ? n : (k < 0 ? -errno : 0); + } + + p += k; + nbytes -= k; + n += k; + } + + return n; +} + +static void +write_ppm(FILE *img, int width, int height, int bpp, uint8_t *buf) +{ + int i; + + fprintf(img, "P6\n"); + fprintf(img, "%d %d\n255\n", width, height); + + for (i = 0; i < width * height; ++i) { + fwrite(&buf[i*bpp+2], 1, 1, img); + fwrite(&buf[i*bpp+1], 1, 1, img); + fwrite(&buf[i*bpp+0], 1, 1, img); + } +} + + +static int +bind_socket(int socktype, char *host, char *port) +{ + struct addrinfo hints, *result, *rp; + int reuseaddr = 1, s; + int fd; + + memset(&hints, 0, sizeof hints); + hints.ai_family = AF_INET; + hints.ai_socktype = socktype; + + s = getaddrinfo(host, port, &hints, &result); + if (s != 0) { + fprintf(stderr, "getaddrinfo :%s\n", gai_strerror(s)); + return -1; + } + for (rp = result; rp != NULL; rp = rp->ai_next) { + fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); + if (fd == -1) + continue; + if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, + &reuseaddr, sizeof(reuseaddr)) == -1) + continue; + + /*ip = ((struct sockaddr_in *)rp->ai_addr)->sin_addr.s_addr;*/ + if (bind(fd, rp->ai_addr, rp->ai_addrlen) == 0) + break; + + close(fd); + } + freeaddrinfo(result); + if (rp == NULL) { + fprintf(stderr, "Failed to bind: %s\n", strerror(errno)); + return -1; + } + + return fd; +} + +int +main(int argc, char *argv[]) +{ + struct ep ep; + int len; + + memset(&ep, 0, sizeof ep); + + ep.vnc_mfd = bind_socket(SOCK_STREAM, "localhost", "5500"); + if (ep.vnc_mfd < 0) + exit(EXIT_FAILURE); + if (listen(ep.vnc_mfd, 1) != 0) + exit(EXIT_FAILURE); + + + ep.vnc_fd = accept(ep.vnc_mfd, NULL, NULL); + if (ep.vnc_fd < 0) + exit(EXIT_FAILURE); + + char client_protocol[12]; + read(ep.vnc_fd, client_protocol, sizeof client_protocol); + + const char *rfb_protocol = "RFB 003.008\n"; + write(ep.vnc_fd, rfb_protocol, strlen(rfb_protocol)); + + char security_types[BUFSIZ]; + len = read(ep.vnc_fd, security_types, BUFSIZ); + printf("security_types: %d\n", len); + +#define NOAUTH 1 + uint8_t auth = NOAUTH; + write(ep.vnc_fd, &auth, sizeof auth); + + uint32_t auth_result = 0; + + len = read(ep.vnc_fd, &auth_result, sizeof auth_result); + if (auth_result != 0) { + fprintf(stderr, "auth failed: %d, %d\n", auth_result, len); + exit(EXIT_FAILURE); + } + + uint8_t share_desktop = 1; + write(ep.vnc_fd, &share_desktop, sizeof share_desktop); + + union init { + rfbServerInitMsg msg; + struct { + rfbServerInitMsg msg; + char name[0]; + } d; + char buf[BUFSIZ]; + }; + union init init; + + + len = read(ep.vnc_fd, &init, sizeof init); + printf("read init: %d\n", len); + + printf("w: %hu, h: %hu\n", ntohs(init.msg.framebufferWidth), ntohs(init.msg.framebufferHeight)); + + + struct { + uint8_t cmd; + uint8_t padding1; + uint16_t padding2; + } cmd_set_pixel_format = { 0, 0, 0 }; + + ep.iov[0].iov_base = &cmd_set_pixel_format; + ep.iov[0].iov_len = sizeof cmd_set_pixel_format; + ep.iov[1].iov_base = &init.msg.format; + ep.iov[1].iov_len = sizeof init.msg.format; + + writev(ep.vnc_fd, ep.iov, 2); + + struct { + uint8_t cmd; + uint8_t padding; + uint16_t number_of_encodings; + uint32_t encodings[2]; + } cmd_set_encodings = { + 2, 0, htons(2), +#if 1 + { htonl(0) /* RAW */, htonl(7) /* Tight */ } +#else + { htonl(7) /* Tight */, htonl(0) /* RAW */ } +#endif + }; + + write(ep.vnc_fd, &cmd_set_encodings, sizeof cmd_set_encodings); + + struct { + uint8_t cmd; + uint8_t incremental; + uint16_t x, y, w, h; + } framebuffer_update_request = { + 3, 0, + htons(0), htons(0), htons(1024), htons(768) + }; + write(ep.vnc_fd, &framebuffer_update_request, sizeof framebuffer_update_request); + + struct framebuffer_update { + uint8_t cmd; + uint8_t padding; + uint16_t nrects; + } framebuffer_update; + + struct rect { + uint16_t x, y, w, h; + int32_t encoding; + uint8_t data[0]; + }; + +#if 0 + ep.iov[0].iov_base = &framebuffer_update; + ep.iov[0].iov_len = sizeof framebuffer_update; + ep.iov[1].iov_base = buf; + ep.iov[1].iov_len = bufsiz; +#endif + + len = read(ep.vnc_fd, &framebuffer_update, sizeof framebuffer_update); + //len = readv(ep.vnc_fd, ep.iov, 2); + printf("read framebuffer update?: %d\n", len); + + framebuffer_update.nrects = ntohs(framebuffer_update.nrects); + printf("cmd: %d, nrects: %d\n", framebuffer_update.cmd, ntohs(framebuffer_update.nrects)); + + size_t bufsiz = framebuffer_update.nrects * (sizeof(struct rect) + 1024 * 768 * init.msg.format.bitsPerPixel/8); + char *buf = malloc(bufsiz); + assert(buf != NULL); + + len = loop_read(ep.vnc_fd, buf, bufsiz, 0); + printf("read framebuffer update data?: %d\n", len); + + struct rect *rect = (void *) buf; + printf("x: %d, y: %d, w: %d, h: %d, encoding: %d\n", + ntohs(rect->x), ntohs(rect->y), ntohs(rect->w), ntohs(rect->h), ntohl(rect->encoding)); + + FILE *img = fopen("/tmp/out.ppm", "w"); + write_ppm(img, 1024, 768, 4, buf); + fclose(img); + + + /* + len = read(ep.vnc_fd, buf, bufsiz); + printf("read framebuffer update data?: %d\n", len); + + while (len > 0) { + len = read(ep.vnc_fd, buf, bufsiz); + printf("read framebuffer update data?: %d\n", len); + } + */ + + pause(); +} diff --git a/launch_x11vnc b/launch_x11vnc new file mode 100755 index 0000000..8098423 --- /dev/null +++ b/launch_x11vnc @@ -0,0 +1,3 @@ +#!/bin/sh + +exec x11vnc -coe localhost -rfbport 0 -nopw -nocursor -nosel -viewonly -deferupdate none -clip 1024x768+0+0 |