1*8ccd4a63SDavid du Colombier #include <u.h>
2*8ccd4a63SDavid du Colombier #include <libc.h>
3*8ccd4a63SDavid du Colombier #include <ip.h>
4*8ccd4a63SDavid du Colombier #include <thread.h>
5*8ccd4a63SDavid du Colombier #include "netbios.h"
6*8ccd4a63SDavid du Colombier
7*8ccd4a63SDavid du Colombier static struct {
8*8ccd4a63SDavid du Colombier int thread;
9*8ccd4a63SDavid du Colombier QLock;
10*8ccd4a63SDavid du Colombier char adir[NETPATHLEN];
11*8ccd4a63SDavid du Colombier int acfd;
12*8ccd4a63SDavid du Colombier char ldir[NETPATHLEN];
13*8ccd4a63SDavid du Colombier int lcfd;
14*8ccd4a63SDavid du Colombier } tcp = { -1 };
15*8ccd4a63SDavid du Colombier
16*8ccd4a63SDavid du Colombier typedef struct Session Session;
17*8ccd4a63SDavid du Colombier
18*8ccd4a63SDavid du Colombier enum { NeedSessionRequest, Connected, Dead };
19*8ccd4a63SDavid du Colombier
20*8ccd4a63SDavid du Colombier struct Session {
21*8ccd4a63SDavid du Colombier NbSession;
22*8ccd4a63SDavid du Colombier int thread;
23*8ccd4a63SDavid du Colombier Session *next;
24*8ccd4a63SDavid du Colombier int state;
25*8ccd4a63SDavid du Colombier NBSSWRITEFN *write;
26*8ccd4a63SDavid du Colombier };
27*8ccd4a63SDavid du Colombier
28*8ccd4a63SDavid du Colombier static struct {
29*8ccd4a63SDavid du Colombier QLock;
30*8ccd4a63SDavid du Colombier Session *head;
31*8ccd4a63SDavid du Colombier } sessions;
32*8ccd4a63SDavid du Colombier
33*8ccd4a63SDavid du Colombier typedef struct Listen Listen;
34*8ccd4a63SDavid du Colombier
35*8ccd4a63SDavid du Colombier struct Listen {
36*8ccd4a63SDavid du Colombier NbName to;
37*8ccd4a63SDavid du Colombier NbName from;
38*8ccd4a63SDavid du Colombier int (*accept)(void *magic, NbSession *s, NBSSWRITEFN **writep);
39*8ccd4a63SDavid du Colombier void *magic;
40*8ccd4a63SDavid du Colombier Listen *next;
41*8ccd4a63SDavid du Colombier };
42*8ccd4a63SDavid du Colombier
43*8ccd4a63SDavid du Colombier static struct {
44*8ccd4a63SDavid du Colombier QLock;
45*8ccd4a63SDavid du Colombier Listen *head;
46*8ccd4a63SDavid du Colombier } listens;
47*8ccd4a63SDavid du Colombier
48*8ccd4a63SDavid du Colombier static void
deletesession(Session * s)49*8ccd4a63SDavid du Colombier deletesession(Session *s)
50*8ccd4a63SDavid du Colombier {
51*8ccd4a63SDavid du Colombier Session **sp;
52*8ccd4a63SDavid du Colombier close(s->fd);
53*8ccd4a63SDavid du Colombier qlock(&sessions);
54*8ccd4a63SDavid du Colombier for (sp = &sessions.head; *sp && *sp != s; sp = &(*sp)->next)
55*8ccd4a63SDavid du Colombier ;
56*8ccd4a63SDavid du Colombier if (*sp)
57*8ccd4a63SDavid du Colombier *sp = s->next;
58*8ccd4a63SDavid du Colombier qunlock(&sessions);
59*8ccd4a63SDavid du Colombier free(s);
60*8ccd4a63SDavid du Colombier }
61*8ccd4a63SDavid du Colombier
62*8ccd4a63SDavid du Colombier static void
tcpreader(void * a)63*8ccd4a63SDavid du Colombier tcpreader(void *a)
64*8ccd4a63SDavid du Colombier {
65*8ccd4a63SDavid du Colombier Session *s = a;
66*8ccd4a63SDavid du Colombier uchar *buf;
67*8ccd4a63SDavid du Colombier int buflen = 0x1ffff + 4;
68*8ccd4a63SDavid du Colombier buf = nbemalloc(buflen);
69*8ccd4a63SDavid du Colombier for (;;) {
70*8ccd4a63SDavid du Colombier int n;
71*8ccd4a63SDavid du Colombier uchar flags;
72*8ccd4a63SDavid du Colombier ushort length;
73*8ccd4a63SDavid du Colombier
74*8ccd4a63SDavid du Colombier n = readn(s->fd, buf, 4);
75*8ccd4a63SDavid du Colombier if (n != 4) {
76*8ccd4a63SDavid du Colombier die:
77*8ccd4a63SDavid du Colombier free(buf);
78*8ccd4a63SDavid du Colombier if (s->state == Connected)
79*8ccd4a63SDavid du Colombier (*s->write)(s, nil, -1);
80*8ccd4a63SDavid du Colombier deletesession(s);
81*8ccd4a63SDavid du Colombier return;
82*8ccd4a63SDavid du Colombier }
83*8ccd4a63SDavid du Colombier flags = buf[1];
84*8ccd4a63SDavid du Colombier length = nhgets(buf + 2) | ((flags & 1) << 16);
85*8ccd4a63SDavid du Colombier n = readn(s->fd, buf + 4, length);
86*8ccd4a63SDavid du Colombier if (n != length)
87*8ccd4a63SDavid du Colombier goto die;
88*8ccd4a63SDavid du Colombier if (flags & 0xfe) {
89*8ccd4a63SDavid du Colombier print("nbss: invalid flags field 0x%.2ux\n", flags);
90*8ccd4a63SDavid du Colombier goto die;
91*8ccd4a63SDavid du Colombier }
92*8ccd4a63SDavid du Colombier switch (buf[0]) {
93*8ccd4a63SDavid du Colombier case 0: /* session message */
94*8ccd4a63SDavid du Colombier if (s->state != Connected && s->state != Dead) {
95*8ccd4a63SDavid du Colombier print("nbss: unexpected session message\n");
96*8ccd4a63SDavid du Colombier goto die;
97*8ccd4a63SDavid du Colombier }
98*8ccd4a63SDavid du Colombier if (s->state == Connected) {
99*8ccd4a63SDavid du Colombier if ((*s->write)(s, buf + 4, length) != 0) {
100*8ccd4a63SDavid du Colombier s->state = Dead;
101*8ccd4a63SDavid du Colombier goto die;
102*8ccd4a63SDavid du Colombier }
103*8ccd4a63SDavid du Colombier }
104*8ccd4a63SDavid du Colombier break;
105*8ccd4a63SDavid du Colombier case 0x81: /* session request */ {
106*8ccd4a63SDavid du Colombier uchar *p, *ep;
107*8ccd4a63SDavid du Colombier Listen *l;
108*8ccd4a63SDavid du Colombier int k;
109*8ccd4a63SDavid du Colombier int called_found;
110*8ccd4a63SDavid du Colombier uchar error_code;
111*8ccd4a63SDavid du Colombier
112*8ccd4a63SDavid du Colombier if (s->state == Connected) {
113*8ccd4a63SDavid du Colombier print("nbss: unexpected session request\n");
114*8ccd4a63SDavid du Colombier goto die;
115*8ccd4a63SDavid du Colombier }
116*8ccd4a63SDavid du Colombier p = buf + 4;
117*8ccd4a63SDavid du Colombier ep = p + length;
118*8ccd4a63SDavid du Colombier k = nbnamedecode(p, p, ep, s->to);
119*8ccd4a63SDavid du Colombier if (k == 0) {
120*8ccd4a63SDavid du Colombier print("nbss: malformed called name in session request\n");
121*8ccd4a63SDavid du Colombier goto die;
122*8ccd4a63SDavid du Colombier }
123*8ccd4a63SDavid du Colombier p += k;
124*8ccd4a63SDavid du Colombier k = nbnamedecode(p, p, ep, s->from);
125*8ccd4a63SDavid du Colombier if (k == 0) {
126*8ccd4a63SDavid du Colombier print("nbss: malformed calling name in session request\n");
127*8ccd4a63SDavid du Colombier goto die;
128*8ccd4a63SDavid du Colombier }
129*8ccd4a63SDavid du Colombier /*
130*8ccd4a63SDavid du Colombier p += k;
131*8ccd4a63SDavid du Colombier if (p != ep) {
132*8ccd4a63SDavid du Colombier print("nbss: extra data at end of session request\n");
133*8ccd4a63SDavid du Colombier goto die;
134*8ccd4a63SDavid du Colombier }
135*8ccd4a63SDavid du Colombier */
136*8ccd4a63SDavid du Colombier called_found = 0;
137*8ccd4a63SDavid du Colombier //print("nbss: called %B calling %B\n", s->to, s->from);
138*8ccd4a63SDavid du Colombier qlock(&listens);
139*8ccd4a63SDavid du Colombier for (l = listens.head; l; l = l->next)
140*8ccd4a63SDavid du Colombier if (nbnameequal(l->to, s->to)) {
141*8ccd4a63SDavid du Colombier called_found = 1;
142*8ccd4a63SDavid du Colombier if (nbnameequal(l->from, s->from))
143*8ccd4a63SDavid du Colombier break;
144*8ccd4a63SDavid du Colombier }
145*8ccd4a63SDavid du Colombier if (l == nil) {
146*8ccd4a63SDavid du Colombier qunlock(&listens);
147*8ccd4a63SDavid du Colombier error_code = called_found ? 0x81 : 0x80;
148*8ccd4a63SDavid du Colombier replydie:
149*8ccd4a63SDavid du Colombier buf[0] = 0x83;
150*8ccd4a63SDavid du Colombier buf[1] = 0;
151*8ccd4a63SDavid du Colombier hnputs(buf + 2, 1);
152*8ccd4a63SDavid du Colombier buf[4] = error_code;
153*8ccd4a63SDavid du Colombier write(s->fd, buf, 5);
154*8ccd4a63SDavid du Colombier goto die;
155*8ccd4a63SDavid du Colombier }
156*8ccd4a63SDavid du Colombier if (!(*l->accept)(l->magic, s, &s->write)) {
157*8ccd4a63SDavid du Colombier qunlock(&listens);
158*8ccd4a63SDavid du Colombier error_code = 0x83;
159*8ccd4a63SDavid du Colombier goto replydie;
160*8ccd4a63SDavid du Colombier }
161*8ccd4a63SDavid du Colombier buf[0] = 0x82;
162*8ccd4a63SDavid du Colombier buf[1] = 0;
163*8ccd4a63SDavid du Colombier hnputs(buf + 2, 0);
164*8ccd4a63SDavid du Colombier if (write(s->fd, buf, 4) != 4) {
165*8ccd4a63SDavid du Colombier qunlock(&listens);
166*8ccd4a63SDavid du Colombier goto die;
167*8ccd4a63SDavid du Colombier }
168*8ccd4a63SDavid du Colombier s->state = Connected;
169*8ccd4a63SDavid du Colombier qunlock(&listens);
170*8ccd4a63SDavid du Colombier break;
171*8ccd4a63SDavid du Colombier }
172*8ccd4a63SDavid du Colombier case 0x85: /* keep awake */
173*8ccd4a63SDavid du Colombier break;
174*8ccd4a63SDavid du Colombier default:
175*8ccd4a63SDavid du Colombier print("nbss: opcode 0x%.2ux unexpected\n", buf[0]);
176*8ccd4a63SDavid du Colombier goto die;
177*8ccd4a63SDavid du Colombier }
178*8ccd4a63SDavid du Colombier }
179*8ccd4a63SDavid du Colombier }
180*8ccd4a63SDavid du Colombier
181*8ccd4a63SDavid du Colombier static NbSession *
createsession(int fd)182*8ccd4a63SDavid du Colombier createsession(int fd)
183*8ccd4a63SDavid du Colombier {
184*8ccd4a63SDavid du Colombier Session *s;
185*8ccd4a63SDavid du Colombier s = nbemalloc(sizeof(Session));
186*8ccd4a63SDavid du Colombier s->fd = fd;
187*8ccd4a63SDavid du Colombier s->state = NeedSessionRequest;
188*8ccd4a63SDavid du Colombier qlock(&sessions);
189*8ccd4a63SDavid du Colombier s->thread = procrfork(tcpreader, s, 32768, RFNAMEG);
190*8ccd4a63SDavid du Colombier if (s->thread < 0) {
191*8ccd4a63SDavid du Colombier qunlock(&sessions);
192*8ccd4a63SDavid du Colombier free(s);
193*8ccd4a63SDavid du Colombier return nil;
194*8ccd4a63SDavid du Colombier }
195*8ccd4a63SDavid du Colombier s->next = sessions.head;
196*8ccd4a63SDavid du Colombier sessions.head = s;
197*8ccd4a63SDavid du Colombier qunlock(&sessions);
198*8ccd4a63SDavid du Colombier return s;
199*8ccd4a63SDavid du Colombier }
200*8ccd4a63SDavid du Colombier
201*8ccd4a63SDavid du Colombier static void
tcplistener(void *)202*8ccd4a63SDavid du Colombier tcplistener(void *)
203*8ccd4a63SDavid du Colombier {
204*8ccd4a63SDavid du Colombier for (;;) {
205*8ccd4a63SDavid du Colombier int dfd;
206*8ccd4a63SDavid du Colombier char ldir[NETPATHLEN];
207*8ccd4a63SDavid du Colombier int lcfd;
208*8ccd4a63SDavid du Colombier //print("tcplistener: listening\n");
209*8ccd4a63SDavid du Colombier lcfd = listen(tcp.adir, ldir);
210*8ccd4a63SDavid du Colombier //print("tcplistener: contact\n");
211*8ccd4a63SDavid du Colombier if (lcfd < 0) {
212*8ccd4a63SDavid du Colombier die:
213*8ccd4a63SDavid du Colombier qlock(&tcp);
214*8ccd4a63SDavid du Colombier close(tcp.acfd);
215*8ccd4a63SDavid du Colombier tcp.thread = -1;
216*8ccd4a63SDavid du Colombier qunlock(&tcp);
217*8ccd4a63SDavid du Colombier return;
218*8ccd4a63SDavid du Colombier }
219*8ccd4a63SDavid du Colombier dfd = accept(lcfd, ldir);
220*8ccd4a63SDavid du Colombier close(lcfd);
221*8ccd4a63SDavid du Colombier if (dfd < 0)
222*8ccd4a63SDavid du Colombier goto die;
223*8ccd4a63SDavid du Colombier if (createsession(dfd) == nil)
224*8ccd4a63SDavid du Colombier close(dfd);
225*8ccd4a63SDavid du Colombier }
226*8ccd4a63SDavid du Colombier }
227*8ccd4a63SDavid du Colombier
228*8ccd4a63SDavid du Colombier int
nbsslisten(NbName to,NbName from,int (* accept)(void * magic,NbSession * s,NBSSWRITEFN ** writep),void * magic)229*8ccd4a63SDavid du Colombier nbsslisten(NbName to, NbName from,int (*accept)(void *magic, NbSession *s, NBSSWRITEFN **writep), void *magic)
230*8ccd4a63SDavid du Colombier {
231*8ccd4a63SDavid du Colombier Listen *l;
232*8ccd4a63SDavid du Colombier qlock(&tcp);
233*8ccd4a63SDavid du Colombier if (tcp.thread < 0) {
234*8ccd4a63SDavid du Colombier fmtinstall('B', nbnamefmt);
235*8ccd4a63SDavid du Colombier tcp.acfd = announce("tcp!*!netbios", tcp.adir);
236*8ccd4a63SDavid du Colombier if (tcp.acfd < 0) {
237*8ccd4a63SDavid du Colombier print("nbsslisten: can't announce: %r\n");
238*8ccd4a63SDavid du Colombier qunlock(&tcp);
239*8ccd4a63SDavid du Colombier return -1;
240*8ccd4a63SDavid du Colombier }
241*8ccd4a63SDavid du Colombier tcp.thread = proccreate(tcplistener, nil, 16384);
242*8ccd4a63SDavid du Colombier }
243*8ccd4a63SDavid du Colombier qunlock(&tcp);
244*8ccd4a63SDavid du Colombier l = nbemalloc(sizeof(Listen));
245*8ccd4a63SDavid du Colombier nbnamecpy(l->to, to);
246*8ccd4a63SDavid du Colombier nbnamecpy(l->from, from);
247*8ccd4a63SDavid du Colombier l->accept = accept;
248*8ccd4a63SDavid du Colombier l->magic = magic;
249*8ccd4a63SDavid du Colombier qlock(&listens);
250*8ccd4a63SDavid du Colombier l->next = listens.head;
251*8ccd4a63SDavid du Colombier listens.head = l;
252*8ccd4a63SDavid du Colombier qunlock(&listens);
253*8ccd4a63SDavid du Colombier return 0;
254*8ccd4a63SDavid du Colombier }
255*8ccd4a63SDavid du Colombier
256*8ccd4a63SDavid du Colombier void
nbssfree(NbSession * s)257*8ccd4a63SDavid du Colombier nbssfree(NbSession *s)
258*8ccd4a63SDavid du Colombier {
259*8ccd4a63SDavid du Colombier deletesession((Session *)s);
260*8ccd4a63SDavid du Colombier }
261*8ccd4a63SDavid du Colombier
262*8ccd4a63SDavid du Colombier int
nbssgatherwrite(NbSession * s,NbScatterGather * a)263*8ccd4a63SDavid du Colombier nbssgatherwrite(NbSession *s, NbScatterGather *a)
264*8ccd4a63SDavid du Colombier {
265*8ccd4a63SDavid du Colombier uchar hdr[4];
266*8ccd4a63SDavid du Colombier NbScatterGather *ap;
267*8ccd4a63SDavid du Colombier long l = 0;
268*8ccd4a63SDavid du Colombier for (ap = a; ap->p; ap++)
269*8ccd4a63SDavid du Colombier l += ap->l;
270*8ccd4a63SDavid du Colombier //print("nbssgatherwrite %ld bytes\n", l);
271*8ccd4a63SDavid du Colombier hnputl(hdr, l);
272*8ccd4a63SDavid du Colombier //nbdumpdata(hdr, sizeof(hdr));
273*8ccd4a63SDavid du Colombier if (write(s->fd, hdr, sizeof(hdr)) != sizeof(hdr))
274*8ccd4a63SDavid du Colombier return -1;
275*8ccd4a63SDavid du Colombier for (ap = a; ap->p; ap++) {
276*8ccd4a63SDavid du Colombier //nbdumpdata(ap->p, ap->l);
277*8ccd4a63SDavid du Colombier if (write(s->fd, ap->p, ap->l) != ap->l)
278*8ccd4a63SDavid du Colombier return -1;
279*8ccd4a63SDavid du Colombier }
280*8ccd4a63SDavid du Colombier return 0;
281*8ccd4a63SDavid du Colombier }
282*8ccd4a63SDavid du Colombier
283*8ccd4a63SDavid du Colombier NbSession *
nbssconnect(NbName to,NbName from)284*8ccd4a63SDavid du Colombier nbssconnect(NbName to, NbName from)
285*8ccd4a63SDavid du Colombier {
286*8ccd4a63SDavid du Colombier Session *s;
287*8ccd4a63SDavid du Colombier uchar ipaddr[IPaddrlen];
288*8ccd4a63SDavid du Colombier char dialaddress[100];
289*8ccd4a63SDavid du Colombier char dir[NETPATHLEN];
290*8ccd4a63SDavid du Colombier uchar msg[576];
291*8ccd4a63SDavid du Colombier int fd;
292*8ccd4a63SDavid du Colombier long o;
293*8ccd4a63SDavid du Colombier uchar flags;
294*8ccd4a63SDavid du Colombier long length;
295*8ccd4a63SDavid du Colombier
296*8ccd4a63SDavid du Colombier if (!nbnameresolve(to, ipaddr))
297*8ccd4a63SDavid du Colombier return nil;
298*8ccd4a63SDavid du Colombier fmtinstall('I', eipfmt);
299*8ccd4a63SDavid du Colombier snprint(dialaddress, sizeof(dialaddress), "tcp!%I!netbios", ipaddr);
300*8ccd4a63SDavid du Colombier fd = dial(dialaddress, nil, dir, nil);
301*8ccd4a63SDavid du Colombier if (fd < 0)
302*8ccd4a63SDavid du Colombier return nil;
303*8ccd4a63SDavid du Colombier msg[0] = 0x81;
304*8ccd4a63SDavid du Colombier msg[1] = 0;
305*8ccd4a63SDavid du Colombier o = 4;
306*8ccd4a63SDavid du Colombier o += nbnameencode(msg + o, msg + sizeof(msg) - o, to);
307*8ccd4a63SDavid du Colombier o += nbnameencode(msg + o, msg + sizeof(msg) - o, from);
308*8ccd4a63SDavid du Colombier hnputs(msg + 2, o - 4);
309*8ccd4a63SDavid du Colombier if (write(fd, msg, o) != o) {
310*8ccd4a63SDavid du Colombier close(fd);
311*8ccd4a63SDavid du Colombier return nil;
312*8ccd4a63SDavid du Colombier }
313*8ccd4a63SDavid du Colombier if (readn(fd, msg, 4) != 4) {
314*8ccd4a63SDavid du Colombier close(fd);
315*8ccd4a63SDavid du Colombier return nil;
316*8ccd4a63SDavid du Colombier }
317*8ccd4a63SDavid du Colombier flags = msg[1];
318*8ccd4a63SDavid du Colombier length = nhgets(msg + 2) | ((flags & 1) << 16);
319*8ccd4a63SDavid du Colombier switch (msg[0]) {
320*8ccd4a63SDavid du Colombier default:
321*8ccd4a63SDavid du Colombier close(fd);
322*8ccd4a63SDavid du Colombier werrstr("unexpected session message code 0x%.2ux", msg[0]);
323*8ccd4a63SDavid du Colombier return nil;
324*8ccd4a63SDavid du Colombier case 0x82:
325*8ccd4a63SDavid du Colombier if (length != 0) {
326*8ccd4a63SDavid du Colombier close(fd);
327*8ccd4a63SDavid du Colombier werrstr("length not 0 in positive session response");
328*8ccd4a63SDavid du Colombier return nil;
329*8ccd4a63SDavid du Colombier }
330*8ccd4a63SDavid du Colombier break;
331*8ccd4a63SDavid du Colombier case 0x83:
332*8ccd4a63SDavid du Colombier if (length != 1) {
333*8ccd4a63SDavid du Colombier close(fd);
334*8ccd4a63SDavid du Colombier werrstr("length not 1 in negative session response");
335*8ccd4a63SDavid du Colombier return nil;
336*8ccd4a63SDavid du Colombier }
337*8ccd4a63SDavid du Colombier if (readn(fd, msg + 4, 1) != 1) {
338*8ccd4a63SDavid du Colombier close(fd);
339*8ccd4a63SDavid du Colombier return nil;
340*8ccd4a63SDavid du Colombier }
341*8ccd4a63SDavid du Colombier close(fd);
342*8ccd4a63SDavid du Colombier werrstr("negative session response 0x%.2ux", msg[4]);
343*8ccd4a63SDavid du Colombier return nil;
344*8ccd4a63SDavid du Colombier }
345*8ccd4a63SDavid du Colombier s = nbemalloc(sizeof(Session));
346*8ccd4a63SDavid du Colombier s->fd = fd;
347*8ccd4a63SDavid du Colombier s->state = Connected;
348*8ccd4a63SDavid du Colombier qlock(&sessions);
349*8ccd4a63SDavid du Colombier s->next = sessions.head;
350*8ccd4a63SDavid du Colombier sessions.head = s;
351*8ccd4a63SDavid du Colombier qunlock(&sessions);
352*8ccd4a63SDavid du Colombier return s;
353*8ccd4a63SDavid du Colombier }
354*8ccd4a63SDavid du Colombier
355*8ccd4a63SDavid du Colombier long
nbssscatterread(NbSession * nbs,NbScatterGather * a)356*8ccd4a63SDavid du Colombier nbssscatterread(NbSession *nbs, NbScatterGather *a)
357*8ccd4a63SDavid du Colombier {
358*8ccd4a63SDavid du Colombier uchar hdr[4];
359*8ccd4a63SDavid du Colombier uchar flags;
360*8ccd4a63SDavid du Colombier long length, total;
361*8ccd4a63SDavid du Colombier NbScatterGather *ap;
362*8ccd4a63SDavid du Colombier Session *s = (Session *)nbs;
363*8ccd4a63SDavid du Colombier
364*8ccd4a63SDavid du Colombier long l = 0;
365*8ccd4a63SDavid du Colombier for (ap = a; ap->p; ap++)
366*8ccd4a63SDavid du Colombier l += ap->l;
367*8ccd4a63SDavid du Colombier //print("nbssscatterread %ld bytes\n", l);
368*8ccd4a63SDavid du Colombier again:
369*8ccd4a63SDavid du Colombier if (readn(s->fd, hdr, 4) != 4) {
370*8ccd4a63SDavid du Colombier dead:
371*8ccd4a63SDavid du Colombier s->state = Dead;
372*8ccd4a63SDavid du Colombier return -1;
373*8ccd4a63SDavid du Colombier }
374*8ccd4a63SDavid du Colombier flags = hdr[1];
375*8ccd4a63SDavid du Colombier length = nhgets(hdr + 2) | ((flags & 1) << 16);
376*8ccd4a63SDavid du Colombier //print("%.2ux: %d\n", hdr[0], length);
377*8ccd4a63SDavid du Colombier switch (hdr[0]) {
378*8ccd4a63SDavid du Colombier case 0x85:
379*8ccd4a63SDavid du Colombier if (length != 0) {
380*8ccd4a63SDavid du Colombier werrstr("length in keepalive not 0");
381*8ccd4a63SDavid du Colombier goto dead;
382*8ccd4a63SDavid du Colombier }
383*8ccd4a63SDavid du Colombier goto again;
384*8ccd4a63SDavid du Colombier case 0x00:
385*8ccd4a63SDavid du Colombier break;
386*8ccd4a63SDavid du Colombier default:
387*8ccd4a63SDavid du Colombier werrstr("unexpected session message code 0x%.2ux", hdr[0]);
388*8ccd4a63SDavid du Colombier goto dead;
389*8ccd4a63SDavid du Colombier }
390*8ccd4a63SDavid du Colombier if (length > l) {
391*8ccd4a63SDavid du Colombier werrstr("message too big (%ld)", length);
392*8ccd4a63SDavid du Colombier goto dead;
393*8ccd4a63SDavid du Colombier }
394*8ccd4a63SDavid du Colombier total = length;
395*8ccd4a63SDavid du Colombier for (ap = a; length && ap->p; ap++) {
396*8ccd4a63SDavid du Colombier long thistime;
397*8ccd4a63SDavid du Colombier long n;
398*8ccd4a63SDavid du Colombier thistime = length;
399*8ccd4a63SDavid du Colombier if (thistime > ap->l)
400*8ccd4a63SDavid du Colombier thistime = ap->l;
401*8ccd4a63SDavid du Colombier //print("reading %d\n", length);
402*8ccd4a63SDavid du Colombier n = readn(s->fd, ap->p, thistime);
403*8ccd4a63SDavid du Colombier if (n != thistime)
404*8ccd4a63SDavid du Colombier goto dead;
405*8ccd4a63SDavid du Colombier length -= thistime;
406*8ccd4a63SDavid du Colombier }
407*8ccd4a63SDavid du Colombier return total;
408*8ccd4a63SDavid du Colombier }
409*8ccd4a63SDavid du Colombier
410*8ccd4a63SDavid du Colombier int
nbsswrite(NbSession * s,void * buf,long maxlen)411*8ccd4a63SDavid du Colombier nbsswrite(NbSession *s, void *buf, long maxlen)
412*8ccd4a63SDavid du Colombier {
413*8ccd4a63SDavid du Colombier NbScatterGather a[2];
414*8ccd4a63SDavid du Colombier a[0].l = maxlen;
415*8ccd4a63SDavid du Colombier a[0].p = buf;
416*8ccd4a63SDavid du Colombier a[1].p = nil;
417*8ccd4a63SDavid du Colombier return nbssgatherwrite(s, a);
418*8ccd4a63SDavid du Colombier }
419*8ccd4a63SDavid du Colombier
420*8ccd4a63SDavid du Colombier long
nbssread(NbSession * s,void * buf,long maxlen)421*8ccd4a63SDavid du Colombier nbssread(NbSession *s, void *buf, long maxlen)
422*8ccd4a63SDavid du Colombier {
423*8ccd4a63SDavid du Colombier NbScatterGather a[2];
424*8ccd4a63SDavid du Colombier a[0].l = maxlen;
425*8ccd4a63SDavid du Colombier a[0].p = buf;
426*8ccd4a63SDavid du Colombier a[1].p = nil;
427*8ccd4a63SDavid du Colombier return nbssscatterread(s, a);
428*8ccd4a63SDavid du Colombier }
429