xref: /inferno-os/appl/lib/plumbmsg.b (revision 37da2899f40661e3e9631e497da8dc59b971cbd0)
1implement Plumbmsg;
2
3include "sys.m";
4	sys: Sys;
5
6include "plumbmsg.m";
7
8input: ref Sys->FD;
9port: ref Sys->FD;
10portname: string;
11maxdatasize: int;
12
13init(doinput: int, rcvport: string, maxdata: int): int
14{
15	sys = load Sys Sys->PATH;
16
17	if(!doinput && rcvport == nil)	# server, not client
18		return 1;
19	input = sys->open("/chan/plumb.input", Sys->OWRITE);
20	if(input == nil)
21		return -1;
22	if(rcvport == nil)	# sending messages but never receiving them
23		return 1;
24	port = sys->open("/chan/plumb."+rcvport, Sys->OREAD);
25	if(port == nil){
26		input = nil;
27		return -1;
28	}
29	maxdatasize = maxdata;
30	portname = rcvport;
31	msg := ref Msg;
32	msg.src = portname;
33	msg.dst = "plumb";
34	msg.kind = "text";
35	msg.data = array of byte "start";
36	if(msg.send() < 0){
37		port = nil;
38		input = nil;
39		return -1;
40	}
41	return 1;
42}
43
44shutdown()
45{
46	msg := ref Msg;
47	msg.src = portname;
48	msg.dst = "plumb";
49	msg.kind = "text";
50	msg.data = array of byte "stop";
51	msg.send();
52}
53
54Msg.send(msg: self ref Msg): int
55{
56	hdr :=
57		msg.src+"\n"+
58		msg.dst+"\n"+
59		msg.dir+"\n"+
60		msg.kind+"\n"+
61		msg.attr+"\n"+
62		string len msg.data+"\n";
63	ahdr := array of byte hdr;
64	b := array[len ahdr+len msg.data] of byte;
65	b[0:] = ahdr;
66	b[len ahdr:] = msg.data;
67	return sys->write(input, b, len b);
68}
69
70Msg.recv(): ref Msg
71{
72	b := array[maxdatasize+1000] of byte;
73	n := sys->read(port, b, len b);
74	if(n <= 0)
75		return nil;
76	return Msg.unpack(b[0:n]);
77}
78
79Msg.unpack(b: array of byte): ref Msg
80{
81	(hdr, data) := unpack(b, 6);
82	if(hdr == nil)
83		return nil;
84
85	msg := ref Msg;
86	msg.src = hdr[0];
87	msg.dst = hdr[1];
88	msg.dir = hdr[2];
89	msg.kind = hdr[3];
90	msg.attr = hdr[4];
91	msg.data = data;
92
93	return msg;
94}
95
96Msg.pack(msg: self ref Msg): array of byte
97{
98	hdr :=
99		msg.src+"\n"+
100		msg.dst+"\n"+
101		msg.dir+"\n"+
102		msg.kind+"\n"+
103		msg.attr+"\n"+
104		string len msg.data+"\n";
105	ahdr := array of byte hdr;
106	b := array[len ahdr+len msg.data] of byte;
107	b[0:] = ahdr;
108	b[len ahdr:] = msg.data;
109	return b;
110}
111
112# unpack message from array of bytes.  last string in message
113# is number of bytes in data portion of message
114unpack(b: array of byte, ns: int): (array of string, array of byte)
115{
116	i := 0;
117	a := array[ns] of string;
118	for(n:=0; n<ns; n++){
119		(i, a[n]) = unpackstring(b, i);
120		if(i < 0)
121			return (nil, nil);
122	}
123	nb := int a[ns-1];
124	if((len b)-i != nb){
125		sys->print("unpack: bad message format: wrong nbytes\n");
126		return (nil, nil);
127	}
128	# copy data so b can be reused or freed
129	data := array[nb] of byte;
130	data[0:] = b[i:];
131	return (a, data);
132}
133
134unpackstring(b: array of byte, i: int): (int, string)
135{
136	starti := i;
137	while(i < len b){
138		if(b[i] == byte '\n')
139			return (i+1, string b[starti:i]);
140		i++;
141	}
142	return (-1, nil);
143}
144
145string2attrs(s: string): list of ref Attr
146{
147	(nil, pairs) := sys->tokenize(s, "\t");
148	if(pairs == nil)
149		return nil;
150	attrs: list of ref Attr;
151	while(pairs != nil){
152		pair := hd pairs;
153		pairs = tl pairs;
154		a := ref Attr;
155		for(i:=0; i<len pair; i++)
156			if(pair[i] == '='){
157				a.name = pair[0:i];
158				if(++i < len pair)
159					a.val = pair[i:];
160				break;
161			}
162		attrs = a :: attrs;
163	}
164	return attrs;
165}
166
167attrs2string(l: list of ref Attr): string
168{
169	s := "";
170	while(l != nil){
171		a := hd l;
172		l = tl l;
173		if(s == "")
174			s = a.name + "=" + a.val;
175		else
176			s += "\t" + a.name + "=" + a.val;
177	}
178	return s;
179}
180
181lookup(attrs: list of ref Attr, name: string): (int, string)
182{
183	while(attrs != nil){
184		a := hd attrs;
185		attrs = tl attrs;
186		if(a.name == name)
187			return (1, a.val);
188	}
189	return (0, nil);
190}
191