* This file is part of LyX, the document processor.
* Licence details can be found in the file COPYING.
*
- * \author Lars Gullik Bjønnes
+ * \author Lars Gullik Bjønnes
* \author Jean-Marc Lasgouttes
* \author Angus Leeming
* \author John Levon
#include <config.h>
#include "Server.h"
-#include "debug.h"
#include "FuncRequest.h"
#include "LyXAction.h"
#include "LyXFunc.h"
+
#include "frontends/Application.h"
+#include "support/debug.h"
#include "support/FileName.h"
#include "support/lstrings.h"
-#include "support/lyxlib.h"
#include <boost/bind.hpp>
#endif
#include <fcntl.h>
+using namespace std;
+using namespace lyx::support;
namespace lyx {
-using support::compare;
-using support::FileName;
-using support::rtrim;
-using support::split;
-
-using std::endl;
-using std::string;
-
-
/////////////////////////////////////////////////////////////////////
//
// LyXComm
#if !defined (HAVE_MKFIFO)
// We provide a stub class that disables the lyxserver.
-LyXComm::LyXComm(std::string const &, Server *, ClientCallbackfct)
+LyXComm::LyXComm(string const &, Server *, ClientCallbackfct)
{}
void LyXComm::openConnection()
#else // defined (HAVE_MKFIFO)
-LyXComm::LyXComm(std::string const & pip, Server * cli, ClientCallbackfct ccb)
+LyXComm::LyXComm(string const & pip, Server * cli, ClientCallbackfct ccb)
: pipename_(pip), client_(cli), clientcb_(ccb)
{
ready_ = false;
}
if (!ready_) {
- lyxerr << "LyXComm: Already disconnected" << endl;
+ LYXERR0("LyXComm: Already disconnected");
return;
}
int LyXComm::startPipe(string const & file, bool write)
{
+ static bool stalepipe = false;
FileName const filename(file);
- if (::access(filename.toFilesystemEncoding().c_str(), F_OK) == 0) {
- lyxerr << "LyXComm: Pipe " << filename << " already exists.\n"
- << "If no other LyX program is active, please delete"
- " the pipe by hand and try again." << endl;
- pipename_.erase();
- return -1;
+ if (filename.exists()) {
+ if (!write) {
+ // Let's see whether we have a stale pipe.
+ int fd = ::open(filename.toFilesystemEncoding().c_str(),
+ O_WRONLY | O_NONBLOCK);
+ if (fd >= 0) {
+ // Another LyX instance is using it.
+ ::close(fd);
+ } else if (errno == ENXIO) {
+ // No process is reading from the other end.
+ stalepipe = true;
+ LYXERR(Debug::LYXSERVER,
+ "LyXComm: trying to remove "
+ << filename);
+ filename.removeFile();
+ }
+ } else if (stalepipe) {
+ LYXERR(Debug::LYXSERVER, "LyXComm: trying to remove "
+ << filename);
+ filename.removeFile();
+ stalepipe = false;
+ }
+ if (filename.exists()) {
+ lyxerr << "LyXComm: Pipe " << filename
+ << " already exists.\nIf no other LyX program"
+ " is active, please delete the pipe by hand"
+ " and try again."
+ << endl;
+ pipename_.erase();
+ return -1;
+ }
}
if (::mkfifo(filename.toFilesystemEncoding().c_str(), 0600) < 0) {
int const charbuf_size = 100;
char charbuf[charbuf_size];
+ // As O_NONBLOCK is set, until no data is available for reading,
+ // read() doesn't block but returns -1 and set errno to EAGAIN.
+ // After a client that opened the pipe for writing, closes it
+ // (and no other client is using the pipe), read() would always
+ // return 0 and thus the connection has to be reset.
+
errno = 0;
int status;
// the single = is intended here.
clientcb_(client_, cmd);
//\n or not \n?
}
- }
- if (errno == EAGAIN) {
- errno = 0;
- return;
- }
- if (errno != 0) {
- lyxerr << "LyXComm: " << strerror(errno) << endl;
+ } else {
+ if (errno == EAGAIN) {
+ // Nothing to read, continue
+ errno = 0;
+ return;
+ }
+ // An error occurred, better bailing out
+ LYXERR0("LyXComm: " << strerror(errno));
if (!read_buffer_.empty()) {
- lyxerr << "LyXComm: truncated command: "
- << read_buffer_ << endl;
+ LYXERR0("LyXComm: truncated command: " << read_buffer_);
read_buffer_.erase();
}
break; // reset connection
}
}
- // The connection gets reset in errno != EAGAIN
- // Why does it need to be reset if errno == 0?
+ // The connection gets reset when read() returns 0 (meaning that the
+ // last client closed the pipe) or an error occurred, in which case
+ // read() returns -1 and errno != EAGAIN.
closeConnection();
openConnection();
errno = 0;
void LyXComm::send(string const & msg)
{
if (msg.empty()) {
- lyxerr << "LyXComm: Request to send empty string. Ignoring."
- << endl;
+ LYXERR0("LyXComm: Request to send empty string. Ignoring.");
return;
}
if (pipename_.empty()) return;
if (!ready_) {
- lyxerr << "LyXComm: Pipes are closed. Could not send "
- << msg << endl;
+ LYXERR0("LyXComm: Pipes are closed. Could not send " << msg);
} else if (::write(outfd_, msg.c_str(), msg.length()) < 0) {
lyxerr << "LyXComm: Error sending message: " << msg
<< '\n' << strerror(errno)
server->callback(msg);
}
-Server::Server(LyXFunc * f, std::string const & pipes)
+Server::Server(LyXFunc * f, string const & pipes)
: numclients_(0), func_(f), pipes_(pipes, this, &ServerCallback)
{}
}
+int compare(char const * a, char const * b, unsigned int len)
+{
+ using namespace std;
+ return strncmp(a, b, len);
+}
+
+
// Handle data gotten from communication, called by LyXComm
void Server::callback(string const & msg)
{
"Server: ignoring bye messge from unregistered client" << client);
}
} else {
- lyxerr <<"Server: Undefined server command "
- << cmd << '.' << endl;
+ LYXERR0("Server: Undefined server command " << cmd << '.');
}
return;
}
}
-// Send a notify messge to a client, called by WorkAreaKeyPress
+// Send a notify message to a client, called by WorkAreaKeyPress
void Server::notifyClient(string const & s)
{
pipes_.send("NOTIFY:" + s + "\n");