shithub: rd

Download patch

ref: 9e4a5b55ba158232bf2781f5914260ff74da5dde
parent: cd46c2b490f73e5cd366b6230cba1eac0b4d01e2
author: Yaroslav Kolomiiets <yarikos@gmail.com>
date: Fri Aug 5 11:42:42 EDT 2016

add libthread version

--- a/mkfile
+++ b/mkfile
@@ -26,6 +26,34 @@
 	wsys.$O\
 	x224.$O\
 
+THREADOFILES=\
+	alloc.$O\
+	cap.$O\
+	eclip.$O\
+	egdi.$O\
+	ele.$O\
+	kbd.$O\
+	rle.$O\
+	load.$O\
+	mcs.$O\
+	mouse.$O\
+	mpas.$O\
+	mppc.$O\
+	msg.$O\
+	rd-thread.$O\
+	rpc.$O\
+	tls.$O\
+	utf16.$O\
+	vchan.$O\
+	wsys.$O\
+	x224.$O\
+
 </sys/src/cmd/mkone
 
 $TARG: mkfile
+
+default:V: $O.thread
+all:V: $O.thread
+
+$O.thread:	$THREADOFILES $LIB
+	$LD $LDFLAGS -o $target $prereq
--- /dev/null
+++ b/rd-thread.c
@@ -1,0 +1,363 @@
+#include <u.h>
+#include <libc.h>
+#include <draw.h>
+#include <thread.h>
+#include <keyboard.h>
+#include <mouse.h>
+#include <cursor.h>
+#include <auth.h>
+#include "dat.h"
+#include "fns.h"
+
+#define	STACK	8192
+
+Rdp conn = {
+	.fd = -1,
+	.depth = 16,
+	.windom = "",
+	.passwd = "",
+	.shell = "",
+	.rwd = "",
+};
+Mousectl		*mousectl;
+Keyboardctl	*keyboardctl;
+
+char Eshort[]=	"short data";
+char Esmall[]=	"buffer too small";
+char Ebignum[]=	"number too big";
+
+void	sendmouse(Rdp* c, Mouse m);
+
+static void	keyboardthread(void*);
+static void	mousethread(void*);
+static void	snarfthread(void*);
+
+static void
+usage(void)
+{
+	fprint(2, "usage: rd [-0A] [-T title] [-a depth] [-c wdir] [-d dom] [-k keyspec] [-n term] [-s shell] [net!]server[!port]\n");
+	threadexitsall("usage");
+}
+
+void
+threadmain(int argc, char *argv[])
+{
+	int doauth;
+	char *server, *addr, *keyspec;
+	UserPasswd *creds;
+	Rdp* c;
+
+	c = &conn;
+
+	keyspec = "";
+	doauth = 1;
+
+	ARGBEGIN {
+	case 'A':
+		doauth = 0;
+		break;
+	case 'k':
+		keyspec = EARGF(usage());
+		break;
+	case 'T':
+		c->label = strdup(EARGF(usage()));
+		break;
+	case 'd':
+		c->windom = strdup(EARGF(usage()));
+		break;
+	case 's':
+		c->shell = strdup(EARGF(usage()));
+		break;
+	case 'c':
+		c->rwd = strdup(EARGF(usage()));
+		break;
+	case 'a':
+		c->depth = atol(EARGF(usage()));
+		break;
+	case '0':
+		c->wantconsole = 1;
+		break;
+	default:
+		usage();
+	} ARGEND
+
+	if (argc != 1)
+		usage();
+
+	server = argv[0];
+
+	c->local = getenv("sysname");
+	c->user = getenv("user");
+	if(c->local == nil)
+		sysfatal("set $sysname or use -n\n");
+	if(c->user == nil)
+		sysfatal("set $user");
+	if(doauth){
+		creds = auth_getuserpasswd(auth_getkey, "proto=pass service=rdp %s", keyspec);
+		if(creds == nil)
+			fprint(2, "factotum: %r\n");
+		else {
+			c->user = creds->user;
+			c->passwd = creds->passwd;
+		}
+	}else
+		c->user = "";
+	if(c->label == nil)
+		c->label = smprint("rd %s", server);
+
+	initvc(c);
+
+	addr = netmkaddr(server, "tcp", "3389");
+	c->fd = dial(addr, nil, nil, nil);
+	if(c->fd < 0)
+		sysfatal("dial %s: %r", addr);
+	if(x224handshake(c) < 0)
+		sysfatal("X.224 handshake: %r");
+	initscreen(c);
+	if(rdphandshake(c) < 0)
+		sysfatal("handshake: %r");
+
+	mousectl = initmouse(nil, screen);
+	if(mousectl == nil){
+		fprint(2, "rd: can't initialize mouse: %r\n");
+		exits("mouse");
+	}
+	keyboardctl = initkeyboard(nil);
+	if(keyboardctl == nil){
+		fprint(2, "rd: can't initialize keyboard: %r\n");
+		exits("keyboard");
+	}
+
+	proccreate(keyboardthread, c, STACK);
+	proccreate(mousethread, c, STACK);
+	proccreate(snarfthread, c, STACK);
+
+	threadsetname("mainthread");
+	readnet(c);
+
+	x224hangup(c);
+	if(!c->active)
+		threadexitsall(nil);
+	if(c->hupreason)
+		sysfatal("disconnect reason code %d", c->hupreason);
+	sysfatal("hangup");
+}
+
+void
+initscreen(Rdp* c)
+{
+	if(initdraw(drawerror, nil, c->label) < 0)
+		sysfatal("initdraw: %r");
+	display->locking = 1;
+	unlockdisplay(display);
+	c->ysz = Dy(screen->r);
+	c->xsz = (Dx(screen->r) +3) & ~3;
+}
+
+void
+readnet(Rdp* c)
+{
+	Msg r;
+
+	for(;;){
+		if(readmsg(c, &r) <= 0)
+			return;
+
+		switch(r.type){
+		case Mclosing:
+			return;
+		case Mvchan:
+			scanvc(c, &r);
+			break;
+		case Aupdate:
+			scanupdates(c, &r);
+			break;
+		case 0:
+			fprint(2, "unsupported PDU\n");
+			break;
+		default:
+			fprint(2, "r.type %d is not expected\n", r.type);
+		}
+	}
+}
+
+void
+scanupdates(Rdp* c, Msg* m)
+{
+	int n;
+	uchar *p, *ep;
+	Share u;
+
+	p = m->data;
+	ep = m->data + m->ndata;
+
+	for(; p < ep; p += n){
+		n = m->getshare(&u, p, ep-p);
+		if(n < 0)
+			sysfatal("scanupdates: %r");
+
+		switch(u.type){
+		default:
+			if(u.type != 0)
+				fprint(2, "scanupdates: unhandled %d\n", u.type);
+			break;
+		case ShDeactivate:
+			deactivating(c, &u);
+			break;
+		case ShActivate:	// server may engage capability re-exchange
+			activating(c, &u);
+			break;
+		case ShEinfo:
+			c->hupreason = u.err;
+			break;
+		case ShUorders:
+			scanorders(c, &u);
+			break;
+		case ShUimg:
+			scanimgupdate(c, &u);
+			break;
+		case ShUcmap:
+			scancmap(c, &u);
+			break;
+		case ShUwarp:
+			warpmouse(u.x, u.y);
+			break;
+		case Aflow:
+			break;
+		}
+	}
+}
+
+void
+scanimgupdate(Rdp *c, Share* as)
+{
+	uchar* p, *ep;
+	int n, err, nr;
+	static Image* img;
+	Rectangle r, rs, d;
+	Imgupd iu;
+
+	assert(as->type == ShUimg);
+	p = as->data;
+	ep = as->data + as->ndata;
+	nr = as->nrect;
+
+	rs = rectaddpt(Rpt(ZP, Pt(c->xsz, c->ysz)), screen->r.min);
+
+	if(display->locking)
+		lockdisplay(display);
+
+	if(img==nil || !eqrect(img->r, rs)){
+		if(img != nil)
+			freeimage(img);
+		img = allocimage(display, rs, c->chan, 0, DNofill);
+		if(img == nil)
+			sysfatal("scanimgupdate: %r");
+	}
+
+	while(p<ep && nr>0){
+		/* 2.2.9.1.1.3.1.2.2 Bitmap Data (TS_BITMAP_DATA) */
+		if((n = getimgupd(&iu, p, ep-p)) < 0)
+			sysfatal("getimgupd: %r");
+		if(iu.depth != img->depth)
+			sysfatal("bad image depth");
+
+		d.min = Pt(iu.x, iu.y);
+		d.max = Pt(iu.xm+1, iu.ym+1);
+		r.min = ZP;
+		r.max = Pt(iu.xsz, iu.ysz);
+		r = rectaddpt(r, img->r.min);
+
+		err = (iu.iscompr? loadrle : loadbmp)(img, r, iu.bytes, iu.nbytes, c->cmap);
+		if(err < 0)
+			sysfatal("%r");
+		draw(screen, rectaddpt(d, screen->r.min), img, nil, img->r.min);
+		p += n;
+		nr--;
+	}
+	flushimage(display, 1);
+	if(display->locking)
+		unlockdisplay(display);
+}
+
+void
+scancmap(Rdp* c, Share* as)
+{
+	int i, n;
+	uchar *p,  *ep, *cmap;
+
+	p = as->data;
+	ep = as->data + as->ndata;
+	cmap = c->cmap;
+
+	n = GSHORT(p+4);
+	p += 8;
+	if(n > sizeof(c->cmap)){
+		fprint(2, "scancmap: data too big");
+		return;
+	}
+	if(p+3*n > ep)
+		sysfatal(Eshort);
+	for(i = 0; i<n; p+=3)
+		cmap[i++] = rgb2cmap(p[0], p[1], p[2]);
+}
+
+static void
+keyboardthread(void* v)
+{
+	Rune r;
+	Rdp* c;
+
+	c = v;
+	threadsetname("keyboardthread");
+	for(;;){
+		recv(keyboardctl->c, &r);
+		sendkbd(c, r);
+	}
+}
+
+static void
+mousethread(void* v)
+{
+	Rdp* c;
+	enum { MResize, MMouse, NMALT };
+	static Alt alts[NMALT+1];
+
+	c = v;
+	threadsetname("mousethread");
+	alts[MResize].c = mousectl->resizec;
+	alts[MResize].v = nil;
+	alts[MResize].op = CHANRCV;
+	alts[MMouse].c = mousectl->c;
+	alts[MMouse].v = &mousectl->Mouse;
+	alts[MMouse].op = CHANRCV;
+
+	for(;;){
+		switch(alt(alts)){
+		case MResize:
+			eresized(c, 1);
+			break;
+		case MMouse:
+			sendmouse(c, mousectl->Mouse);
+			break;
+		}
+	}
+}
+
+void
+warpmouse(int x, int y)
+{
+	moveto(mousectl, Pt(x, y));
+}
+
+static void
+snarfthread(void* v)
+{
+	Rdp* c;
+
+	c = v;
+	threadsetname("snarfthread");
+	initsnarf();
+	pollsnarf(c);
+	threadexits("snarf eof");
+}