Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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
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
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 *
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
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
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