xref: /plan9/sys/src/cmd/aquarela/nbss.c (revision 8ccd4a6360d974db7bd7bbd4f37e7018419ea908)
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