Subversion Repositories planix.SVN

Rev

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

#include "headers.h"

static struct {
        int thread;
        QLock;
        char adir[NETPATHLEN];
        int acfd;
        char ldir[NETPATHLEN];
        int lcfd;
        SMBCIFSACCEPTFN *accept;
} tcp = { -1 };

typedef struct Session Session;

enum { Connected, Dead };

struct Session {
        SmbCifsSession;
        int thread;
        Session *next;
        int state;
        SMBCIFSWRITEFN *write;
};

static struct {
        QLock;
        Session *head;
} sessions;

typedef struct Listen Listen;

static void
deletesession(Session *s)
{
        Session **sp;
        close(s->fd);
        qlock(&sessions);
        for (sp = &sessions.head; *sp && *sp != s; sp = &(*sp)->next)
                ;
        if (*sp)
                *sp = s->next;
        qunlock(&sessions);
        free(s);
}

static void
tcpreader(void *a)
{
        Session *s = a;
        uchar *buf;
        int buflen = smbglobals.maxreceive + 4;
        buf = nbemalloc(buflen);
        for (;;) {
                int n;
                uchar flags;
                ushort length;

                n = readn(s->fd, buf, 4);
                if (n != 4) {
                die:
                        free(buf);
                        if (s->state == Connected)
                                (*s->write)(s, nil, -1);
                        deletesession(s);
                        return;
                }
                flags = buf[1];
                length = nhgets(buf + 2) | ((flags & 1) << 16);
                if (length > buflen - 4) {
                        print("nbss: too much data (%ud)\n", length);
                        goto die;
                }
                n = readn(s->fd, buf + 4, length);
                if (n != length)
                        goto die;
                if (s->state == Connected) {
                        if ((*s->write)(s, buf + 4, length) != 0) {
                                s->state = Dead;
                                goto die;
                        }
                }
        }
}

static Session *
createsession(int fd)
{
        Session *s;
        s = smbemalloc(sizeof(Session));
        s->fd = fd;
        s->state = Connected;
        qlock(&sessions);
        if (!(*tcp.accept)(s, &s->write)) {
                qunlock(&sessions);
                free(s);
                return nil;
        }
        s->thread = procrfork(tcpreader, s, 32768, RFNAMEG);
        if (s->thread < 0) {
                qunlock(&sessions);
                (*s->write)(s, nil, -1);
                free(s);
                return nil;
        }
        s->next = sessions.head;
        sessions.head = s;
        qunlock(&sessions);
        return s;
}

static void
tcplistener(void *)
{
        for (;;) {
                int dfd;
                char ldir[NETPATHLEN];
                int lcfd;
//print("cifstcplistener: listening\n");
                lcfd = listen(tcp.adir, ldir);
//print("cifstcplistener: contact\n");
                if (lcfd < 0) {
                die:
                        qlock(&tcp);
                        close(tcp.acfd);
                        tcp.thread = -1;
                        qunlock(&tcp);
                        return;
                }
                dfd = accept(lcfd, ldir);
                close(lcfd);
                if (dfd < 0)
                        goto die;
                if (createsession(dfd) == nil)
                        close(dfd);
        }
}

int
smblistencifs(SMBCIFSACCEPTFN *accept)
{
        qlock(&tcp);
        if (tcp.thread < 0) {
                tcp.acfd = announce("tcp!*!cifs", tcp.adir);
                if (tcp.acfd < 0) {
                        print("smblistentcp: can't announce: %r\n");
                        qunlock(&tcp);
                        return -1;
                }
                tcp.thread = proccreate(tcplistener, nil, 16384);
        }
        tcp.accept = accept;
        qunlock(&tcp);
        return 0;
}
        

Generated by GNU Enscript 1.6.6.