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