summaryrefslogtreecommitdiff
path: root/netfs/daemon.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'netfs/daemon.cpp')
-rw-r--r--netfs/daemon.cpp228
1 files changed, 171 insertions, 57 deletions
diff --git a/netfs/daemon.cpp b/netfs/daemon.cpp
index 4876a1a..d9990fe 100644
--- a/netfs/daemon.cpp
+++ b/netfs/daemon.cpp
@@ -1,6 +1,7 @@
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
+#include <signal.h>
#include <errno.h>
#include <string.h>
#include <set>
@@ -49,73 +50,186 @@ class TempUserChange {
}
void
-runDaemonOn(FILE * f, DaemonConfigPtr, DaemonGlobalStatePtr)
+runDaemonOn(FILE * f, DaemonGlobalStatePtr)
{
- while (true) {
- PacketPtr p = new Packet(f);
- Sender s(p->index, f);
- uint16_t type (p->data->dataTypeID());
- // Dirs
- TRYCLASS(OpenDirRequest);
- TRYCLASS(CloseDirRequest);
- TRYCLASS(ReadDirRequest);
- TRYCLASS(RmDirRequest);
- TRYCLASS(MkDirRequest);
- // Misc
- TRYCLASS(AccessRequest);
- TRYCLASS(GetAttrRequest);
- TRYCLASS(FgetAttrRequest);
- TRYCLASS(UnlinkRequest);
- TRYCLASS(SymlinkRequest);
- TRYCLASS(LinkRequest);
- TRYCLASS(RenameRequest);
- TRYCLASS(ReadlinkRequest);
- TRYCLASS(ChmodRequest);
- TRYCLASS(ChownRequest);
- // Files
- TRYCLASS(OpenRequest);
- TRYCLASS(CloseRequest);
- TRYCLASS(ReadRequest);
- TRYCLASS(WriteRequest);
- TRYCLASS(TruncateRequest);
- TRYCLASS(FtruncateRequest);
- TRYCLASS(CreateRequest);
- // FS
- TRYCLASS(StatfsRequest);
+ PacketPtr p = new Packet(f);
+ Sender s(p->index, f);
+ uint16_t type (p->data->dataTypeID());
+ // Dirs
+ TRYCLASS(OpenDirRequest);
+ TRYCLASS(CloseDirRequest);
+ TRYCLASS(ReadDirRequest);
+ TRYCLASS(RmDirRequest);
+ TRYCLASS(MkDirRequest);
+ // Misc
+ TRYCLASS(AccessRequest);
+ TRYCLASS(GetAttrRequest);
+ TRYCLASS(FgetAttrRequest);
+ TRYCLASS(UnlinkRequest);
+ TRYCLASS(SymlinkRequest);
+ TRYCLASS(LinkRequest);
+ TRYCLASS(RenameRequest);
+ TRYCLASS(ReadlinkRequest);
+ TRYCLASS(ChmodRequest);
+ TRYCLASS(ChownRequest);
+ // Files
+ TRYCLASS(OpenRequest);
+ TRYCLASS(CloseRequest);
+ TRYCLASS(ReadRequest);
+ TRYCLASS(WriteRequest);
+ TRYCLASS(TruncateRequest);
+ TRYCLASS(FtruncateRequest);
+ TRYCLASS(CreateRequest);
+ // FS
+ TRYCLASS(StatfsRequest);
+}
+typedef void (*sa_sigaction_t)(int, siginfo_t *, void *);
+
+bool running = true;
+void onsigint(int, siginfo_t *, void *)
+{
+ running = false;
+}
+
+void setsignal(int sig, sa_sigaction_t f)
+{
+ struct sigaction act;
+ memset(&act, 0, sizeof(struct sigaction));
+ act.sa_sigaction = f;
+ sigaction(sig, &act, NULL);
+}
+
+class SocketEventHandler : public IsRefCounted {
+ public:
+ SocketEventHandler(int sock) : socket(sock) { }
+ virtual void onRead() { }
+ virtual void onWrite() { }
+ virtual void onError() { }
+
+ const int socket;
+};
+typedef SmartPointer<SocketEventHandler> SockEvHdlrPtr;
+typedef std::map<int, SockEvHdlrPtr> SocketSet;
+
+class IncomingPacketHandler : public SocketEventHandler {
+ public:
+ IncomingPacketHandler(int sock, DaemonGlobalStatePtr d) : SocketEventHandler(sock), dgs(d)
+ {
+ f = fdopen(sock, "a+");
+ }
+ void onRead()
+ {
+ runDaemonOn(f, dgs);
+ }
+ void onError()
+ {
+ }
+ private:
+ FILE * f;
+ DaemonGlobalStatePtr dgs;
+};
+class ListenAcceptHandler : public SocketEventHandler {
+ public:
+ ListenAcceptHandler(int sock, SocketSet & socks, DaemonGlobalStatePtr d) :
+ SocketEventHandler(sock), sockets(socks), dgs(d)
+ {
+ }
+ void onRead()
+ {
+ int fd = accept(socket, NULL, NULL);
+ sockets[fd] = new IncomingPacketHandler(fd, dgs);
+ }
+ private:
+ SocketSet & sockets;
+ DaemonGlobalStatePtr dgs;
+};
+
+
+void
+createListeners(DaemonGlobalStatePtr dgs, SocketSet & lsocks)
+{
+ struct addrinfo hints;
+ memset(&hints, 0, sizeof(struct addrinfo));
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_flags = AI_PASSIVE;
+ struct addrinfo *result, *rp;
+ if (getaddrinfo(NULL, dgs->config->tcpPort.c_str(), &hints, &result) == 0) {
+ for (rp = result; rp != NULL; rp = rp->ai_next) {
+ int sfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
+ if (sfd == -1) {
+ close(sfd);
+ continue;
+ }
+ if (bind(sfd, rp->ai_addr, rp->ai_addrlen) != 0) {
+ close(sfd);
+ continue;
+ }
+ if (listen(sfd, 5)) {
+ close(sfd);
+ continue;
+ }
+ lsocks[sfd] = new ListenAcceptHandler(sfd, lsocks, dgs);
+ }
}
- fclose(f);
}
-int main(int, char* [])
+void
+listener(DaemonGlobalStatePtr dgs)
{
- DaemonConfigPtr dc = DaemonConfig::Load("daemon.xml");
- DaemonGlobalStatePtr dgs = new DaemonGlobalState();
- while (true) {
- struct addrinfo hints;
- memset(&hints, 0, sizeof(struct addrinfo));
- hints.ai_family = AF_UNSPEC;
- hints.ai_socktype = SOCK_STREAM;
- hints.ai_flags = AI_PASSIVE;
- struct addrinfo *result, *rp;
- if (getaddrinfo(NULL, dc->tcpPort.c_str(), &hints, &result) == 0) {
- for (rp = result; rp != NULL; rp = rp->ai_next) {
- int sfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
- if (sfd == -1)
- continue;
- if (bind(sfd, rp->ai_addr, rp->ai_addrlen) == 0) {
- if (listen(sfd, 5)) {
- // Error
- continue;
- }
- for (int newfd; (newfd = accept(sfd, NULL, NULL)) > 0; ) {
- runDaemonOn(fdopen(newfd, "a+"), dc, dgs);
+ SocketSet socks;
+ createListeners(dgs, socks);
+ if (!socks.size()) {
+ return;
+ }
+ while (running) {
+ fd_set readSocks;
+ fd_set errSocks;
+ FD_ZERO(&readSocks);
+ FD_ZERO(&errSocks);
+ int maxfd = 0;
+ foreach(SocketSet::const_iterator, socks, s) {
+ FD_SET(s->first, &readSocks);
+ FD_SET(s->first, &errSocks);
+ maxfd = std::max(s->first, maxfd);
+ }
+ struct timeval to = { 1, 0 };
+ int rsel = select(maxfd + 1, &readSocks, NULL, &errSocks, &to);
+ if (rsel) {
+ std::set<int> toRemove;
+ foreach(SocketSet::const_iterator, socks, s) {
+ if (FD_ISSET(s->first, &errSocks)) {
+ s->second->onError();
+ close(s->first);
+ toRemove.insert(s->second);
+ }
+ else {
+ if (FD_ISSET(s->first, &readSocks)) {
+ try {
+ s->second->onRead();
+ }
+ catch (...) {
+ }
}
- break;
}
- close(sfd);
+ }
+ foreach(std::set<int>::const_iterator, toRemove, s) {
+ socks.erase(*s);
}
}
}
+ foreach(SocketSet::const_iterator, socks, s) {
+ close(s->first);
+ }
+}
+
+int main(int, char* [])
+{
+ DaemonConfigPtr dc = DaemonConfig::Load("daemon.xml");
+ DaemonGlobalStatePtr dgs = new DaemonGlobalState(dc);
+ setsignal(SIGINT, onsigint);
+
+ listener(dgs);
return 0;
}