#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; }