X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Flyxsocket.C;h=0de947676401945c424931c139dfea79178b6e3b;hb=35204f8f33d7400a5fefeffea533fb4cb4097211;hp=e3a84683e5723cfc02942708e1bd94cbd024b181;hpb=c38370d1c3dc594b17c53c28582f8092a15901d9;p=lyx.git diff --git a/src/lyxsocket.C b/src/lyxsocket.C index e3a84683e5..0de9476764 100644 --- a/src/lyxsocket.C +++ b/src/lyxsocket.C @@ -12,6 +12,8 @@ * Full author contact details are available in file CREDITS. */ +#include + #include "lyxsocket.h" #include "debug.h" @@ -19,33 +21,53 @@ #include "LyXAction.h" #include "lyxfunc.h" -#include "frontends/lyx_gui.h" +#include "frontends/Application.h" +#include "support/environment.h" #include "support/lyxlib.h" #include "support/socktools.h" -#include +#include + #include +#if defined (_WIN32) +# include +#endif + +using boost::shared_ptr; using std::auto_ptr; using std::endl; using std::string; +namespace lyx { + // Address is the unix address for the socket. // MAX_CLIENTS is the maximum number of clients // that can connect at the same time. LyXServerSocket::LyXServerSocket(LyXFunc * f, string const & addr) : func(f), - fd_(lyx::support::socktools::listen(addr, MAX_CLIENTS)), + fd_(support::socktools::listen(addr, 3)), address_(addr) { if (fd_ == -1) { lyxerr << "lyx: Disabling LyX socket." << endl; return; } - lyx_gui::set_serversocket_callback(this); + + // These env vars are used by DVI inverse search + // Needed by xdvi + support::setEnv("XEDITOR", "lyxclient -g %f %l"); + // Needed by lyxclient + support::setEnv("LYXSOCKET", address_); + + theApp->registerSocketCallback( + fd_, + boost::bind(&LyXServerSocket::serverCallback, this) + ); + lyxerr[Debug::LYXSERVER] << "lyx: New server socket " << fd_ << ' ' << address_ << endl; } @@ -54,19 +76,17 @@ LyXServerSocket::LyXServerSocket(LyXFunc * f, string const & addr) // Close the socket and remove the address of the filesystem. LyXServerSocket::~LyXServerSocket() { - ::close(fd_); - lyx::support::unlink(address_); - while (!clients.empty()) close(*clients.rbegin()); + if (fd_ != -1) { + theApp->unregisterSocketCallback(fd_); + if (::close(fd_) != 0) + lyxerr << "lyx: Server socket " << fd_ + << " IO error on closing: " << strerror(errno); + } + support::unlink(address_); lyxerr[Debug::LYXSERVER] << "lyx: Server socket quitting" << endl; } -int LyXServerSocket::fd() const -{ - return fd_; -} - - string const & LyXServerSocket::address() const { return address_; @@ -77,23 +97,36 @@ string const & LyXServerSocket::address() const // is OK and if the number of clients does not exceed MAX_CLIENTS void LyXServerSocket::serverCallback() { - auto_ptr client(new LyXDataSocket(this)); - if (client->connected()) { - if (clients.size() == MAX_CLIENTS) { - client->writeln("BYE:Too many clients connected"); - } else { - lyx_gui::set_datasocket_callback(client.get()); - clients.insert(client.release()); - return; - } + int const client_fd = support::socktools::accept(fd_); + + if (fd_ == -1) { + lyxerr[Debug::LYXSERVER] << "lyx: Failed to accept new client" + << endl; + return; } + + if (clients.size() >= MAX_CLIENTS) { + writeln("BYE:Too many clients connected"); + return; + } + + // Register the new client. + clients[client_fd] = + shared_ptr(new LyXDataSocket(client_fd)); + theApp->registerSocketCallback( + client_fd, + boost::bind(&LyXServerSocket::dataCallback, + this, client_fd) + ); } // Reads and processes input from client and check // if the connection has been closed -void LyXServerSocket::dataCallback(LyXDataSocket * client) +void LyXServerSocket::dataCallback(int fd) { + shared_ptr client = clients[fd]; + string line; string::size_type pos; bool saidbye = false; @@ -109,7 +142,7 @@ void LyXServerSocket::dataCallback(LyXDataSocket * client) if (key == "LYXCMD") { string const cmd = line.substr(pos + 1); func->dispatch(lyxaction.lookupFunc(cmd)); - string const rval = func->getMessage(); + string const rval = to_utf8(func->getMessage()); if (func->errorStat()) { client->writeln("ERROR:" + cmd + ':' + rval); } else { @@ -126,17 +159,30 @@ void LyXServerSocket::dataCallback(LyXDataSocket * client) } if (saidbye || (!client->connected())) { - close(client); + clients.erase(fd); } } -// Removes client callback and deletes client object -void LyXServerSocket::close(LyXDataSocket * client) +void LyXServerSocket::writeln(string const & line) { - lyx_gui::remove_datasocket_callback(client); - clients.erase(client); - delete client; + string const linen(line + '\n'); + int const size = linen.size(); + int const written = ::write(fd_, linen.c_str(), size); + if (written < size) { // Always mean end of connection. + if ((written == -1) && (errno == EPIPE)) { + // The program will also receive a SIGPIPE + // that must be caught + lyxerr << "lyx: Server socket " << fd_ + << " connection closed while writing." << endl; + } else { + // Anything else, including errno == EAGAIN, must be + // considered IO error. EAGAIN should never happen + // when line is small + lyxerr << "lyx: Server socket " << fd_ + << " IO error: " << strerror(errno); + } + } } // Debug @@ -145,44 +191,29 @@ void LyXServerSocket::close(LyXDataSocket * client) // lyxerr << "LyXServerSocket debug dump.\n" // << "fd = " << fd_ << ", address = " << address_ << ".\n" // << "Clients: " << clients.size() << ".\n"; -// if (!clients.empty()) { -// std::set::const_iterator client = clients.begin(); -// std::set::const_iterator end = clients.end(); -// for (; client != end; ++client) -// lyxerr << "fd = " << (*client)->fd() << "\n"; -// } +// std::map >::const_iterator client = clients.begin(); +// std::map >::const_iterator end = clients.end(); +// for (; client != end; ++client) +// lyxerr << "fd = " << client->first << '\n'; // } -LyXDataSocket::LyXDataSocket(LyXServerSocket * serv) - :server_(serv), - fd_(lyx::support::socktools::accept(serv->fd())) +LyXDataSocket::LyXDataSocket(int fd) + : fd_(fd), connected_(true) { - if (fd_ == -1) { - connected_ = false; - } else { - lyxerr[Debug::LYXSERVER] << "lyx: New data socket " << fd_ << endl; - connected_ = true; - } + lyxerr[Debug::LYXSERVER] << "lyx: New data socket " << fd_ << endl; } LyXDataSocket::~LyXDataSocket() { - ::close(fd_); - lyxerr[Debug::LYXSERVER] << "lyx: Data socket " << fd_ << " quitting." << endl; -} - - -LyXServerSocket * LyXDataSocket::server() const -{ - return server_; -} - + if (::close(fd_) != 0) + lyxerr << "lyx: Data socket " << fd_ + << " IO error on closing: " << strerror(errno); -int LyXDataSocket::fd() const -{ - return fd_; + theApp->unregisterSocketCallback(fd_); + lyxerr[Debug::LYXSERVER] << "lyx: Data socket " << fd_ << " quitting." + << endl; } @@ -196,14 +227,12 @@ bool LyXDataSocket::connected() const bool LyXDataSocket::readln(string & line) { int const charbuf_size = 100; - char charbuf[charbuf_size]; // buffer for the ::read() system call + char charbuf[charbuf_size]; // buffer for the ::read() system call int count; - string::size_type pos; // read and store characters in buffer while ((count = ::read(fd_, charbuf, charbuf_size - 1)) > 0) { - charbuf[count] = '\0'; // turn it into a c string - buffer += charbuf; + buffer_.append(charbuf, charbuf + count); } // Error conditions. The buffer must still be @@ -219,13 +248,14 @@ bool LyXDataSocket::readln(string & line) } // Cut a line from buffer - if ((pos = buffer.find('\n')) == string::npos) { + string::size_type pos = buffer_.find('\n'); + if (pos == string::npos) { lyxerr[Debug::LYXSERVER] << "lyx: Data socket " << fd_ << ": line not completed." << endl; return false; // No complete line stored } - line = buffer.substr(0, pos); - buffer = buffer.substr(pos + 1); + line = buffer_.substr(0, pos); + buffer_.erase(0, pos + 1); return true; } @@ -233,10 +263,10 @@ bool LyXDataSocket::readln(string & line) // Write a line of the form : to the socket void LyXDataSocket::writeln(string const & line) { - string linen(line + '\n'); - int size = linen.size(); - int written = ::write(fd_, linen.c_str(), size); - if (written < size) { // Allways mean end of connection. + string const linen(line + '\n'); + int const size = linen.size(); + int const written = ::write(fd_, linen.c_str(), size); + if (written < size) { // Always mean end of connection. if ((written == -1) && (errno == EPIPE)) { // The program will also receive a SIGPIPE // that must be catched @@ -252,3 +282,6 @@ void LyXDataSocket::writeln(string const & line) connected_ = false; } } + + +} // namespace lyx