IBR-DTNSuite  0.8
daemon/src/net/FileMonitor.cpp
Go to the documentation of this file.
00001 /*
00002  * FileMonitor.cpp
00003  *
00004  *  Created on: 10.04.2012
00005  *      Author: morgenro
00006  */
00007 
00008 #include "config.h"
00009 #include "net/FileMonitor.h"
00010 #include "core/BundleCore.h"
00011 #include <ibrcommon/Logger.h>
00012 #include <ibrcommon/data/ConfigFile.h>
00013 
00014 #ifdef HAVE_SYS_INOTIFY_H
00015 #include <sys/inotify.h>
00016 #include <unistd.h>
00017 #endif
00018 
00019 namespace dtn
00020 {
00021         namespace net
00022         {
00023                 FileMonitor::FileMonitor()
00024                  : _inotify_sock(0), _running(true)
00025                 {
00026 #ifdef HAVE_SYS_INOTIFY_H
00027                         _inotify_sock = inotify_init();
00028 #endif
00029                 }
00030 
00031                 FileMonitor::~FileMonitor()
00032                 {
00033                         join();
00034                 }
00035 
00036                 void FileMonitor::watch(const ibrcommon::File &watch)
00037                 {
00038                         IBRCOMMON_LOGGER_DEBUG(5) << "watch on: " << watch.getPath() << IBRCOMMON_LOGGER_ENDL;
00039 
00040                         if (!watch.isDirectory())
00041                                 throw ibrcommon::Exception("can not watch files, please specify a directory");
00042 
00043 #ifdef HAVE_SYS_INOTIFY_H
00044                         int wd = inotify_add_watch(_inotify_sock, watch.getPath().c_str(), IN_CREATE | IN_DELETE);
00045                         _watch_map[wd] = watch;
00046 #endif
00047                 }
00048 
00049                 void FileMonitor::componentUp()
00050                 {
00051 #ifdef HAVE_SYS_INOTIFY_H
00052                         _socket.add(_inotify_sock);
00053 #endif
00054                 }
00055 
00056                 void FileMonitor::componentRun()
00057                 {
00058 #ifdef HAVE_SYS_INOTIFY_H
00059                         while (_running)
00060                         {
00061                                 std::list<int> fds;
00062 
00063                                 // scan for mounts
00064                                 scan();
00065 
00066                                 try {
00067                                         // select on all bound sockets
00068                                         _socket.select(fds);
00069 
00070                                         unsigned char buf[1024];
00071 
00072                                         // receive from all sockets
00073                                         for (std::list<int>::const_iterator iter = fds.begin(); iter != fds.end(); iter++)
00074                                         {
00075                                                 int fd = (*iter);
00076                                                 ::read(fd, &buf, 1024);
00077                                         }
00078 
00079                                         ::sleep(2);
00080                                 } catch (const ibrcommon::vsocket_timeout&) { };
00081                         }
00082 #endif
00083                 }
00084 
00085                 void FileMonitor::componentDown()
00086                 {
00087 #ifdef HAVE_SYS_INOTIFY_H
00088                         for (watch_map::iterator iter = _watch_map.begin(); iter != _watch_map.end(); iter++)
00089                         {
00090                                 const int wd = (*iter).first;
00091                                 inotify_rm_watch(_inotify_sock, wd);
00092                         }
00093 #endif
00094                         _watch_map.clear();
00095                 }
00096 
00097                 void FileMonitor::__cancellation()
00098                 {
00099 #ifdef HAVE_SYS_INOTIFY_H
00100                         _socket.close();
00101 #endif
00102                 }
00103 
00104                 void FileMonitor::scan()
00105                 {
00106                         IBRCOMMON_LOGGER_DEBUG(5) << "scan for file changes" << IBRCOMMON_LOGGER_ENDL;
00107 
00108                         std::set<ibrcommon::File> watch_set;
00109 
00110                         for (watch_map::iterator iter = _watch_map.begin(); iter != _watch_map.end(); iter++)
00111                         {
00112                                 const ibrcommon::File &path = (*iter).second;
00113                                 std::list<ibrcommon::File> files;
00114 
00115                                 if (path.getFiles(files) == 0)
00116                                 {
00117                                         for (std::list<ibrcommon::File>::iterator iter = files.begin(); iter != files.end(); iter++)
00118                                         {
00119                                                 watch_set.insert(*iter);
00120                                         }
00121                                 }
00122                                 else
00123                                 {
00124                                         IBRCOMMON_LOGGER(error) << "scan of " << path.getPath() << " failed" << IBRCOMMON_LOGGER_ENDL;
00125                                 }
00126                         }
00127 
00128                         // check for new directories
00129                         for (std::set<ibrcommon::File>::iterator iter = watch_set.begin(); iter != watch_set.end(); iter++)
00130                         {
00131                                 const ibrcommon::File &path = (*iter);
00132                                 if (path.isDirectory() && !path.isSystem())
00133                                 {
00134                                         if (!isActive(path)) {
00135                                                 adopt(path);
00136                                         }
00137                                 }
00138                         }
00139 
00140                         // look for gone directories
00141                         for (std::map<ibrcommon::File, dtn::core::Node>::iterator iter = _active_paths.begin(); iter != _active_paths.end();)
00142                         {
00143                                 const ibrcommon::File &path = (*iter).first;
00144                                 const dtn::core::Node &node = (*iter).second;
00145 
00146                                 if (watch_set.find(path) == watch_set.end())
00147                                 {
00148                                         dtn::core::BundleCore::getInstance().removeConnection(node);
00149                                         IBRCOMMON_LOGGER_DEBUG(5) << "Node on drive gone: " << node.getEID().getString() << IBRCOMMON_LOGGER_ENDL;
00150                                         _active_paths.erase(iter++);
00151                                 }
00152                                 else
00153                                 {
00154                                         iter++;
00155                                 }
00156                         }
00157                 }
00158 
00159                 void FileMonitor::adopt(const ibrcommon::File &path)
00160                 {
00161                         // look for ".dtndrive" file
00162                         const ibrcommon::File drivefile = path.get(".dtndrive");
00163                         if (drivefile.exists())
00164                         {
00165                                 ibrcommon::ConfigFile cf(drivefile.getPath());
00166 
00167                                 try {
00168                                         const dtn::data::EID eid( cf.read<std::string>("EID") );
00169 
00170                                         dtn::core::Node n(eid);
00171                                         const std::string uri = "file://" + path.getPath() + "/" + cf.read<std::string>("PATH");
00172 
00173                                         n.add(dtn::core::Node::URI(dtn::core::Node::NODE_STATIC, dtn::core::Node::CONN_FILE, uri, 0, 10));
00174                                         dtn::core::BundleCore::getInstance().addConnection(n);
00175 
00176                                         _active_paths[path] = n;
00177 
00178                                         IBRCOMMON_LOGGER_DEBUG(5) << "Node on drive found: " << n.getEID().getString() << IBRCOMMON_LOGGER_ENDL;
00179 
00180                                 } catch (const ibrcommon::ConfigFile::key_not_found&) {};
00181                         }
00182                 }
00183 
00184                 bool FileMonitor::isActive(const ibrcommon::File &path) const
00185                 {
00186                         return (_active_paths.find(path) != _active_paths.end());
00187                 }
00188 
00189                 const std::string FileMonitor::getName() const
00190                 {
00191                         return "FileMonitor";
00192                 }
00193         }
00194 } /* namespace ibrcommon */