"Fossies" - the Fresh Open Source Software Archive

Member "google-gadgets-for-linux-0.11.2/ggadget/run_once.cc" (20 Mar 2009, 5533 Bytes) of package /linux/misc/old/google-gadgets-for-linux-0.11.2.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    1 /*
    2   Copyright 2008 Google Inc.
    3 
    4   Licensed under the Apache License, Version 2.0 (the "License");
    5   you may not use this file except in compliance with the License.
    6   You may obtain a copy of the License at
    7 
    8        http://www.apache.org/licenses/LICENSE-2.0
    9 
   10   Unless required by applicable law or agreed to in writing, software
   11   distributed under the License is distributed on an "AS IS" BASIS,
   12   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   13   See the License for the specific language governing permissions and
   14   limitations under the License.
   15 */
   16 
   17 #include "run_once.h"
   18 #include <cstdlib>
   19 #include <list>
   20 #include <signal.h>
   21 #include <string>
   22 #include <sys/select.h>
   23 #include <sys/socket.h>
   24 #include <sys/time.h>
   25 #include <sys/types.h>
   26 #include <sys/un.h>
   27 #include <unistd.h>
   28 #include "light_map.h"
   29 #include "main_loop_interface.h"
   30 #include "signals.h"
   31 
   32 namespace ggadget {
   33 
   34 const size_t kBufferSize = 4096;
   35 // UNIX_PATH_MAX is not available in <sys/un.h>.
   36 const size_t kSizeOfSunPath =
   37     sizeof(reinterpret_cast<struct sockaddr_un *>(0)->sun_path);
   38 
   39 class RunOnce::Impl : public WatchCallbackInterface {
   40  public:
   41   struct Session {
   42     int watch_id;
   43     std::string data;
   44   };
   45 
   46   Impl(const char *path)
   47       : path_(path),
   48         is_running_(false),
   49         watch_id_(-1),
   50         fd_(-1) {
   51     ASSERT(path);
   52     if (path_.size() < kSizeOfSunPath) {
   53       fd_ = RunAsServer();
   54       if (fd_ == -1) {
   55         fd_ = RunAsClient();
   56         if (fd_ != -1) {
   57           is_running_ = true;
   58           return;
   59         } else {
   60           unlink(path_.c_str());
   61           fd_ = RunAsServer();
   62         }
   63       }
   64     }
   65 
   66     is_running_ = false;
   67     if (fd_ != -1)
   68       watch_id_ = GetGlobalMainLoop()->AddIOReadWatch(fd_, this);
   69   }
   70 
   71   ~Impl() {
   72     if (is_running_) {
   73       close(fd_);
   74     } else {
   75       // Removes watch for all running clients.
   76       for (LightMap<int, Session>::iterator ite = connections_.begin();
   77            ite != connections_.end();
   78            ++ite) {
   79         GetGlobalMainLoop()->RemoveWatch(ite->second.watch_id);
   80       }
   81       // Removes watch for the listening socket.
   82       GetGlobalMainLoop()->RemoveWatch(watch_id_);
   83       unlink(path_.c_str());
   84     }
   85   }
   86 
   87   bool IsRunning() const {
   88     return is_running_;
   89   }
   90 
   91   size_t SendMessage(const std::string &data) {
   92     if (!is_running_)
   93       return 0;
   94 
   95     if (fd_ == -1) {
   96       // In case of repeated SendMessage() calls.
   97       fd_ = RunAsClient();
   98     }
   99 
  100     sig_t old_proc = signal(SIGPIPE, SIG_IGN);
  101 
  102     fd_set fds;
  103     FD_ZERO(&fds);
  104     FD_SET(fd_, &fds);
  105     struct timeval time;
  106 
  107     size_t written = 0;
  108     while (written < data.size()) {
  109       // Waits for at most 1 second.
  110       time.tv_sec = 1;
  111       time.tv_usec = 0;
  112       int result = select(fd_ + 1, NULL, &fds, NULL, &time);
  113       if (result == -1 || result == 0) {
  114         goto end;
  115       }
  116       ssize_t current = write(fd_,
  117                               &data.c_str()[written],
  118                               data.size() - written);
  119       if (current < 1) {
  120         goto end;
  121       }
  122       written += current;
  123     }
  124 
  125 end:
  126     FD_CLR(fd_, &fds);
  127     close(fd_);
  128     fd_ = -1;
  129     signal(SIGPIPE, old_proc);
  130     return written;
  131   }
  132 
  133   Connection *ConnectOnMessage(Slot1<void, const std::string&> *slot) {
  134     return on_message_.Connect(slot);
  135   }
  136 
  137   virtual bool Call(MainLoopInterface *main_loop, int watch_id) {
  138     int fd;
  139     char buf[kBufferSize];
  140 
  141     fd = main_loop->GetWatchData(watch_id);
  142 
  143     if (fd_ == fd) {
  144       socklen_t len;
  145       fd = accept(fd, NULL, &len);
  146       connections_[fd].watch_id =
  147           main_loop->AddIOReadWatch(fd, this);
  148       return true;
  149     }
  150 
  151     ssize_t size = 0;
  152     if ((size = read(fd, &buf, kBufferSize)) > 0) {
  153       connections_[fd].data += std::string(buf, size);
  154     } else {
  155       LightMap<int, Session>::iterator ite = connections_.find(fd);
  156       if (ite != connections_.end()) {
  157         on_message_(ite->second.data);
  158         main_loop->RemoveWatch(watch_id);
  159         connections_.erase(ite);
  160       }
  161       return false;
  162     }
  163 
  164     return true;
  165   }
  166 
  167   virtual void OnRemove(MainLoopInterface *main_loop, int watch_id) {
  168     close(main_loop->GetWatchData(watch_id));
  169   }
  170 
  171   int RunAsServer() {
  172     int fd;
  173     struct sockaddr_un uaddr;
  174     uaddr.sun_family = AF_UNIX;
  175     ASSERT(path_.size() < kSizeOfSunPath);
  176     strncpy(uaddr.sun_path, path_.c_str(), kSizeOfSunPath);
  177     fd = socket(PF_UNIX, SOCK_STREAM, 0);
  178     if (bind(fd, (struct sockaddr*) &uaddr, sizeof(uaddr)) == -1) {
  179       close(fd);
  180       return -1;
  181     }
  182     listen(fd, 5);
  183     return fd;
  184   }
  185 
  186   int RunAsClient() {
  187     int fd;
  188     struct sockaddr_un uaddr;
  189     uaddr.sun_family = AF_UNIX;
  190     ASSERT(path_.size() < kSizeOfSunPath);
  191     strncpy(uaddr.sun_path, path_.c_str(), kSizeOfSunPath);
  192     fd = socket(PF_UNIX, SOCK_STREAM, 0);
  193     if (connect(fd, (struct sockaddr*) &uaddr, sizeof(uaddr)) == -1) {
  194       close(fd);
  195       return -1;
  196     }
  197     return fd;
  198   }
  199 
  200   std::string path_;
  201   bool is_running_;
  202   int watch_id_;
  203   int fd_;
  204   LightMap<int, Session> connections_;
  205   Signal1<void, const std::string &> on_message_;
  206 };
  207 
  208 RunOnce::RunOnce(const char *path)
  209   : impl_(new Impl(path)) {
  210 }
  211 
  212 RunOnce::~RunOnce() {
  213   delete impl_;
  214 }
  215 
  216 bool RunOnce::IsRunning() const {
  217   return impl_->IsRunning();
  218 }
  219 
  220 size_t RunOnce::SendMessage(const std::string &data) {
  221   return impl_->SendMessage(data);
  222 }
  223 
  224 Connection *RunOnce::ConnectOnMessage(Slot1<void, const std::string&> *slot) {
  225   return impl_->ConnectOnMessage(slot);
  226 }
  227 
  228 } // namespace ggadget