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