xref: /plan9/sys/src/cmd/aquarela/nbns.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 	Lock;
24 	ushort id;
25 } id;
26 
27 struct {
28 	QLock;
29 	NbnsTransaction *head;
30 } transactionlist;
31 
32 static void
udplistener(void *)33 udplistener(void *)
34 {
35 	for (;;) {
36 		uchar msg[Udphdrsize + 576];
37 		int len = read(udp.fd, msg, sizeof(msg));
38 		if (len < 0)
39 			break;
40 		if (len >= nbudphdrsize) {
41 			NbnsMessage *s;
42 //			Udphdr *uh;
43 			uchar *p;
44 
45 //			uh = (Udphdr*)msg;
46 			p = msg + nbudphdrsize;
47 			len -= nbudphdrsize;
48 			s = nbnsconvM2S(p, len);
49 			if (s) {
50 //print("%I:%d -> %I:%d\n", uh->raddr, nhgets(uh->rport), uh->laddr, nhgets(uh->lport));
51 //nbnsdumpmessage(s);
52 				if (s->response) {
53 					NbnsTransaction *t;
54 					qlock(&transactionlist);
55 					for (t = transactionlist.head; t; t = t->next)
56 						if (t->id == s->id)
57 							break;
58 					if (t)
59 						sendp(t->c, s);
60 					else
61 						nbnsmessagefree(&s);
62 					qunlock(&transactionlist);
63 				}
64 				else
65 					nbnsmessagefree(&s);
66 			}
67 		}
68 	}
69 }
70 
71 static char *
startlistener(void)72 startlistener(void)
73 {
74 	qlock(&udp);
75 	if (udp.thread < 0) {
76 		char *e;
77 		e = nbudpannounce(NbnsPort, &udp.fd);
78 		if (e) {
79 			qunlock(&udp);
80 			return e;
81 		}
82 		udp.thread = proccreate(udplistener, nil, 16384);
83 	}
84 	qunlock(&udp);
85 	return nil;
86 }
87 
88 ushort
nbnsnextid(void)89 nbnsnextid(void)
90 {
91 	ushort rv;
92 	lock(&id);
93 	rv = id.id++;
94 	unlock(&id);
95 	return rv;
96 }
97 
98 NbnsTransaction *
nbnstransactionnew(NbnsMessage * s,uchar * ipaddr)99 nbnstransactionnew(NbnsMessage *s, uchar *ipaddr)
100 {
101 	NbnsTransaction *t;
102 	uchar msg[Udphdrsize + 576];
103 	Udphdr *u;
104 	int len;
105 
106 	startlistener();
107 	len = nbnsconvS2M(s, msg + nbudphdrsize, sizeof(msg) - nbudphdrsize);
108 	if (len == 0)
109 		return 0;
110 	t = mallocz(sizeof(*t), 1);
111 	if (t == nil)
112 		return nil;
113 	t->id = s->id;
114 	t->c = chancreate(sizeof(NbnsMessage *), 3);
115 	if (t->c == nil) {
116 		free(t);
117 		return nil;
118 	}
119 	qlock(&transactionlist);
120 	t->next = transactionlist.head;
121 	transactionlist.head = t;
122 	qunlock(&transactionlist);
123 	u = (Udphdr *)msg;
124 	ipmove(u->laddr, nbglobals.myipaddr);
125 	hnputs(u->lport, NbnsPort);
126 	if (s->broadcast || ipaddr == nil)
127 		ipmove(u->raddr, nbglobals.bcastaddr);
128 	else
129 		ipmove(u->raddr, ipaddr);
130 	hnputs(u->rport, NbnsPort);
131 	write(udp.fd, msg, len + nbudphdrsize);
132 	return t;
133 }
134 
135 void
nbnstransactionfree(NbnsTransaction ** tp)136 nbnstransactionfree(NbnsTransaction **tp)
137 {
138 	NbnsTransaction **tp2;
139 	NbnsMessage *s;
140 	NbnsTransaction *t;
141 
142 	t = *tp;
143 	if (t) {
144 		qlock(&transactionlist);
145 		while ((s = nbrecvp(t->c)) != nil)
146 			nbnsmessagefree(&s);
147 		for (tp2 = &transactionlist.head; *tp2 && *tp2 != t; tp2 = &(*tp2)->next)
148 			;
149 		if (*tp2) {
150 			*tp2 = t->next;
151 			free(t);
152 		}
153 		qunlock(&transactionlist);
154 		*tp = nil;
155 	}
156 }
157