3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
6 * \author Lars Gullik Bjønnes
7 * \author Jean-Marc Lasgouttes
8 * \author Angus Leeming
10 * \author Enrico Forestieri
12 * Full author contact details are available in file CREDITS.
16 Docu : To use the lyxserver define the name of the pipe in your
18 \serverpipe "/home/myhome/.lyxpipe"
19 Then use .lyxpipe.in and .lyxpipe.out to communicate to LyX.
20 Each message consists of a single line in ASCII. Input lines
21 (client -> LyX) have the following format:
22 "LYXCMD:<clientname>:<functionname>:<argument>"
23 Answers from LyX look like this:
24 "INFO:<clientname>:<functionname>:<data>"
25 [asierra970531] Or like this in case of error:
26 "ERROR:<clientname>:<functionname>:<error message>"
27 where <clientname> and <functionname> are just echoed.
28 If LyX notifies about a user defined extension key-sequence,
29 the line looks like this:
30 "NOTIFY:<key-sequence>"
31 [asierra970531] New server-only messages to implement a simple protocol
32 "LYXSRV:<clientname>:<protocol message>"
33 where <protocol message> can be "hello" or "bye". If hello is
34 received LyX will inform the client that it's listening its
35 messages, and 'bye' will inform that lyx is closing.
37 See development/lyxserver/server_monitor.cpp for an example client.
38 Purpose: implement a client/server lib for LyX
45 #include "DispatchResult.h"
46 #include "FuncRequest.h"
48 #include "LyXAction.h"
50 #include "frontends/Application.h"
52 #include "support/debug.h"
53 #include "support/FileName.h"
54 #include "support/filetools.h"
55 #include "support/lassert.h"
56 #include "support/lstrings.h"
57 #include "support/os.h"
63 # include <QCoreApplication>
72 #ifdef HAVE_SYS_STAT_H
73 # include <sys/stat.h>
78 using namespace lyx::support;
79 using os::external_path;
83 /////////////////////////////////////////////////////////////////////
87 /////////////////////////////////////////////////////////////////////
91 class ReadReadyEvent : public QEvent {
94 ReadReadyEvent(DWORD inpipe) : QEvent(QEvent::User), inpipe_(inpipe)
97 DWORD inpipe() const { return inpipe_; }
105 string errormsg(DWORD const error)
109 if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
110 FORMAT_MESSAGE_FROM_SYSTEM |
111 FORMAT_MESSAGE_IGNORE_INSERTS,
113 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
114 (LPTSTR) &msgbuf, 0, NULL)) {
115 message = static_cast<char *>(msgbuf);
118 message = "Unknown error";
126 DWORD WINAPI pipeServerWrapper(void * arg)
128 LyXComm * lyxcomm = reinterpret_cast<LyXComm *>(arg);
129 if (!lyxcomm->pipeServer()) {
130 // Error exit; perform cleanup.
131 lyxcomm->ready_ = false;
132 lyxcomm->closeHandles();
133 CloseHandle(lyxcomm->server_thread_);
134 CloseHandle(lyxcomm->stopserver_);
135 CloseHandle(lyxcomm->outbuf_mutex_);
136 lyxerr << "LyXComm: Closing connection" << endl;
142 LyXComm::LyXComm(string const & pip, Server * cli, ClientCallbackfct ccb)
144 ready_(false), pipename_(pip), client_(cli), clientcb_(ccb),
145 deferred_loading_(false)
147 for (int i = 0; i < MAX_PIPES; ++i) {
149 pipe_[i].handle = INVALID_HANDLE_VALUE;
155 bool LyXComm::pipeServer()
160 for (i = 0; i < MAX_PIPES; ++i) {
161 bool const is_outpipe = i >= MAX_CLIENTS;
162 DWORD const open_mode = is_outpipe ? PIPE_ACCESS_OUTBOUND
163 : PIPE_ACCESS_INBOUND;
164 string const pipename = external_path(pipeName(i));
166 // Manual-reset event, initial state = signaled
167 event_[i] = CreateEvent(NULL, TRUE, TRUE, NULL);
169 error = GetLastError();
170 lyxerr << "LyXComm: Could not create event for pipe "
171 << pipename << "\nLyXComm: "
172 << errormsg(error) << endl;
176 pipe_[i].overlap.hEvent = event_[i];
177 pipe_[i].iobuf.erase();
178 pipe_[i].handle = CreateNamedPipeA(pipename.c_str(),
179 open_mode | FILE_FLAG_OVERLAPPED, PIPE_WAIT,
180 MAX_CLIENTS, PIPE_BUFSIZE, PIPE_BUFSIZE,
183 if (pipe_[i].handle == INVALID_HANDLE_VALUE) {
184 error = GetLastError();
185 lyxerr << "LyXComm: Could not create pipe "
186 << pipename << "\nLyXComm: "
187 << errormsg(error) << endl;
193 pipe_[i].state = pipe_[i].pending_io ?
194 CONNECTING_STATE : (is_outpipe ? WRITING_STATE
198 // Add the stopserver_ event
199 event_[MAX_PIPES] = stopserver_;
202 LYXERR(Debug::LYXSERVER, "LyXComm: Connection established");
206 bool success = false;
208 while (!checkStopServer()) {
209 // Indefinitely wait for the completion of an overlapped
210 // read, write, or connect operation.
211 DWORD wait = WaitForMultipleObjects(MAX_PIPES + 1, event_,
214 // Determine which pipe instance completed the operation.
215 i = wait - WAIT_OBJECT_0;
216 LASSERT(i <= MAX_PIPES, /**/);
218 // Check whether we were waked up for stopping the pipe server.
222 bool const is_outpipe = i >= MAX_CLIENTS;
224 // Get the result if the operation was pending.
225 if (pipe_[i].pending_io) {
226 success = GetOverlappedResult(pipe_[i].handle,
227 &pipe_[i].overlap, &status, FALSE);
229 switch (pipe_[i].state) {
230 case CONNECTING_STATE:
231 // Pending connect operation
233 error = GetLastError();
234 lyxerr << "LyXComm: "
235 << errormsg(error) << endl;
236 if (!resetPipe(i, true))
240 pipe_[i].state = is_outpipe ? WRITING_STATE
245 // Pending read operation
246 LASSERT(!is_outpipe, /**/);
247 if (!success || status == 0) {
248 if (!resetPipe(i, !success))
252 pipe_[i].nbytes = status;
253 pipe_[i].state = WRITING_STATE;
257 // Pending write operation
258 LASSERT(is_outpipe, /**/);
259 // Let's see whether we have a reply
260 if (!outbuf_.empty()) {
261 // Yep. Deliver it to all pipe
262 // instances if we get ownership
263 // of the mutex, otherwise we'll
264 // try again the next round.
265 DWORD result = WaitForSingleObject(
267 if (result == WAIT_OBJECT_0) {
268 DWORD j = MAX_CLIENTS;
269 while (j < MAX_PIPES) {
270 pipe_[j].iobuf = outbuf_;
275 ReleaseMutex(outbuf_mutex_);
277 if (pipe_[i].iobuf.empty())
278 pipe_[i].pending_io = false;
283 // Operate according to the pipe state
284 switch (pipe_[i].state) {
286 // The pipe instance is connected to a client
287 // and is ready to read a request.
288 LASSERT(!is_outpipe, /**/);
289 success = ReadFile(pipe_[i].handle,
290 pipe_[i].readbuf, PIPE_BUFSIZE - 1,
291 &pipe_[i].nbytes, &pipe_[i].overlap);
293 if (success && pipe_[i].nbytes != 0) {
294 // The read operation completed successfully.
295 pipe_[i].pending_io = false;
296 pipe_[i].state = WRITING_STATE;
300 error = GetLastError();
302 if (!success && error == ERROR_IO_PENDING) {
303 // The read operation is still pending.
304 pipe_[i].pending_io = true;
308 success = error == ERROR_BROKEN_PIPE;
310 // Client closed connection (ERROR_BROKEN_PIPE) or
311 // an error occurred; in either case, reset the pipe.
313 lyxerr << "LyXComm: " << errormsg(error) << endl;
314 if (!pipe_[i].iobuf.empty()) {
315 lyxerr << "LyXComm: truncated command: "
316 << pipe_[i].iobuf << endl;
317 pipe_[i].iobuf.erase();
320 if (!resetPipe(i, !success))
326 // The request was successfully read
327 // from the client; commit it.
328 ReadReadyEvent * event = new ReadReadyEvent(i);
329 QCoreApplication::postEvent(this,
330 static_cast<QEvent *>(event));
331 // Wait for completion
332 while (pipe_[i].nbytes && !checkStopServer(100))
334 pipe_[i].pending_io = false;
335 pipe_[i].state = READING_STATE;
339 // This is an output pipe instance. Initiate the
340 // overlapped write operation or monitor its progress.
342 if (pipe_[i].pending_io) {
343 success = WriteFile(pipe_[i].handle,
344 pipe_[i].iobuf.c_str(),
345 pipe_[i].iobuf.length(),
350 if (success && !pipe_[i].iobuf.empty()
351 && status == pipe_[i].iobuf.length()) {
352 // The write operation completed successfully.
353 pipe_[i].iobuf.erase();
354 pipe_[i].pending_io = false;
360 error = GetLastError();
362 if (success && (error == ERROR_IO_PENDING || error == NO_ERROR)) {
363 // The write operation is still pending.
364 // We get here when a reader is started
365 // well before a reply is ready, so delay
366 // a bit in order to not burden the cpu.
367 checkStopServer(100);
368 pipe_[i].pending_io = true;
372 success = error == ERROR_NO_DATA;
374 // Client closed connection (ERROR_NO_DATA) or
375 // an error occurred; in either case, reset the pipe.
377 lyxerr << "LyXComm: Error sending message: "
378 << pipe_[i].iobuf << "\nLyXComm: "
379 << errormsg(error) << endl;
381 if (!resetPipe(i, !success))
384 case CONNECTING_STATE:
385 LYXERR0("Wrong pipe state");
396 void LyXComm::closeHandles()
398 for (int i = 0; i < MAX_PIPES; ++i) {
400 ResetEvent(event_[i]);
401 CloseHandle(event_[i]);
404 if (pipe_[i].handle != INVALID_HANDLE_VALUE) {
405 CloseHandle(pipe_[i].handle);
406 pipe_[i].handle = INVALID_HANDLE_VALUE;
412 bool LyXComm::event(QEvent * e)
414 if (e->type() == QEvent::User) {
415 read_ready(static_cast<ReadReadyEvent *>(e)->inpipe());
422 bool LyXComm::checkStopServer(DWORD timeout)
424 return WaitForSingleObject(stopserver_, timeout) == WAIT_OBJECT_0;
428 bool LyXComm::startPipe(DWORD index)
430 pipe_[index].pending_io = false;
431 pipe_[index].overlap.Offset = 0;
432 pipe_[index].overlap.OffsetHigh = 0;
434 // Overlapped ConnectNamedPipe should return zero.
435 if (ConnectNamedPipe(pipe_[index].handle, &pipe_[index].overlap)) {
436 DWORD const error = GetLastError();
437 lyxerr << "LyXComm: Could not connect pipe "
438 << external_path(pipeName(index))
439 << "\nLyXComm: " << errormsg(error) << endl;
443 switch (GetLastError()) {
444 case ERROR_IO_PENDING:
445 // The overlapped connection is in progress.
446 pipe_[index].pending_io = true;
449 case ERROR_PIPE_CONNECTED:
450 // Client is already connected, so signal an event.
451 if (SetEvent(pipe_[index].overlap.hEvent))
455 // Anything else is an error.
456 DWORD const error = GetLastError();
457 lyxerr << "LyXComm: An error occurred while connecting pipe "
458 << external_path(pipeName(index))
459 << "\nLyXComm: " << errormsg(error) << endl;
467 bool LyXComm::resetPipe(DWORD index, bool close_handle)
469 // This method is called when an error occurs or when a client
470 // closes the connection. We first disconnect the pipe instance,
471 // then reconnect it, ready to wait for another client.
473 if (!DisconnectNamedPipe(pipe_[index].handle)) {
474 DWORD const error = GetLastError();
475 lyxerr << "LyXComm: Could not disconnect pipe "
476 << external_path(pipeName(index))
477 << "\nLyXComm: " << errormsg(error) << endl;
478 // What to do now? Let's try whether re-creating the pipe helps.
482 bool const is_outpipe = index >= MAX_CLIENTS;
485 DWORD const open_mode = is_outpipe ? PIPE_ACCESS_OUTBOUND
486 : PIPE_ACCESS_INBOUND;
487 string const name = external_path(pipeName(index));
489 CloseHandle(pipe_[index].handle);
491 pipe_[index].iobuf.erase();
492 pipe_[index].handle = CreateNamedPipeA(name.c_str(),
493 open_mode | FILE_FLAG_OVERLAPPED, PIPE_WAIT,
494 MAX_CLIENTS, PIPE_BUFSIZE, PIPE_BUFSIZE,
497 if (pipe_[index].handle == INVALID_HANDLE_VALUE) {
498 DWORD const error = GetLastError();
499 lyxerr << "LyXComm: Could not reset pipe " << name
500 << "\nLyXComm: " << errormsg(error) << endl;
505 if (!startPipe(index))
507 pipe_[index].state = pipe_[index].pending_io ?
508 CONNECTING_STATE : (is_outpipe ? WRITING_STATE
514 void LyXComm::openConnection()
516 LYXERR(Debug::LYXSERVER, "LyXComm: Opening connection");
518 // If we are up, that's an error
520 LYXERR(Debug::LYXSERVER, "LyXComm: Already connected");
524 if (pipename_.empty()) {
525 LYXERR(Debug::LYXSERVER, "LyXComm: server is disabled, nothing to do");
529 // Check whether the pipe name is being used by some other instance.
530 if (!stopserver_ && WaitNamedPipeA(inPipeName().c_str(), 0)) {
531 // Tell the running instance to load the files
532 if (run_mode == USE_REMOTE && loadFilesInOtherInstance()) {
533 deferred_loading_ = true;
537 lyxerr << "LyXComm: Pipe " << external_path(inPipeName())
538 << " already exists.\nMaybe another instance of LyX"
539 " is using it." << endl;
544 // Mutex with no initial owner for synchronized access to outbuf_
545 outbuf_mutex_ = CreateMutex(NULL, FALSE, NULL);
546 if (!outbuf_mutex_) {
547 DWORD const error = GetLastError();
548 lyxerr << "LyXComm: Could not create output buffer mutex"
549 << "\nLyXComm: " << errormsg(error) << endl;
554 // Manual-reset event, initial state = not signaled
555 stopserver_ = CreateEvent(NULL, TRUE, FALSE, NULL);
557 DWORD const error = GetLastError();
558 lyxerr << "LyXComm: Could not create stop server event"
559 << "\nLyXComm: " << errormsg(error) << endl;
561 CloseHandle(outbuf_mutex_);
565 server_thread_ = CreateThread(NULL, 0, pipeServerWrapper,
566 static_cast<void *>(this), 0, NULL);
567 if (!server_thread_) {
568 DWORD const error = GetLastError();
569 lyxerr << "LyXComm: Could not create pipe server thread"
570 << "\nLyXComm: " << errormsg(error) << endl;
572 CloseHandle(stopserver_);
573 CloseHandle(outbuf_mutex_);
580 void LyXComm::closeConnection()
582 LYXERR(Debug::LYXSERVER, "LyXComm: Closing connection");
584 if (pipename_.empty()) {
585 LYXERR(Debug::LYXSERVER, "LyXComm: server is disabled, nothing to do");
590 LYXERR(Debug::LYXSERVER, "LyXComm: Already disconnected");
594 SetEvent(stopserver_);
595 // Wait for the pipe server to finish
596 WaitForSingleObject(server_thread_, INFINITE);
597 CloseHandle(server_thread_);
598 ResetEvent(stopserver_);
599 CloseHandle(stopserver_);
600 CloseHandle(outbuf_mutex_);
604 void LyXComm::emergencyCleanup()
607 SetEvent(stopserver_);
608 // Forcibly terminate the pipe server thread if it does
609 // not finish quickly.
610 if (WaitForSingleObject(server_thread_, 200) != WAIT_OBJECT_0) {
611 TerminateThread(server_thread_, 0);
615 CloseHandle(server_thread_);
616 ResetEvent(stopserver_);
617 CloseHandle(stopserver_);
618 CloseHandle(outbuf_mutex_);
623 void LyXComm::read_ready(DWORD inpipe)
625 // Turn the pipe buffer into a C string
626 DWORD const nbytes = pipe_[inpipe].nbytes;
627 pipe_[inpipe].readbuf[nbytes] = '\0';
629 pipe_[inpipe].iobuf += rtrim(pipe_[inpipe].readbuf, "\r");
631 // Commit any commands read
632 while (pipe_[inpipe].iobuf.find('\n') != string::npos) {
633 // split() grabs the entire string if
634 // the delim /wasn't/ found. ?:-P
636 pipe_[inpipe].iobuf = split(pipe_[inpipe].iobuf, cmd, '\n');
637 cmd = rtrim(cmd, "\r");
638 LYXERR(Debug::LYXSERVER, "LyXComm: nbytes:" << nbytes
639 << ", iobuf:" << pipe_[inpipe].iobuf
642 clientcb_(client_, cmd);
645 // Signal that we are done.
646 pipe_[inpipe].nbytes = 0;
650 void LyXComm::send(string const & msg)
653 lyxerr << "LyXComm: Request to send empty string. Ignoring."
658 LYXERR(Debug::LYXSERVER, "LyXComm: Sending '" << msg << '\'');
660 if (pipename_.empty())
664 lyxerr << "LyXComm: Pipes are closed. Could not send "
669 // Request ownership of the outbuf_mutex_
670 DWORD result = WaitForSingleObject(outbuf_mutex_, PIPE_TIMEOUT);
672 if (result == WAIT_OBJECT_0) {
673 // If a client doesn't care to read a reply (JabRef is one
674 // such client), the output buffer could grow without limit.
675 // So, we empty it when its size is larger than PIPE_BUFSIZE.
676 if (outbuf_.size() > PIPE_BUFSIZE)
679 ReleaseMutex(outbuf_mutex_);
681 // Something is fishy, better resetting the connection.
682 DWORD const error = GetLastError();
683 lyxerr << "LyXComm: Error sending message: " << msg
684 << "\nLyXComm: " << errormsg(error)
685 << "\nLyXComm: Resetting connection" << endl;
686 ReleaseMutex(outbuf_mutex_);
693 string const LyXComm::pipeName(DWORD index) const
695 return index < MAX_CLIENTS ? inPipeName() : outPipeName();
699 #elif !defined (HAVE_MKFIFO)
700 // We provide a stub class that disables the lyxserver.
702 LyXComm::LyXComm(string const &, Server *, ClientCallbackfct)
706 void LyXComm::openConnection()
710 void LyXComm::closeConnection()
714 int LyXComm::startPipe(string const & filename, bool write)
720 void LyXComm::endPipe(int & fd, string const & filename, bool write)
724 void LyXComm::emergencyCleanup()
728 void LyXComm::read_ready()
732 void LyXComm::send(string const & msg)
736 #else // defined (HAVE_MKFIFO)
738 LyXComm::LyXComm(string const & pip, Server * cli, ClientCallbackfct ccb)
739 : infd_(-1), outfd_(-1),
740 ready_(false), pipename_(pip), client_(cli), clientcb_(ccb),
741 deferred_loading_(false)
747 void LyXComm::openConnection()
749 LYXERR(Debug::LYXSERVER, "LyXComm: Opening connection");
751 // If we are up, that's an error
753 lyxerr << "LyXComm: Already connected" << endl;
756 // We assume that we don't make it
759 if (pipename_.empty()) {
760 LYXERR(Debug::LYXSERVER, "LyXComm: server is disabled, nothing to do");
764 infd_ = startPipe(inPipeName(), false);
768 outfd_ = startPipe(outPipeName(), true);
770 endPipe(infd_, inPipeName(), false);
774 if (fcntl(outfd_, F_SETFL, O_NONBLOCK) < 0) {
775 lyxerr << "LyXComm: Could not set flags on pipe " << outPipeName()
776 << '\n' << strerror(errno) << endl;
782 LYXERR(Debug::LYXSERVER, "LyXComm: Connection established");
787 void LyXComm::closeConnection()
789 LYXERR(Debug::LYXSERVER, "LyXComm: Closing connection");
791 if (pipename_.empty()) {
792 LYXERR(Debug::LYXSERVER, "LyXComm: server is disabled, nothing to do");
797 LYXERR0("LyXComm: Already disconnected");
801 endPipe(infd_, inPipeName(), false);
802 endPipe(outfd_, outPipeName(), true);
808 int LyXComm::startPipe(string const & file, bool write)
810 static bool stalepipe = false;
811 FileName const filename(file);
812 if (filename.exists()) {
814 // Let's see whether we have a stale pipe.
815 int fd = ::open(filename.toFilesystemEncoding().c_str(),
816 O_WRONLY | O_NONBLOCK);
818 // Another LyX instance is using it.
820 // Tell the running instance to load the files
821 if (run_mode == USE_REMOTE && loadFilesInOtherInstance()) {
822 deferred_loading_ = true;
826 } else if (errno == ENXIO) {
827 // No process is reading from the other end.
829 LYXERR(Debug::LYXSERVER,
830 "LyXComm: trying to remove "
832 filename.removeFile();
834 } else if (stalepipe) {
835 LYXERR(Debug::LYXSERVER, "LyXComm: trying to remove "
837 filename.removeFile();
840 if (filename.exists()) {
841 lyxerr << "LyXComm: Pipe " << filename
842 << " already exists.\nIf no other LyX program"
843 " is active, please delete the pipe by hand"
851 if (::mkfifo(filename.toFilesystemEncoding().c_str(), 0600) < 0) {
852 lyxerr << "LyXComm: Could not create pipe " << filename << '\n'
853 << strerror(errno) << endl;
856 int const fd = ::open(filename.toFilesystemEncoding().c_str(),
857 write ? (O_RDWR) : (O_RDONLY|O_NONBLOCK));
860 lyxerr << "LyXComm: Could not open pipe " << filename << '\n'
861 << strerror(errno) << endl;
862 filename.removeFile();
867 // Make sure not to call read_ready after destruction.
868 weak_ptr<void> tracker = tracker_.p();
869 theApp()->registerSocketCallback(fd, [this, tracker](){
870 if (!tracker.expired())
879 void LyXComm::endPipe(int & fd, string const & filename, bool write)
885 theApp()->unregisterSocketCallback(fd);
887 if (::close(fd) < 0) {
888 lyxerr << "LyXComm: Could not close pipe " << filename
889 << '\n' << strerror(errno) << endl;
892 if (!FileName(filename).removeFile()) {
893 lyxerr << "LyXComm: Could not remove pipe " << filename
894 << '\n' << strerror(errno) << endl;
901 void LyXComm::emergencyCleanup()
903 if (!pipename_.empty()) {
904 endPipe(infd_, inPipeName(), false);
905 endPipe(outfd_, outPipeName(), true);
910 // Receives messages and sends then to client
911 void LyXComm::read_ready()
913 // FIXME: make read_buffer_ a class-member for multiple sessions
914 static string read_buffer_;
915 read_buffer_.erase();
917 int const charbuf_size = 100;
918 char charbuf[charbuf_size];
920 // As O_NONBLOCK is set, until no data is available for reading,
921 // read() doesn't block but returns -1 and set errno to EAGAIN.
922 // After a client that opened the pipe for writing, closes it
923 // (and no other client is using the pipe), read() would always
924 // return 0 and thus the connection has to be reset.
928 // the single = is intended here.
929 while ((status = ::read(infd_, charbuf, charbuf_size - 1))) {
931 charbuf[status] = '\0'; // turn it into a c string
932 read_buffer_ += rtrim(charbuf, "\r");
933 // commit any commands read
934 while (read_buffer_.find('\n') != string::npos) {
935 // split() grabs the entire string if
936 // the delim /wasn't/ found. ?:-P
938 read_buffer_= split(read_buffer_, cmd,'\n');
939 LYXERR(Debug::LYXSERVER, "LyXComm: status:" << status
940 << ", read_buffer_:" << read_buffer_
943 clientcb_(client_, cmd);
947 if (errno == EAGAIN) {
948 // Nothing to read, continue
952 // An error occurred, better bailing out
953 LYXERR0("LyXComm: " << strerror(errno));
954 if (!read_buffer_.empty()) {
955 LYXERR0("LyXComm: truncated command: " << read_buffer_);
956 read_buffer_.erase();
958 break; // reset connection
962 // The connection gets reset when read() returns 0 (meaning that the
963 // last client closed the pipe) or an error occurred, in which case
964 // read() returns -1 and errno != EAGAIN.
971 void LyXComm::send(string const & msg)
974 LYXERR0("LyXComm: Request to send empty string. Ignoring.");
978 LYXERR(Debug::LYXSERVER, "LyXComm: Sending '" << msg << '\'');
980 if (pipename_.empty())
984 LYXERR0("LyXComm: Pipes are closed. Could not send " << msg);
985 } else if (::write(outfd_, msg.c_str(), msg.length()) < 0) {
986 lyxerr << "LyXComm: Error sending message: " << msg
987 << '\n' << strerror(errno)
988 << "\nLyXComm: Resetting connection" << endl;
994 #endif // defined (HAVE_MKFIFO)
998 struct Sleep : QThread
1000 static void millisec(unsigned long ms)
1002 QThread::usleep(ms * 1000);
1009 bool LyXComm::loadFilesInOtherInstance() const
1012 FileName const pipe(inPipeName());
1014 if (theFilesToLoad().empty()) {
1015 LYXERR0("LyX is already running in another instance\n"
1016 "and 'use single instance' is active.");
1017 // Wait a while for the other instance to reset the connection
1018 Sleep::millisec(200);
1019 pipefd = ::open(pipe.toFilesystemEncoding().c_str(), O_WRONLY);
1021 string const cmd = "LYXCMD:pipe:window-raise\n";
1022 if (::write(pipefd, cmd.c_str(), cmd.length()) < 0)
1023 LYXERR0("Cannot communicate with running instance!");
1029 int loaded_files = 0;
1030 vector<string>::iterator it = theFilesToLoad().begin();
1031 while (it != theFilesToLoad().end()) {
1032 FileName fname = fileSearch(string(), os::internal_path(*it),
1033 "lyx", may_not_exist);
1034 if (fname.empty()) {
1038 // Wait a while to allow time for the other
1039 // instance to reset the connection
1040 Sleep::millisec(200);
1041 pipefd = ::open(pipe.toFilesystemEncoding().c_str(), O_WRONLY);
1044 string const cmd = "LYXCMD:pipe:file-open:" +
1045 fname.absFileName() + '\n';
1046 if (::write(pipefd, cmd.c_str(), cmd.length()) < 0)
1047 LYXERR0("Cannot write to pipe!");
1050 it = theFilesToLoad().erase(it);
1052 return loaded_files > 0;
1056 string const LyXComm::inPipeName() const
1058 return pipename_ + ".in";
1062 string const LyXComm::outPipeName() const
1064 return pipename_ + ".out";
1068 /////////////////////////////////////////////////////////////////////
1072 /////////////////////////////////////////////////////////////////////
1074 void ServerCallback(Server * server, string const & msg)
1076 server->callback(msg);
1079 Server::Server(string const & pipes)
1080 : numclients_(0), pipes_(pipes, this, &ServerCallback)
1086 // say goodbye to clients so they stop sending messages
1087 // send as many bye messages as there are clients,
1088 // each with client's name.
1090 for (int i = 0; i != numclients_; ++i) {
1091 message = "LYXSRV:" + clients_[i] + ":bye\n";
1092 pipes_.send(message);
1097 int compare(char const * a, char const * b, unsigned int len)
1099 return strncmp(a, b, len);
1103 // Handle data gotten from communication, called by LyXComm
1104 void Server::callback(string const & msg)
1106 LYXERR(Debug::LYXSERVER, "Server: Received: '" << msg << '\'');
1108 char const * p = msg.c_str();
1110 // --- parse the string --------------------------------------------
1112 // Format: LYXCMD:<client>:<func>:<argstring>\n
1114 bool server_only = false;
1116 // --- 1. check 'header' ---
1118 if (compare(p, "LYXSRV:", 7) == 0) {
1120 } else if (0 != compare(p, "LYXCMD:", 7)) {
1121 lyxerr << "Server: Unknown request \""
1122 << p << '"' << endl;
1127 // --- 2. for the moment ignore the client name ---
1129 while (*p && *p != ':')
1130 client += char(*p++);
1136 // --- 3. get function name ---
1138 while (*p && *p != ':')
1141 // --- 4. parse the argument ---
1143 if (!server_only && *p == ':' && *(++p)) {
1144 while (*p && *p != '\n')
1149 LYXERR(Debug::LYXSERVER, "Server: Client: '" << client
1150 << "' Command: '" << cmd << "' Argument: '" << arg << '\'');
1152 // --- lookup and exec the command ------------------
1156 // return the greeting to inform the client that
1157 // we are listening.
1158 if (cmd == "hello") {
1160 if (numclients_ == MAX_CLIENTS) { //paranoid check
1161 LYXERR(Debug::LYXSERVER, "Server: too many clients...");
1165 while (!clients_[i].empty() && i < numclients_)
1167 clients_[i] = client;
1169 buf = "LYXSRV:" + client + ":hello\n";
1170 LYXERR(Debug::LYXSERVER, "Server: Greeting " << client);
1172 } else if (cmd == "bye") {
1173 // If clients_ == 0 maybe we should reset the pipes
1174 // to prevent fake callbacks
1175 int i = 0; //look if client is registered
1176 for (; i < numclients_; ++i) {
1177 if (clients_[i] == client)
1180 if (i < numclients_) {
1182 clients_[i].erase();
1183 LYXERR(Debug::LYXSERVER, "Server: Client "
1184 << client << " said goodbye");
1186 LYXERR(Debug::LYXSERVER,
1187 "Server: ignoring bye message from unregistered client" << client);
1190 LYXERR0("Server: Undefined server command " << cmd << '.');
1196 // which lyxfunc should we let it connect to?
1197 // The correct solution would be to have a
1198 // specialized (non-gui) BufferView. But how do
1199 // we do it now? Probably we should just let it
1200 // connect to the lyxfunc in the single GuiView we
1201 // support currently. (Lgb)
1203 FuncRequest fr(lyxaction.lookupFunc(cmd), from_utf8(arg));
1204 fr.setOrigin(FuncRequest::LYXSERVER);
1206 theApp()->dispatch(fr, dr);
1207 string const rval = to_utf8(dr.message());
1209 // all commands produce an INFO or ERROR message
1210 // in the output pipe, even if they do not return
1211 // anything. See chapter 4 of Customization doc.
1217 buf += client + ':' + cmd + ':' + rval + '\n';
1220 // !!! we don't do any error checking -
1221 // if the client won't listen, the
1222 // message is lost and others too
1223 // maybe; so the client should empty
1224 // the outpipe before issuing a request.
1232 // Send a notify message to a client, called by WorkAreaKeyPress
1233 void Server::notifyClient(string const & s)
1235 pipes_.send("NOTIFY:" + s + "\n");
1242 #include "moc_Server.cpp"