2003-08-23 00:17:00 +00:00
|
|
|
|
/**
|
2007-04-29 16:22:46 +00:00
|
|
|
|
* \file Server.cpp
|
2003-08-23 00:17:00 +00:00
|
|
|
|
* This file is part of LyX, the document processor.
|
|
|
|
|
* Licence details can be found in the file COPYING.
|
2002-03-21 17:27:08 +00:00
|
|
|
|
*
|
2003-08-23 00:17:00 +00:00
|
|
|
|
* \author Lars Gullik Bj<EFBFBD>nnes
|
|
|
|
|
* \author Jean-Marc Lasgouttes
|
|
|
|
|
* \author Angus Leeming
|
|
|
|
|
* \author John Levon
|
1999-10-02 16:21:10 +00:00
|
|
|
|
*
|
2003-08-23 00:17:00 +00:00
|
|
|
|
* Full author contact details are available in file CREDITS.
|
|
|
|
|
*/
|
1999-09-27 18:44:28 +00:00
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
Docu : To use the lyxserver define the name of the pipe in your
|
2002-03-21 17:27:08 +00:00
|
|
|
|
lyxrc:
|
|
|
|
|
\serverpipe "/home/myhome/.lyxpipe"
|
|
|
|
|
Then use .lyxpipe.in and .lyxpipe.out to communicate to LyX.
|
|
|
|
|
Each message consists of a single line in ASCII. Input lines
|
|
|
|
|
(client -> LyX) have the following format:
|
|
|
|
|
"LYXCMD:<clientname>:<functionname>:<argument>"
|
|
|
|
|
Answers from LyX look like this:
|
|
|
|
|
"INFO:<clientname>:<functionname>:<data>"
|
1999-09-27 18:44:28 +00:00
|
|
|
|
[asierra970531] Or like this in case of error:
|
2002-03-21 17:27:08 +00:00
|
|
|
|
"ERROR:<clientname>:<functionname>:<error message>"
|
|
|
|
|
where <clientname> and <functionname> are just echoed.
|
|
|
|
|
If LyX notifies about a user defined extension key-sequence,
|
|
|
|
|
the line looks like this:
|
|
|
|
|
"NOTIFY:<key-sequence>"
|
1999-09-27 18:44:28 +00:00
|
|
|
|
[asierra970531] New server-only messages to implement a simple protocol
|
2002-03-21 17:27:08 +00:00
|
|
|
|
"LYXSRV:<clientname>:<protocol message>"
|
|
|
|
|
where <protocol message> can be "hello" or "bye". If hello is
|
|
|
|
|
received LyX will inform the client that it's listening its
|
|
|
|
|
messages, and 'bye' will inform that lyx is closing.
|
1999-09-27 18:44:28 +00:00
|
|
|
|
|
2002-03-21 17:27:08 +00:00
|
|
|
|
See development/server_monitor.c for an example client.
|
1999-09-27 18:44:28 +00:00
|
|
|
|
Purpose: implement a client/server lib for LyX
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
|
2007-04-29 16:22:46 +00:00
|
|
|
|
#include "Server.h"
|
2007-04-26 04:41:58 +00:00
|
|
|
|
#include "FuncRequest.h"
|
2003-10-13 00:38:09 +00:00
|
|
|
|
#include "LyXAction.h"
|
2007-04-26 04:41:58 +00:00
|
|
|
|
#include "LyXFunc.h"
|
2008-02-18 07:14:42 +00:00
|
|
|
|
|
2006-10-12 14:10:13 +00:00
|
|
|
|
#include "frontends/Application.h"
|
2006-11-26 21:30:39 +00:00
|
|
|
|
|
2008-02-18 07:14:42 +00:00
|
|
|
|
#include "support/debug.h"
|
Rename files in src/support, step one.
src/support/package.h src/support/Package.h Package
src/support/package.C.in src/support/Package.C.in Package
src/support/path.h src/support/Path.h Path
src/support/fs_extras.h src/support/fs_extras.h NOCLASSES
src/support/RandomAccessList.h src/support/RandomAccessList.h RandomAccessList
src/support/lyxmanip.h src/support/lyxmanip.h NOCLASSES
src/support/rename.C src/support/rename.cpp NOCLASSES
src/support/abort.C src/support/abort.cpp NOCLASSES
src/support/lyxlib.h src/support/lyxlib.h NOCLASSES
src/support/ExceptionMessage.h src/support/ExceptionMessage.h ExceptionMessage
src/support/copy.C src/support/copy.cpp NOCLASSES
src/support/limited_stack.h src/support/limited_stack.h limited_stack
src/support/filefilterlist.C src/support/FileFilterList.cpp ['FileFilterList', 'Filter']
src/support/cow_ptr.h src/support/cow_ptr.h cow_ptr
src/support/os_unix.C src/support/os_unix.cpp NOCLASSES
src/support/socktools.h src/support/socktools.h NOCLASSES
src/support/forkedcontr.h src/support/ForkedcallsController.h ForkedcallsController
src/support/os.h src/support/os.h NOCLASSES
src/support/FileMonitor.h src/support/FileMonitor.h FileMonitor
src/support/copied_ptr.h src/support/copied_ptr.h copied_ptr
src/support/translator.h src/support/Translator.h Translator
src/support/filetools.C src/support/filetools.cpp NOCLASSES
src/support/unlink.C src/support/unlink.cpp NOCLASSES
src/support/os_win32.C src/support/os_win32.cpp GetFolderPath
src/support/lstrings.C src/support/lstrings.cpp NOCLASSES
src/support/qstring_helpers.C src/support/qstring_helpers.cpp NOCLASSES
src/support/getcwd.C src/support/getcwd.cpp NOCLASSES
src/support/systemcall.C src/support/Systemcall.cpp Systemcall
src/support/lyxalgo.h src/support/lyxalgo.h NOCLASSES
src/support/filefilterlist.h src/support/FileFilterList.h ['FileFilterList', 'Filter']
src/support/unicode.C src/support/unicode.cpp IconvProcessor
src/support/userinfo.C src/support/userinfo.cpp NOCLASSES
src/support/lyxtime.C src/support/lyxtime.cpp NOCLASSES
src/support/kill.C src/support/kill.cpp NOCLASSES
src/support/docstring.C src/support/docstring.cpp to_local8bit_failure
src/support/os_cygwin.C src/support/os_cygwin.cpp NOCLASSES
src/support/lyxsum.C src/support/lyxsum.cpp NOCLASSES
src/support/environment.C src/support/environment.cpp NOCLASSES
src/support/filetools.h src/support/filetools.h NOCLASSES
src/support/textutils.C src/support/textutils.cpp NOCLASSES
src/support/mkdir.C src/support/mkdir.cpp NOCLASSES
src/support/forkedcall.C src/support/Forkedcall.cpp ['ForkedProcess', 'Forkedcall']
src/support/tempname.C src/support/tempname.cpp NOCLASSES
src/support/os_win32.h src/support/os_win32.h GetFolderPath
src/support/types.h src/support/types.h NOCLASSES
src/support/lstrings.h src/support/lstrings.h NOCLASSES
src/support/forkedcallqueue.C src/support/ForkedCallQueue.cpp ForkedCallQueue
src/support/qstring_helpers.h src/support/qstring_helpers.h NOCLASSES
src/support/convert.C src/support/convert.cpp NOCLASSES
src/support/filename.C src/support/FileName.cpp ['FileName', 'DocFileName']
src/support/tests/convert.C src/support/tests/convert.cpp NOCLASSES
src/support/tests/filetools.C src/support/tests/filetools.cpp NOCLASSES
src/support/tests/lstrings.C src/support/tests/lstrings.cpp NOCLASSES
src/support/tests/boost.C src/support/tests/boost.cpp NOCLASSES
src/support/docstream.C src/support/docstream.cpp ['iconv_codecvt_facet_exception', 'idocfstream', 'odocfstream']
src/support/std_istream.h src/support/std_istream.h NOCLASSES
src/support/systemcall.h src/support/Systemcall.h Systemcall
src/support/chdir.C src/support/chdir.cpp NOCLASSES
src/support/std_ostream.h src/support/std_ostream.h NOCLASSES
src/support/unicode.h src/support/unicode.h IconvProcessor
src/support/path.C src/support/Path.cpp Path
src/support/fs_extras.C src/support/fs_extras.cpp NOCLASSES
src/support/userinfo.h src/support/userinfo.h NOCLASSES
src/support/lyxtime.h src/support/lyxtime.h NOCLASSES
src/support/docstring.h src/support/docstring.h to_local8bit_failure
src/support/debugstream.h src/support/debugstream.h basic_debugstream
src/support/environment.h src/support/environment.h NOCLASSES
src/support/textutils.h src/support/textutils.h NOCLASSES
src/support/forkedcall.h src/support/Forkedcall.h ['ForkedProcess', 'Forkedcall']
src/support/socktools.C src/support/socktools.cpp NOCLASSES
src/support/forkedcallqueue.h src/support/ForkedCallQueue.h ForkedCallQueue
src/support/forkedcontr.C src/support/ForkedcallsController.cpp ForkedcallsController
src/support/os.C src/support/os.cpp NOCLASSES
src/support/convert.h src/support/convert.h NOCLASSES
src/support/filename.h src/support/FileName.h ['FileName', 'DocFileName']
src/support/docstream.h src/support/docstream.h ['iconv_codecvt_facet_exception', 'idocfstream', 'odocfstream']
src/support/FileMonitor.C src/support/FileMonitor.cpp FileMonitor
git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@18024 a592a061-630c-0410-9148-cb99ea01b6c8
2007-04-26 05:12:52 +00:00
|
|
|
|
#include "support/FileName.h"
|
1999-10-02 16:21:10 +00:00
|
|
|
|
#include "support/lstrings.h"
|
1999-09-27 18:44:28 +00:00
|
|
|
|
|
2004-07-22 13:44:40 +00:00
|
|
|
|
#include <boost/bind.hpp>
|
|
|
|
|
|
2003-09-05 22:17:02 +00:00
|
|
|
|
#include <cerrno>
|
2005-04-26 10:30:24 +00:00
|
|
|
|
#ifdef HAVE_SYS_STAT_H
|
|
|
|
|
# include <sys/stat.h>
|
|
|
|
|
#endif
|
2003-09-05 22:17:02 +00:00
|
|
|
|
#include <fcntl.h>
|
|
|
|
|
|
2007-12-12 10:16:00 +00:00
|
|
|
|
using namespace std;
|
2007-12-12 18:57:56 +00:00
|
|
|
|
using namespace lyx::support;
|
2006-10-21 00:16:43 +00:00
|
|
|
|
|
|
|
|
|
namespace lyx {
|
|
|
|
|
|
2007-09-16 20:58:22 +00:00
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
|
|
|
//
|
|
|
|
|
// LyXComm
|
|
|
|
|
//
|
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
2005-05-02 13:35:30 +00:00
|
|
|
|
#if !defined (HAVE_MKFIFO)
|
|
|
|
|
// We provide a stub class that disables the lyxserver.
|
|
|
|
|
|
2007-12-12 19:28:07 +00:00
|
|
|
|
LyXComm::LyXComm(string const &, Server *, ClientCallbackfct)
|
2007-09-16 20:58:22 +00:00
|
|
|
|
{}
|
|
|
|
|
|
2005-05-02 13:35:30 +00:00
|
|
|
|
void LyXComm::openConnection()
|
|
|
|
|
{}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void LyXComm::closeConnection()
|
|
|
|
|
{}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int LyXComm::startPipe(string const & filename, bool write)
|
|
|
|
|
{
|
|
|
|
|
return -1;
|
1999-09-27 18:44:28 +00:00
|
|
|
|
}
|
2005-05-02 13:35:30 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void LyXComm::endPipe(int & fd, string const & filename, bool write)
|
|
|
|
|
{}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void LyXComm::emergencyCleanup()
|
|
|
|
|
{}
|
|
|
|
|
|
|
|
|
|
void LyXComm::read_ready()
|
|
|
|
|
{}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void LyXComm::send(string const & msg)
|
|
|
|
|
{}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#else // defined (HAVE_MKFIFO)
|
1999-09-27 18:44:28 +00:00
|
|
|
|
|
|
|
|
|
|
2007-12-12 19:28:07 +00:00
|
|
|
|
LyXComm::LyXComm(string const & pip, Server * cli, ClientCallbackfct ccb)
|
2007-09-16 20:58:22 +00:00
|
|
|
|
: pipename_(pip), client_(cli), clientcb_(ccb)
|
|
|
|
|
{
|
|
|
|
|
ready_ = false;
|
|
|
|
|
openConnection();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2001-09-09 22:02:19 +00:00
|
|
|
|
void LyXComm::openConnection()
|
|
|
|
|
{
|
2007-11-15 20:04:51 +00:00
|
|
|
|
LYXERR(Debug::LYXSERVER, "LyXComm: Opening connection");
|
2002-03-21 17:27:08 +00:00
|
|
|
|
|
1999-09-27 18:44:28 +00:00
|
|
|
|
// If we are up, that's an error
|
2007-09-16 20:58:22 +00:00
|
|
|
|
if (ready_) {
|
1999-10-07 18:44:17 +00:00
|
|
|
|
lyxerr << "LyXComm: Already connected" << endl;
|
1999-09-27 18:44:28 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
// We assume that we don't make it
|
2007-09-16 20:58:22 +00:00
|
|
|
|
ready_ = false;
|
2002-03-21 17:27:08 +00:00
|
|
|
|
|
2007-09-16 20:58:22 +00:00
|
|
|
|
if (pipename_.empty()) {
|
2007-11-15 20:04:51 +00:00
|
|
|
|
LYXERR(Debug::LYXSERVER, "LyXComm: server is disabled, nothing to do");
|
2001-11-14 12:00:51 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
1999-09-27 18:44:28 +00:00
|
|
|
|
|
2007-09-16 20:58:22 +00:00
|
|
|
|
infd_ = startPipe(inPipeName(), false);
|
|
|
|
|
if (infd_ == -1)
|
2001-10-19 15:13:49 +00:00
|
|
|
|
return;
|
|
|
|
|
|
2007-09-16 20:58:22 +00:00
|
|
|
|
outfd_ = startPipe(outPipeName(), true);
|
|
|
|
|
if (outfd_ == -1) {
|
|
|
|
|
endPipe(infd_, inPipeName(), false);
|
2001-10-19 15:13:49 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
2002-03-21 17:27:08 +00:00
|
|
|
|
|
2007-09-16 20:58:22 +00:00
|
|
|
|
if (fcntl(outfd_, F_SETFL, O_NONBLOCK) < 0) {
|
2001-11-12 17:43:21 +00:00
|
|
|
|
lyxerr << "LyXComm: Could not set flags on pipe " << outPipeName()
|
2001-10-19 15:13:49 +00:00
|
|
|
|
<< '\n' << strerror(errno) << endl;
|
|
|
|
|
return;
|
|
|
|
|
}
|
2002-03-21 17:27:08 +00:00
|
|
|
|
|
2001-10-19 15:13:49 +00:00
|
|
|
|
// We made it!
|
2007-09-16 20:58:22 +00:00
|
|
|
|
ready_ = true;
|
2007-11-15 20:04:51 +00:00
|
|
|
|
LYXERR(Debug::LYXSERVER, "LyXComm: Connection established");
|
2001-10-19 15:13:49 +00:00
|
|
|
|
}
|
|
|
|
|
|
2002-03-21 17:27:08 +00:00
|
|
|
|
|
2001-10-19 15:13:49 +00:00
|
|
|
|
/// Close pipes
|
|
|
|
|
void LyXComm::closeConnection()
|
|
|
|
|
{
|
2007-11-15 20:04:51 +00:00
|
|
|
|
LYXERR(Debug::LYXSERVER, "LyXComm: Closing connection");
|
2001-10-19 15:13:49 +00:00
|
|
|
|
|
2007-09-16 20:58:22 +00:00
|
|
|
|
if (pipename_.empty()) {
|
2007-11-15 20:04:51 +00:00
|
|
|
|
LYXERR(Debug::LYXSERVER, "LyXComm: server is disabled, nothing to do");
|
2002-03-21 17:27:08 +00:00
|
|
|
|
return;
|
2001-10-19 15:13:49 +00:00
|
|
|
|
}
|
|
|
|
|
|
2007-09-16 20:58:22 +00:00
|
|
|
|
if (!ready_) {
|
2007-11-30 22:02:33 +00:00
|
|
|
|
LYXERR0("LyXComm: Already disconnected");
|
2001-10-19 15:13:49 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
2002-03-21 17:27:08 +00:00
|
|
|
|
|
2007-09-16 20:58:22 +00:00
|
|
|
|
endPipe(infd_, inPipeName(), false);
|
|
|
|
|
endPipe(outfd_, outPipeName(), true);
|
2002-03-21 17:27:08 +00:00
|
|
|
|
|
2007-09-16 20:58:22 +00:00
|
|
|
|
ready_ = false;
|
2001-10-19 15:13:49 +00:00
|
|
|
|
}
|
|
|
|
|
|
2003-10-06 15:43:21 +00:00
|
|
|
|
|
2006-11-26 21:30:39 +00:00
|
|
|
|
int LyXComm::startPipe(string const & file, bool write)
|
2001-10-19 15:13:49 +00:00
|
|
|
|
{
|
2008-11-26 19:10:42 +00:00
|
|
|
|
static bool stalepipe = false;
|
2006-11-26 21:30:39 +00:00
|
|
|
|
FileName const filename(file);
|
2008-11-26 19:10:42 +00:00
|
|
|
|
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;
|
|
|
|
|
}
|
1999-09-27 18:44:28 +00:00
|
|
|
|
}
|
2002-03-21 17:27:08 +00:00
|
|
|
|
|
2006-11-26 21:30:39 +00:00
|
|
|
|
if (::mkfifo(filename.toFilesystemEncoding().c_str(), 0600) < 0) {
|
2001-10-19 15:13:49 +00:00
|
|
|
|
lyxerr << "LyXComm: Could not create pipe " << filename << '\n'
|
1999-10-07 18:44:17 +00:00
|
|
|
|
<< strerror(errno) << endl;
|
2001-10-19 15:13:49 +00:00
|
|
|
|
return -1;
|
2007-09-16 20:58:22 +00:00
|
|
|
|
}
|
2006-11-26 21:30:39 +00:00
|
|
|
|
int const fd = ::open(filename.toFilesystemEncoding().c_str(),
|
2005-02-15 11:04:40 +00:00
|
|
|
|
write ? (O_RDWR) : (O_RDONLY|O_NONBLOCK));
|
2002-03-21 17:27:08 +00:00
|
|
|
|
|
2001-10-19 15:13:49 +00:00
|
|
|
|
if (fd < 0) {
|
|
|
|
|
lyxerr << "LyXComm: Could not open pipe " << filename << '\n'
|
1999-10-07 18:44:17 +00:00
|
|
|
|
<< strerror(errno) << endl;
|
2007-11-28 09:01:49 +00:00
|
|
|
|
filename.removeFile();
|
2001-10-19 15:13:49 +00:00
|
|
|
|
return -1;
|
2001-09-09 22:02:19 +00:00
|
|
|
|
}
|
2002-03-21 17:27:08 +00:00
|
|
|
|
|
2002-07-14 01:44:15 +00:00
|
|
|
|
if (!write) {
|
2006-11-30 08:42:29 +00:00
|
|
|
|
theApp()->registerSocketCallback(fd,
|
2006-10-12 14:10:13 +00:00
|
|
|
|
boost::bind(&LyXComm::read_ready, this));
|
2002-07-14 01:44:15 +00:00
|
|
|
|
}
|
2002-03-21 17:27:08 +00:00
|
|
|
|
|
2001-10-19 15:13:49 +00:00
|
|
|
|
return fd;
|
1999-09-27 18:44:28 +00:00
|
|
|
|
}
|
2001-09-09 22:02:19 +00:00
|
|
|
|
|
2001-10-19 15:13:49 +00:00
|
|
|
|
|
2002-07-30 22:35:43 +00:00
|
|
|
|
void LyXComm::endPipe(int & fd, string const & filename, bool write)
|
2001-09-09 22:02:19 +00:00
|
|
|
|
{
|
2001-10-19 15:13:49 +00:00
|
|
|
|
if (fd < 0)
|
|
|
|
|
return;
|
|
|
|
|
|
2007-09-16 20:58:22 +00:00
|
|
|
|
if (!write)
|
2006-11-30 08:42:29 +00:00
|
|
|
|
theApp()->unregisterSocketCallback(fd);
|
2002-11-27 10:30:28 +00:00
|
|
|
|
|
2001-10-19 15:13:49 +00:00
|
|
|
|
if (::close(fd) < 0) {
|
|
|
|
|
lyxerr << "LyXComm: Could not close pipe " << filename
|
|
|
|
|
<< '\n' << strerror(errno) << endl;
|
1999-09-27 18:44:28 +00:00
|
|
|
|
}
|
2002-03-21 17:27:08 +00:00
|
|
|
|
|
2007-11-28 09:01:49 +00:00
|
|
|
|
if (FileName(filename).removeFile() < 0) {
|
2001-10-19 15:13:49 +00:00
|
|
|
|
lyxerr << "LyXComm: Could not remove pipe " << filename
|
|
|
|
|
<< '\n' << strerror(errno) << endl;
|
2007-09-16 20:58:22 +00:00
|
|
|
|
}
|
2001-11-08 11:46:06 +00:00
|
|
|
|
|
|
|
|
|
fd = -1;
|
2001-10-19 15:13:49 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void LyXComm::emergencyCleanup()
|
|
|
|
|
{
|
2007-09-16 20:58:22 +00:00
|
|
|
|
if (!pipename_.empty()) {
|
|
|
|
|
endPipe(infd_, inPipeName(), false);
|
|
|
|
|
endPipe(outfd_, outPipeName(), true);
|
2001-11-14 12:00:51 +00:00
|
|
|
|
}
|
1999-09-27 18:44:28 +00:00
|
|
|
|
}
|
2001-09-09 22:02:19 +00:00
|
|
|
|
|
|
|
|
|
|
1999-09-27 18:44:28 +00:00
|
|
|
|
// Receives messages and sends then to client
|
2002-07-14 01:44:15 +00:00
|
|
|
|
void LyXComm::read_ready()
|
1999-09-27 18:44:28 +00:00
|
|
|
|
{
|
2007-09-16 20:58:22 +00:00
|
|
|
|
// FIXME: make read_buffer_ a class-member for multiple sessions
|
2002-09-11 16:48:07 +00:00
|
|
|
|
static string read_buffer_;
|
|
|
|
|
read_buffer_.erase();
|
2002-03-21 17:27:08 +00:00
|
|
|
|
|
2002-09-11 16:48:07 +00:00
|
|
|
|
int const charbuf_size = 100;
|
|
|
|
|
char charbuf[charbuf_size];
|
1999-09-27 18:44:28 +00:00
|
|
|
|
|
2008-10-05 00:50:39 +00:00
|
|
|
|
// 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.
|
|
|
|
|
|
1999-09-27 18:44:28 +00:00
|
|
|
|
errno = 0;
|
|
|
|
|
int status;
|
|
|
|
|
// the single = is intended here.
|
2007-09-16 20:58:22 +00:00
|
|
|
|
while ((status = ::read(infd_, charbuf, charbuf_size - 1))) {
|
2002-09-11 16:48:07 +00:00
|
|
|
|
|
2002-07-14 01:44:15 +00:00
|
|
|
|
if (status > 0) {
|
2002-09-11 16:48:07 +00:00
|
|
|
|
charbuf[status] = '\0'; // turn it into a c string
|
|
|
|
|
read_buffer_ += rtrim(charbuf, "\r");
|
2003-02-06 01:18:36 +00:00
|
|
|
|
// commit any commands read
|
|
|
|
|
while (read_buffer_.find('\n') != string::npos) {
|
|
|
|
|
// split() grabs the entire string if
|
|
|
|
|
// the delim /wasn't/ found. ?:-P
|
|
|
|
|
string cmd;
|
|
|
|
|
read_buffer_= split(read_buffer_, cmd,'\n');
|
2007-11-15 20:04:51 +00:00
|
|
|
|
LYXERR(Debug::LYXSERVER, "LyXComm: status:" << status
|
2003-02-06 01:18:36 +00:00
|
|
|
|
<< ", read_buffer_:" << read_buffer_
|
2007-11-15 20:04:51 +00:00
|
|
|
|
<< ", cmd:" << cmd);
|
2003-02-06 01:18:36 +00:00
|
|
|
|
if (!cmd.empty())
|
2007-09-16 20:58:22 +00:00
|
|
|
|
clientcb_(client_, cmd);
|
2003-02-06 01:18:36 +00:00
|
|
|
|
//\n or not \n?
|
|
|
|
|
}
|
2008-10-05 00:50:39 +00:00
|
|
|
|
} else {
|
|
|
|
|
if (errno == EAGAIN) {
|
|
|
|
|
// Nothing to read, continue
|
|
|
|
|
errno = 0;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
// An error occurred, better bailing out
|
2007-11-30 22:02:33 +00:00
|
|
|
|
LYXERR0("LyXComm: " << strerror(errno));
|
2002-09-11 16:48:07 +00:00
|
|
|
|
if (!read_buffer_.empty()) {
|
2007-11-30 22:02:33 +00:00
|
|
|
|
LYXERR0("LyXComm: truncated command: " << read_buffer_);
|
2002-09-11 16:48:07 +00:00
|
|
|
|
read_buffer_.erase();
|
1999-09-27 18:44:28 +00:00
|
|
|
|
}
|
2003-02-06 01:18:36 +00:00
|
|
|
|
break; // reset connection
|
1999-09-27 18:44:28 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2002-09-11 16:48:07 +00:00
|
|
|
|
|
2008-10-05 00:50:39 +00:00
|
|
|
|
// 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.
|
2003-02-06 01:18:36 +00:00
|
|
|
|
closeConnection();
|
|
|
|
|
openConnection();
|
2002-09-11 16:48:07 +00:00
|
|
|
|
errno = 0;
|
1999-09-27 18:44:28 +00:00
|
|
|
|
}
|
1999-10-25 14:18:30 +00:00
|
|
|
|
|
|
|
|
|
|
2001-09-09 22:02:19 +00:00
|
|
|
|
void LyXComm::send(string const & msg)
|
|
|
|
|
{
|
1999-09-27 18:44:28 +00:00
|
|
|
|
if (msg.empty()) {
|
2007-11-30 22:02:33 +00:00
|
|
|
|
LYXERR0("LyXComm: Request to send empty string. Ignoring.");
|
1999-09-27 18:44:28 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2007-11-15 20:04:51 +00:00
|
|
|
|
LYXERR(Debug::LYXSERVER, "LyXComm: Sending '" << msg << '\'');
|
1999-09-27 18:44:28 +00:00
|
|
|
|
|
2007-09-16 20:58:22 +00:00
|
|
|
|
if (pipename_.empty()) return;
|
1999-09-27 18:44:28 +00:00
|
|
|
|
|
2007-09-16 20:58:22 +00:00
|
|
|
|
if (!ready_) {
|
2007-11-30 22:02:33 +00:00
|
|
|
|
LYXERR0("LyXComm: Pipes are closed. Could not send " << msg);
|
2007-09-16 20:58:22 +00:00
|
|
|
|
} else if (::write(outfd_, msg.c_str(), msg.length()) < 0) {
|
1999-10-07 18:44:17 +00:00
|
|
|
|
lyxerr << "LyXComm: Error sending message: " << msg
|
|
|
|
|
<< '\n' << strerror(errno)
|
|
|
|
|
<< "\nLyXComm: Resetting connection" << endl;
|
1999-09-27 18:44:28 +00:00
|
|
|
|
closeConnection();
|
|
|
|
|
openConnection();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2005-05-02 13:35:30 +00:00
|
|
|
|
#endif // defined (HAVE_MKFIFO)
|
|
|
|
|
|
1999-09-27 18:44:28 +00:00
|
|
|
|
|
2005-01-20 15:07:36 +00:00
|
|
|
|
string const LyXComm::inPipeName() const
|
|
|
|
|
{
|
2007-09-16 20:58:22 +00:00
|
|
|
|
return pipename_ + ".in";
|
2005-01-20 15:07:36 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
string const LyXComm::outPipeName() const
|
|
|
|
|
{
|
2007-09-16 20:58:22 +00:00
|
|
|
|
return pipename_ + ".out";
|
2005-01-20 15:07:36 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2007-09-16 20:58:22 +00:00
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
|
|
|
//
|
|
|
|
|
// Server
|
|
|
|
|
//
|
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
void ServerCallback(Server * server, string const & msg)
|
|
|
|
|
{
|
|
|
|
|
server->callback(msg);
|
|
|
|
|
}
|
|
|
|
|
|
2007-12-12 19:28:07 +00:00
|
|
|
|
Server::Server(LyXFunc * f, string const & pipes)
|
2007-09-16 20:58:22 +00:00
|
|
|
|
: numclients_(0), func_(f), pipes_(pipes, this, &ServerCallback)
|
|
|
|
|
{}
|
|
|
|
|
|
1999-09-27 18:44:28 +00:00
|
|
|
|
|
2007-04-29 16:22:46 +00:00
|
|
|
|
Server::~Server()
|
1999-09-27 18:44:28 +00:00
|
|
|
|
{
|
|
|
|
|
// say goodbye to clients so they stop sending messages
|
2007-09-16 20:58:22 +00:00
|
|
|
|
// send as many bye messages as there are clients,
|
|
|
|
|
// each with client's name.
|
1999-10-02 16:21:10 +00:00
|
|
|
|
string message;
|
2007-09-16 20:58:22 +00:00
|
|
|
|
for (int i = 0; i != numclients_; ++i) {
|
|
|
|
|
message = "LYXSRV:" + clients_[i] + ":bye\n";
|
|
|
|
|
pipes_.send(message);
|
1999-09-27 18:44:28 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2007-11-30 22:02:33 +00:00
|
|
|
|
int compare(char const * a, char const * b, unsigned int len)
|
|
|
|
|
{
|
|
|
|
|
using namespace std;
|
|
|
|
|
return strncmp(a, b, len);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2007-09-16 20:58:22 +00:00
|
|
|
|
// Handle data gotten from communication, called by LyXComm
|
|
|
|
|
void Server::callback(string const & msg)
|
1999-09-27 18:44:28 +00:00
|
|
|
|
{
|
2007-11-15 20:04:51 +00:00
|
|
|
|
LYXERR(Debug::LYXSERVER, "Server: Received: '" << msg << '\'');
|
2002-03-21 17:27:08 +00:00
|
|
|
|
|
2000-09-26 13:54:57 +00:00
|
|
|
|
char const * p = msg.c_str();
|
2002-03-21 17:27:08 +00:00
|
|
|
|
|
1999-09-27 18:44:28 +00:00
|
|
|
|
// --- parse the string --------------------------------------------
|
|
|
|
|
//
|
|
|
|
|
// Format: LYXCMD:<client>:<func>:<argstring>\n
|
|
|
|
|
//
|
|
|
|
|
bool server_only = false;
|
2001-12-05 08:04:20 +00:00
|
|
|
|
while (*p) {
|
1999-09-27 18:44:28 +00:00
|
|
|
|
// --- 1. check 'header' ---
|
2000-04-11 16:57:16 +00:00
|
|
|
|
|
2002-03-21 17:27:08 +00:00
|
|
|
|
if (compare(p, "LYXSRV:", 7) == 0) {
|
|
|
|
|
server_only = true;
|
2001-02-16 09:25:43 +00:00
|
|
|
|
} else if (0 != compare(p, "LYXCMD:", 7)) {
|
2007-04-29 16:22:46 +00:00
|
|
|
|
lyxerr << "Server: Unknown request \""
|
2002-11-27 10:30:28 +00:00
|
|
|
|
<< p << '"' << endl;
|
1999-09-27 18:44:28 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
p += 7;
|
2002-03-21 17:27:08 +00:00
|
|
|
|
|
1999-09-27 18:44:28 +00:00
|
|
|
|
// --- 2. for the moment ignore the client name ---
|
1999-10-02 16:21:10 +00:00
|
|
|
|
string client;
|
2001-12-05 08:04:20 +00:00
|
|
|
|
while (*p && *p != ':')
|
1999-09-27 18:44:28 +00:00
|
|
|
|
client += char(*p++);
|
2007-09-16 20:58:22 +00:00
|
|
|
|
if (*p == ':')
|
|
|
|
|
++p;
|
|
|
|
|
if (!*p)
|
|
|
|
|
return;
|
2002-03-21 17:27:08 +00:00
|
|
|
|
|
1999-09-27 18:44:28 +00:00
|
|
|
|
// --- 3. get function name ---
|
1999-10-02 16:21:10 +00:00
|
|
|
|
string cmd;
|
2001-12-05 08:04:20 +00:00
|
|
|
|
while (*p && *p != ':')
|
1999-09-27 18:44:28 +00:00
|
|
|
|
cmd += char(*p++);
|
2002-03-21 17:27:08 +00:00
|
|
|
|
|
1999-09-27 18:44:28 +00:00
|
|
|
|
// --- 4. parse the argument ---
|
1999-10-02 16:21:10 +00:00
|
|
|
|
string arg;
|
2000-11-04 10:00:12 +00:00
|
|
|
|
if (!server_only && *p == ':' && *(++p)) {
|
2001-12-05 08:04:20 +00:00
|
|
|
|
while (*p && *p != '\n')
|
1999-09-27 18:44:28 +00:00
|
|
|
|
arg += char(*p++);
|
2000-11-04 10:00:12 +00:00
|
|
|
|
if (*p) ++p;
|
1999-09-27 18:44:28 +00:00
|
|
|
|
}
|
2002-03-21 17:27:08 +00:00
|
|
|
|
|
2007-11-15 20:04:51 +00:00
|
|
|
|
LYXERR(Debug::LYXSERVER, "Server: Client: '" << client
|
|
|
|
|
<< "' Command: '" << cmd << "' Argument: '" << arg << '\'');
|
2002-03-21 17:27:08 +00:00
|
|
|
|
|
1999-09-27 18:44:28 +00:00
|
|
|
|
// --- lookup and exec the command ------------------
|
2002-03-21 17:27:08 +00:00
|
|
|
|
|
1999-09-27 18:44:28 +00:00
|
|
|
|
if (server_only) {
|
1999-10-02 16:21:10 +00:00
|
|
|
|
string buf;
|
2002-03-21 17:27:08 +00:00
|
|
|
|
// return the greeting to inform the client that
|
1999-09-27 18:44:28 +00:00
|
|
|
|
// we are listening.
|
|
|
|
|
if (cmd == "hello") {
|
|
|
|
|
// One more client
|
2007-09-16 20:58:22 +00:00
|
|
|
|
if (numclients_ == MAX_CLIENTS) { //paranoid check
|
2007-11-15 20:04:51 +00:00
|
|
|
|
LYXERR(Debug::LYXSERVER, "Server: too many clients...");
|
1999-09-27 18:44:28 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
2007-09-16 20:58:22 +00:00
|
|
|
|
int i = 0;
|
|
|
|
|
while (!clients_[i].empty() && i < numclients_)
|
2000-01-24 18:34:46 +00:00
|
|
|
|
++i;
|
2007-09-16 20:58:22 +00:00
|
|
|
|
clients_[i] = client;
|
|
|
|
|
++numclients_;
|
1999-09-27 18:44:28 +00:00
|
|
|
|
buf = "LYXSRV:" + client + ":hello\n";
|
2007-11-15 20:04:51 +00:00
|
|
|
|
LYXERR(Debug::LYXSERVER, "Server: Greeting " << client);
|
2007-09-16 20:58:22 +00:00
|
|
|
|
pipes_.send(buf);
|
1999-09-27 18:44:28 +00:00
|
|
|
|
} else if (cmd == "bye") {
|
2007-09-16 20:58:22 +00:00
|
|
|
|
// If clients_ == 0 maybe we should reset the pipes
|
1999-09-27 18:44:28 +00:00
|
|
|
|
// to prevent fake callbacks
|
2000-01-24 18:34:46 +00:00
|
|
|
|
int i = 0; //look if client is registered
|
2007-09-16 20:58:22 +00:00
|
|
|
|
for (; i < numclients_; ++i) {
|
|
|
|
|
if (clients_[i] == client)
|
|
|
|
|
break;
|
1999-09-27 18:44:28 +00:00
|
|
|
|
}
|
2007-09-16 20:58:22 +00:00
|
|
|
|
if (i < numclients_) {
|
|
|
|
|
--numclients_;
|
|
|
|
|
clients_[i].erase();
|
2007-11-15 20:04:51 +00:00
|
|
|
|
LYXERR(Debug::LYXSERVER, "Server: Client "
|
|
|
|
|
<< client << " said goodbye");
|
1999-09-27 18:44:28 +00:00
|
|
|
|
} else {
|
2007-11-15 20:04:51 +00:00
|
|
|
|
LYXERR(Debug::LYXSERVER,
|
|
|
|
|
"Server: ignoring bye messge from unregistered client" << client);
|
1999-09-27 18:44:28 +00:00
|
|
|
|
}
|
|
|
|
|
} else {
|
2007-11-30 22:02:33 +00:00
|
|
|
|
LYXERR0("Server: Undefined server command " << cmd << '.');
|
1999-09-27 18:44:28 +00:00
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
2002-03-21 17:27:08 +00:00
|
|
|
|
|
1999-09-27 18:44:28 +00:00
|
|
|
|
if (!cmd.empty()) {
|
|
|
|
|
// which lyxfunc should we let it connect to?
|
|
|
|
|
// The correct solution would be to have a
|
|
|
|
|
// specialized (non-gui) BufferView. But how do
|
|
|
|
|
// we do it now? Probably we should just let it
|
|
|
|
|
// connect to the lyxfunc in the single LyXView we
|
|
|
|
|
// support currently. (Lgb)
|
|
|
|
|
|
2007-09-16 20:58:22 +00:00
|
|
|
|
func_->dispatch(FuncRequest(lyxaction.lookupFunc(cmd), arg));
|
|
|
|
|
string const rval = to_utf8(func_->getMessage());
|
1999-09-27 18:44:28 +00:00
|
|
|
|
|
2007-09-16 20:58:22 +00:00
|
|
|
|
// all commands produce an INFO or ERROR message
|
|
|
|
|
// in the output pipe, even if they do not return
|
|
|
|
|
// anything. See chapter 4 of Customization doc.
|
2002-05-28 23:04:57 +00:00
|
|
|
|
string buf;
|
2007-09-16 20:58:22 +00:00
|
|
|
|
if (func_->errorStat())
|
1999-09-27 18:44:28 +00:00
|
|
|
|
buf = "ERROR:";
|
|
|
|
|
else
|
|
|
|
|
buf = "INFO:";
|
2002-11-27 10:30:28 +00:00
|
|
|
|
buf += client + ':' + cmd + ':' + rval + '\n';
|
2007-09-16 20:58:22 +00:00
|
|
|
|
pipes_.send(buf);
|
1999-09-27 18:44:28 +00:00
|
|
|
|
|
|
|
|
|
// !!! we don't do any error checking -
|
|
|
|
|
// if the client won't listen, the
|
|
|
|
|
// message is lost and others too
|
|
|
|
|
// maybe; so the client should empty
|
|
|
|
|
// the outpipe before issuing a request.
|
2002-03-21 17:27:08 +00:00
|
|
|
|
|
1999-09-27 18:44:28 +00:00
|
|
|
|
// not found
|
|
|
|
|
}
|
2007-09-16 20:58:22 +00:00
|
|
|
|
} // while *p
|
1999-09-27 18:44:28 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2008-07-07 17:26:07 +00:00
|
|
|
|
// Send a notify message to a client, called by WorkAreaKeyPress
|
2007-04-29 16:22:46 +00:00
|
|
|
|
void Server::notifyClient(string const & s)
|
1999-09-27 18:44:28 +00:00
|
|
|
|
{
|
2007-09-16 20:58:22 +00:00
|
|
|
|
pipes_.send("NOTIFY:" + s + "\n");
|
1999-09-27 18:44:28 +00:00
|
|
|
|
}
|
2006-10-21 00:16:43 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} // namespace lyx
|