#include #include #include #include #include "netbios.h" static struct { int thread; QLock; int fd; } udp = { -1 }; typedef struct Listen Listen; struct Listen { NbName to; int (*deliver)(void *magic, NbDgram *s); void *magic; Listen *next; }; static struct { Lock; ushort id; } id; struct { QLock; NbnsTransaction *head; } transactionlist; static void udplistener(void *) { for (;;) { uchar msg[Udphdrsize + 576]; int len = read(udp.fd, msg, sizeof(msg)); if (len < 0) break; if (len >= nbudphdrsize) { NbnsMessage *s; // Udphdr *uh; uchar *p; // uh = (Udphdr*)msg; p = msg + nbudphdrsize; len -= nbudphdrsize; s = nbnsconvM2S(p, len); if (s) { //print("%I:%d -> %I:%d\n", uh->raddr, nhgets(uh->rport), uh->laddr, nhgets(uh->lport)); //nbnsdumpmessage(s); if (s->response) { NbnsTransaction *t; qlock(&transactionlist); for (t = transactionlist.head; t; t = t->next) if (t->id == s->id) break; if (t) sendp(t->c, s); else nbnsmessagefree(&s); qunlock(&transactionlist); } else nbnsmessagefree(&s); } } } } static char * startlistener(void) { qlock(&udp); if (udp.thread < 0) { char *e; e = nbudpannounce(NbnsPort, &udp.fd); if (e) { qunlock(&udp); return e; } udp.thread = proccreate(udplistener, nil, 16384); } qunlock(&udp); return nil; } ushort nbnsnextid(void) { ushort rv; lock(&id); rv = id.id++; unlock(&id); return rv; } NbnsTransaction * nbnstransactionnew(NbnsMessage *s, uchar *ipaddr) { NbnsTransaction *t; uchar msg[Udphdrsize + 576]; Udphdr *u; int len; startlistener(); len = nbnsconvS2M(s, msg + nbudphdrsize, sizeof(msg) - nbudphdrsize); if (len == 0) return 0; t = mallocz(sizeof(*t), 1); if (t == nil) return nil; t->id = s->id; t->c = chancreate(sizeof(NbnsMessage *), 3); if (t->c == nil) { free(t); return nil; } qlock(&transactionlist); t->next = transactionlist.head; transactionlist.head = t; qunlock(&transactionlist); u = (Udphdr *)msg; ipmove(u->laddr, nbglobals.myipaddr); hnputs(u->lport, NbnsPort); if (s->broadcast || ipaddr == nil) ipmove(u->raddr, nbglobals.bcastaddr); else ipmove(u->raddr, ipaddr); hnputs(u->rport, NbnsPort); write(udp.fd, msg, len + nbudphdrsize); return t; } void nbnstransactionfree(NbnsTransaction **tp) { NbnsTransaction **tp2; NbnsMessage *s; NbnsTransaction *t; t = *tp; if (t) { qlock(&transactionlist); while ((s = nbrecvp(t->c)) != nil) nbnsmessagefree(&s); for (tp2 = &transactionlist.head; *tp2 && *tp2 != t; tp2 = &(*tp2)->next) ; if (*tp2) { *tp2 = t->next; free(t); } qunlock(&transactionlist); *tp = nil; } }