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");
+}