xref: /plan9/sys/src/cmd/aquarela/nbdgram.c (revision 8ccd4a6360d974db7bd7bbd4f37e7018419ea908)
1 #include <u.h>
2 #include <libc.h>
3 #include <ip.h>
4 #include <thread.h>
5 #include "netbios.h"
6 
7 static struct {
8 	int thread;
9 	QLock;
10 	int fd;
11 } udp = { -1 };
12 
13 typedef struct Listen Listen;
14 
15 struct Listen {
16 	NbName to;
17 	int (*deliver)(void *magic, NbDgram *s);
18 	void *magic;
19 	Listen *next;
20 };
21 
22 static struct {
23 	QLock;
24 	Listen *head;
25 } listens;
26 
27 static void
udplistener(void *)28 udplistener(void *)
29 {
30 //print("udplistener - starting\n");
31 	for (;;) {
32 		uchar msg[Udphdrsize + 576];
33 		int len = read(udp.fd, msg, sizeof(msg));
34 		if (len < 0)
35 			break;
36 		if (len >= nbudphdrsize) {
37 			NbDgram s;
38 //			Udphdr *uh;
39 			uchar *p;
40 			int n;
41 
42 //			uh = (Udphdr*)msg;
43 			p = msg + nbudphdrsize;
44 			len -= nbudphdrsize;
45 			n = nbdgramconvM2S(&s, p, p + len);
46 			if (n) {
47 				switch (s.type) {
48 				case NbDgramError:
49 					print("nbdgramlisten: error: ip %I port %d code 0x%.2ux\n", s.srcip, s.srcport, s.error.code);
50 					break;
51 				case NbDgramDirectUnique:
52 				case NbDgramDirectGroup:
53 				case NbDgramBroadcast: {
54 					int delivered = 0;
55 					Listen **lp, *l;
56 					if ((s.flags & NbDgramMore) || s.datagram.offset != 0)
57 						break;
58 					if (!nbnameisany(s.datagram.dstname)
59 						&& !nbnametablefind(s.datagram.dstname, 0)) {
60 /* - only do this if a broadcast node, and can tell when packets are broadcast...
61 						s.flags &= 3;
62 						ipmove(s.srcip, nbglobals.myipaddr);
63 						s.srcport = NbDgramPort;
64 						s.type = NbDgramError;
65 						s.error.code = NbDgramErrorDestinationNameNotPresent;
66 						nbdgramsendto(uh->raddr, nhgets(uh->rport), &s);
67 */
68 						break;
69 					}
70 					qlock(&listens);
71 					for (lp = &listens.head; (l = *lp) != nil;) {
72 						if (nbnameisany(l->to) || nbnameequal(l->to, s.datagram.dstname)) {
73 							switch ((*l->deliver)(l->magic, &s)) {
74 							case 0:
75 								delivered = 1;
76 								/* fall through */
77 							case -1:
78 								*lp = l->next;
79 								free(l);
80 								continue;
81 							default:
82 								delivered = 1;
83 								break;
84 							}
85 						}
86 						lp = &l->next;
87 					}
88 					qunlock(&listens);
89 					USED(delivered);
90 				}
91 				default:
92 					;
93 				}
94 			}
95 		}
96 	}
97 print("udplistener - exiting\n");
98 	qlock(&udp);
99 	udp.thread = -1;
100 	qunlock(&udp);
101 }
102 
103 static char *
startlistener(void)104 startlistener(void)
105 {
106 	qlock(&udp);
107 	if (udp.thread < 0) {
108 		char *e;
109 		e = nbudpannounce(NbDgramPort, &udp.fd);
110 		if (e) {
111 			qunlock(&udp);
112 			return e;
113 		}
114 		udp.thread = proccreate(udplistener, nil, 16384);
115 	}
116 	qunlock(&udp);
117 	return nil;
118 }
119 
120 char *
nbdgramlisten(NbName to,int (* deliver)(void * magic,NbDgram * s),void * magic)121 nbdgramlisten(NbName to, int (*deliver)(void *magic, NbDgram *s), void *magic)
122 {
123 	Listen *l;
124 	char *e;
125 	nbnametablefind(to, 1);
126 	e = startlistener();
127 	if (e)
128 		return e;
129 	l = nbemalloc(sizeof(Listen));
130 	nbnamecpy(l->to, to);
131 	l->deliver = deliver;
132 	l->magic = magic;
133 	qlock(&listens);
134 	l->next = listens.head;
135 	listens.head = l;
136 	qunlock(&listens);
137 	return 0;
138 }
139 
140 int
nbdgramsendto(uchar * ipaddr,ushort port,NbDgram * s)141 nbdgramsendto(uchar *ipaddr, ushort port, NbDgram *s)
142 {
143 	Udphdr *u;
144 	uchar msg[NbDgramMaxPacket + Udphdrsize];
145 	int l;
146 	int rv;
147 	char *e;
148 
149 	e = startlistener();
150 	if (e != nil)
151 		return 0;
152 
153 	l = nbdgramconvS2M(msg + nbudphdrsize, msg + sizeof(msg), s);
154 	if (l == 0) {
155 		print("conv failed\n");
156 		return 0;
157 	}
158 	u = (Udphdr *)msg;
159 	ipmove(u->laddr, nbglobals.myipaddr);
160 	hnputs(u->lport, NbDgramPort);
161 	ipmove(u->raddr, ipaddr);
162 	hnputs(u->rport, port);
163 //nbdumpdata(msg, l + nbudphdrsize);
164 //print("transmitting\n");
165 	rv = write(udp.fd, msg, l + nbudphdrsize);
166 //print("rv %d l %d hdrsize %d error %r\n", rv, l, nbudphdrsize);
167 	return rv == l + nbudphdrsize;
168 }
169 
170 static struct {
171 	Lock;
172 	ushort id;
173 } id;
174 
175 static ushort
nextdgramid(void)176 nextdgramid(void)
177 {
178 	ushort v;
179 	lock(&id);
180 	v = id.id++;
181 	unlock(&id);
182 	return v;
183 }
184 
185 int
nbdgramsend(NbDgramSendParameters * p,uchar * data,long datalen)186 nbdgramsend(NbDgramSendParameters *p, uchar *data, long datalen)
187 {
188 	NbDgram s;
189 	uchar dstip[IPaddrlen];
190 	s.type = p->type;
191 	switch (p->type) {
192 	case NbDgramBroadcast:
193 	case NbDgramDirectGroup:
194 		ipmove(dstip, nbglobals.bcastaddr);
195 		break;
196 	case NbDgramDirectUnique:
197 		if (!nbnameresolve(p->to, dstip)) {
198 			werrstr("nbdgramsend: name resolution failed");
199 			return 0;
200 		}
201 		break;
202 	default:
203 		werrstr("nbdgramsend: illegal datagram type");
204 		return 0;
205 	}
206 	s.flags = NbDgramFirst;
207 	s.id = nextdgramid();
208 	ipmove(s.srcip, nbglobals.myipaddr);
209 	s.srcport = NbDgramPort;
210 	s.datagram.offset = 0;
211 	s.datagram.data = data;
212 	s.datagram.length = datalen;
213 	nbnamecpy(s.datagram.dstname, p->to);
214 	nbnamecpy(s.datagram.srcname, nbglobals.myname);
215 	return nbdgramsendto(dstip, NbDgramPort, &s);
216 }
217