summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenjamin Franzke <benjaminfranzke@googlemail.com>2013-03-07 17:00:01 +0100
committerBenjamin Franzke <benjaminfranzke@googlemail.com>2013-03-07 17:01:12 +0100
commitc377f001e2f19aba95b89affd71592cc8e5866bc (patch)
tree553c73042d6b639c8d08e263eac910259d23aa29
downloadecon-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.h220
-rw-r--r--econproxy.c294
-rwxr-xr-xlaunch_x11vnc3
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