xref: /plan9-contrib/sys/src/cmd/aquarela/smblisten.c (revision 8ccd4a6360d974db7bd7bbd4f37e7018419ea908)
1 #include "headers.h"
2 
3 static struct {
4 	int thread;
5 	QLock;
6 	char adir[NETPATHLEN];
7 	int acfd;
8 	char ldir[NETPATHLEN];
9 	int lcfd;
10 	SMBCIFSACCEPTFN *accept;
11 } tcp = { -1 };
12 
13 typedef struct Session Session;
14 
15 enum { Connected, Dead };
16 
17 struct Session {
18 	SmbCifsSession;
19 	int thread;
20 	Session *next;
21 	int state;
22 	SMBCIFSWRITEFN *write;
23 };
24 
25 static struct {
26 	QLock;
27 	Session *head;
28 } sessions;
29 
30 typedef struct Listen Listen;
31 
32 static void
deletesession(Session * s)33 deletesession(Session *s)
34 {
35 	Session **sp;
36 	close(s->fd);
37 	qlock(&sessions);
38 	for (sp = &sessions.head; *sp && *sp != s; sp = &(*sp)->next)
39 		;
40 	if (*sp)
41 		*sp = s->next;
42 	qunlock(&sessions);
43 	free(s);
44 }
45 
46 static void
tcpreader(void * a)47 tcpreader(void *a)
48 {
49 	Session *s = a;
50 	uchar *buf;
51 	int buflen = smbglobals.maxreceive + 4;
52 	buf = nbemalloc(buflen);
53 	for (;;) {
54 		int n;
55 		uchar flags;
56 		ushort length;
57 
58 		n = readn(s->fd, buf, 4);
59 		if (n != 4) {
60 		die:
61 			free(buf);
62 			if (s->state == Connected)
63 				(*s->write)(s, nil, -1);
64 			deletesession(s);
65 			return;
66 		}
67 		flags = buf[1];
68 		length = nhgets(buf + 2) | ((flags & 1) << 16);
69 		if (length > buflen - 4) {
70 			print("nbss: too much data (%ud)\n", length);
71 			goto die;
72 		}
73 		n = readn(s->fd, buf + 4, length);
74 		if (n != length)
75 			goto die;
76 		if (s->state == Connected) {
77 			if ((*s->write)(s, buf + 4, length) != 0) {
78 				s->state = Dead;
79 				goto die;
80 			}
81 		}
82 	}
83 }
84 
85 static Session *
createsession(int fd)86 createsession(int fd)
87 {
88 	Session *s;
89 	s = smbemalloc(sizeof(Session));
90 	s->fd = fd;
91 	s->state = Connected;
92 	qlock(&sessions);
93 	if (!(*tcp.accept)(s, &s->write)) {
94 		qunlock(&sessions);
95 		free(s);
96 		return nil;
97 	}
98 	s->thread = procrfork(tcpreader, s, 32768, RFNAMEG);
99 	if (s->thread < 0) {
100 		qunlock(&sessions);
101 		(*s->write)(s, nil, -1);
102 		free(s);
103 		return nil;
104 	}
105 	s->next = sessions.head;
106 	sessions.head = s;
107 	qunlock(&sessions);
108 	return s;
109 }
110 
111 static void
tcplistener(void *)112 tcplistener(void *)
113 {
114 	for (;;) {
115 		int dfd;
116 		char ldir[NETPATHLEN];
117 		int lcfd;
118 //print("cifstcplistener: listening\n");
119 		lcfd = listen(tcp.adir, ldir);
120 //print("cifstcplistener: contact\n");
121 		if (lcfd < 0) {
122 		die:
123 			qlock(&tcp);
124 			close(tcp.acfd);
125 			tcp.thread = -1;
126 			qunlock(&tcp);
127 			return;
128 		}
129 		dfd = accept(lcfd, ldir);
130 		close(lcfd);
131 		if (dfd < 0)
132 			goto die;
133 		if (createsession(dfd) == nil)
134 			close(dfd);
135 	}
136 }
137 
138 int
smblistencifs(SMBCIFSACCEPTFN * accept)139 smblistencifs(SMBCIFSACCEPTFN *accept)
140 {
141 	qlock(&tcp);
142 	if (tcp.thread < 0) {
143 		tcp.acfd = announce("tcp!*!cifs", tcp.adir);
144 		if (tcp.acfd < 0) {
145 			print("smblistentcp: can't announce: %r\n");
146 			qunlock(&tcp);
147 			return -1;
148 		}
149 		tcp.thread = proccreate(tcplistener, nil, 16384);
150 	}
151 	tcp.accept = accept;
152 	qunlock(&tcp);
153 	return 0;
154 }
155