Subversion Repositories planix.SVN

Rev

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

#include <u.h>
#include <libc.h>
#include <ip.h>
#include <thread.h>
#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;
        }
}