* de.po: sync with branch.
[lyx.git] / src / Server.cpp
blob33c32ea19ceac317ebd26010e91b85c78fecd087
1 /**
2 * \file Server.cpp
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
9 * \author John Levon
10 * \author Enrico Forestieri
12 * Full author contact details are available in file CREDITS.
15 /**
16 Docu : To use the lyxserver define the name of the pipe in your
17 lyxrc:
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/server_monitor.c for an example client.
38 Purpose: implement a client/server lib for LyX
41 #include <config.h>
43 #include "Server.h"
44 #include "FuncRequest.h"
45 #include "LyXAction.h"
46 #include "LyXFunc.h"
48 #include "frontends/Application.h"
50 #include "support/debug.h"
51 #include "support/FileName.h"
52 #include "support/lassert.h"
53 #include "support/lstrings.h"
54 #include "support/os.h"
56 #include <boost/bind.hpp>
58 #ifdef _WIN32
59 #include <QCoreApplication>
60 #endif
62 #include <cerrno>
63 #ifdef HAVE_SYS_STAT_H
64 # include <sys/stat.h>
65 #endif
66 #include <fcntl.h>
68 using namespace std;
69 using namespace lyx::support;
70 using os::external_path;
72 namespace lyx {
74 /////////////////////////////////////////////////////////////////////
76 // LyXComm
78 /////////////////////////////////////////////////////////////////////
80 #if defined(_WIN32)
82 class ReadReadyEvent : public QEvent {
83 public:
84 ///
85 ReadReadyEvent(DWORD inpipe) : QEvent(QEvent::User), inpipe_(inpipe)
87 ///
88 DWORD inpipe() const { return inpipe_; }
90 private:
91 DWORD inpipe_;
94 namespace {
96 string errormsg(DWORD const error)
98 void * msgbuf;
99 string message;
100 if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
101 FORMAT_MESSAGE_FROM_SYSTEM |
102 FORMAT_MESSAGE_IGNORE_INSERTS,
103 NULL, error,
104 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
105 (LPTSTR) &msgbuf, 0, NULL)) {
106 message = static_cast<char *>(msgbuf);
107 LocalFree(msgbuf);
108 } else
109 message = "Unknown error";
111 return message;
114 } // namespace anon
117 DWORD WINAPI pipeServerWrapper(void * arg)
119 LyXComm * lyxcomm = reinterpret_cast<LyXComm *>(arg);
120 if (!lyxcomm->pipeServer()) {
121 // Error exit; perform cleanup.
122 lyxcomm->ready_ = false;
123 lyxcomm->closeHandles();
124 CloseHandle(lyxcomm->server_thread_);
125 CloseHandle(lyxcomm->stopserver_);
126 CloseHandle(lyxcomm->outbuf_mutex_);
127 lyxerr << "LyXComm: Closing connection" << endl;
129 return 1;
133 LyXComm::LyXComm(string const & pip, Server * cli, ClientCallbackfct ccb)
134 : pipename_(pip), client_(cli), clientcb_(ccb), stopserver_(0)
136 for (int i = 0; i < MAX_PIPES; ++i) {
137 event_[i] = 0;
138 pipe_[i].handle = INVALID_HANDLE_VALUE;
140 ready_ = false;
141 openConnection();
145 bool LyXComm::pipeServer()
147 DWORD i;
148 DWORD error;
150 for (i = 0; i < MAX_PIPES; ++i) {
151 bool const is_outpipe = i >= MAX_CLIENTS;
152 DWORD const open_mode = is_outpipe ? PIPE_ACCESS_OUTBOUND
153 : PIPE_ACCESS_INBOUND;
154 string const pipename = external_path(pipeName(i));
156 // Manual-reset event, initial state = signaled
157 event_[i] = CreateEvent(NULL, TRUE, TRUE, NULL);
158 if (!event_[i]) {
159 error = GetLastError();
160 lyxerr << "LyXComm: Could not create event for pipe "
161 << pipename << "\nLyXComm: "
162 << errormsg(error) << endl;
163 return false;
166 pipe_[i].overlap.hEvent = event_[i];
167 pipe_[i].iobuf.erase();
168 pipe_[i].handle = CreateNamedPipe(pipename.c_str(),
169 open_mode | FILE_FLAG_OVERLAPPED, PIPE_WAIT,
170 MAX_CLIENTS, PIPE_BUFSIZE, PIPE_BUFSIZE,
171 PIPE_TIMEOUT, NULL);
173 if (pipe_[i].handle == INVALID_HANDLE_VALUE) {
174 error = GetLastError();
175 lyxerr << "LyXComm: Could not create pipe "
176 << pipename << "\nLyXComm: "
177 << errormsg(error) << endl;
178 return false;
181 if (!startPipe(i))
182 return false;
183 pipe_[i].state = pipe_[i].pending_io ?
184 CONNECTING_STATE : (is_outpipe ? WRITING_STATE
185 : READING_STATE);
188 // Add the stopserver_ event
189 event_[MAX_PIPES] = stopserver_;
191 // We made it!
192 LYXERR(Debug::LYXSERVER, "LyXComm: Connection established");
193 ready_ = true;
194 outbuf_.erase();
195 DWORD status;
196 bool success;
198 while (!checkStopServer()) {
199 // Indefinitely wait for the completion of an overlapped
200 // read, write, or connect operation.
201 DWORD wait = WaitForMultipleObjects(MAX_PIPES + 1, event_,
202 FALSE, INFINITE);
204 // Determine which pipe instance completed the operation.
205 i = wait - WAIT_OBJECT_0;
206 LASSERT(i >= 0 && i <= MAX_PIPES, /**/);
208 // Check whether we were waked up for stopping the pipe server.
209 if (i == MAX_PIPES)
210 break;
212 bool const is_outpipe = i >= MAX_CLIENTS;
214 // Get the result if the operation was pending.
215 if (pipe_[i].pending_io) {
216 success = GetOverlappedResult(pipe_[i].handle,
217 &pipe_[i].overlap, &status, FALSE);
219 switch (pipe_[i].state) {
220 case CONNECTING_STATE:
221 // Pending connect operation
222 if (!success) {
223 error = GetLastError();
224 lyxerr << "LyXComm: "
225 << errormsg(error) << endl;
226 if (!resetPipe(i, true))
227 return false;
228 continue;
230 pipe_[i].state = is_outpipe ? WRITING_STATE
231 : READING_STATE;
232 break;
234 case READING_STATE:
235 // Pending read operation
236 LASSERT(!is_outpipe, /**/);
237 if (!success || status == 0) {
238 if (!resetPipe(i, !success))
239 return false;
240 continue;
242 pipe_[i].nbytes = status;
243 pipe_[i].state = WRITING_STATE;
244 break;
246 case WRITING_STATE:
247 // Pending write operation
248 LASSERT(is_outpipe, /**/);
249 // Let's see whether we have a reply
250 if (!outbuf_.empty()) {
251 // Yep. Deliver it to all pipe
252 // instances if we get ownership
253 // of the mutex, otherwise we'll
254 // try again the next round.
255 DWORD result = WaitForSingleObject(
256 outbuf_mutex_, 200);
257 if (result == WAIT_OBJECT_0) {
258 DWORD j = MAX_CLIENTS;
259 while (j < MAX_PIPES) {
260 pipe_[j].iobuf = outbuf_;
261 ++j;
263 outbuf_.erase();
265 ReleaseMutex(outbuf_mutex_);
267 if (pipe_[i].iobuf.empty())
268 pipe_[i].pending_io = false;
269 break;
273 // Operate according to the pipe state
274 switch (pipe_[i].state) {
275 case READING_STATE:
276 // The pipe instance is connected to a client
277 // and is ready to read a request.
278 LASSERT(!is_outpipe, /**/);
279 success = ReadFile(pipe_[i].handle,
280 pipe_[i].readbuf, PIPE_BUFSIZE - 1,
281 &pipe_[i].nbytes, &pipe_[i].overlap);
283 if (success && pipe_[i].nbytes != 0) {
284 // The read operation completed successfully.
285 pipe_[i].pending_io = false;
286 pipe_[i].state = WRITING_STATE;
287 continue;
290 error = GetLastError();
292 if (!success && error == ERROR_IO_PENDING) {
293 // The read operation is still pending.
294 pipe_[i].pending_io = true;
295 continue;
298 success = error == ERROR_BROKEN_PIPE;
300 // Client closed connection (ERROR_BROKEN_PIPE) or
301 // an error occurred; in either case, reset the pipe.
302 if (!success) {
303 lyxerr << "LyXComm: " << errormsg(error) << endl;
304 if (!pipe_[i].iobuf.empty()) {
305 lyxerr << "LyXComm: truncated command: "
306 << pipe_[i].iobuf << endl;
307 pipe_[i].iobuf.erase();
310 if (!resetPipe(i, !success))
311 return false;
312 break;
314 case WRITING_STATE:
315 if (!is_outpipe) {
316 // The request was successfully read
317 // from the client; commit it.
318 ReadReadyEvent * event = new ReadReadyEvent(i);
319 QCoreApplication::postEvent(this,
320 static_cast<QEvent *>(event));
321 // Wait for completion
322 while (pipe_[i].nbytes && !checkStopServer(100))
324 pipe_[i].pending_io = false;
325 pipe_[i].state = READING_STATE;
326 continue;
329 // This is an output pipe instance. Initiate the
330 // overlapped write operation or monitor its progress.
332 if (pipe_[i].pending_io) {
333 success = WriteFile(pipe_[i].handle,
334 pipe_[i].iobuf.c_str(),
335 pipe_[i].iobuf.length(),
336 &status,
337 &pipe_[i].overlap);
340 if (success && !pipe_[i].iobuf.empty()
341 && status == pipe_[i].iobuf.length()) {
342 // The write operation completed successfully.
343 pipe_[i].iobuf.erase();
344 pipe_[i].pending_io = false;
345 if (!resetPipe(i))
346 return false;
347 continue;
350 error = GetLastError();
352 if (success && error == ERROR_IO_PENDING) {
353 // The write operation is still pending.
354 // We get here when a reader is started
355 // well before a reply is ready, so delay
356 // a bit in order to not burden the cpu.
357 checkStopServer(100);
358 pipe_[i].pending_io = true;
359 continue;
362 success = error == ERROR_NO_DATA;
364 // Client closed connection (ERROR_NO_DATA) or
365 // an error occurred; in either case, reset the pipe.
366 if (!success) {
367 lyxerr << "LyXComm: Error sending message: "
368 << pipe_[i].iobuf << "\nLyXComm: "
369 << errormsg(error) << endl;
371 if (!resetPipe(i, !success))
372 return false;
373 break;
377 ready_ = false;
378 closeHandles();
379 return true;
383 void LyXComm::closeHandles()
385 for (int i = 0; i < MAX_PIPES; ++i) {
386 if (event_[i]) {
387 ResetEvent(event_[i]);
388 CloseHandle(event_[i]);
389 event_[i] = 0;
391 if (pipe_[i].handle != INVALID_HANDLE_VALUE) {
392 CloseHandle(pipe_[i].handle);
393 pipe_[i].handle = INVALID_HANDLE_VALUE;
399 bool LyXComm::event(QEvent * e)
401 if (e->type() == QEvent::User) {
402 read_ready(static_cast<ReadReadyEvent *>(e)->inpipe());
403 return true;
405 return false;
409 bool LyXComm::checkStopServer(DWORD timeout)
411 return WaitForSingleObject(stopserver_, timeout) == WAIT_OBJECT_0;
415 bool LyXComm::startPipe(DWORD index)
417 pipe_[index].pending_io = false;
418 pipe_[index].overlap.Offset = 0;
419 pipe_[index].overlap.OffsetHigh = 0;
421 // Overlapped ConnectNamedPipe should return zero.
422 if (ConnectNamedPipe(pipe_[index].handle, &pipe_[index].overlap)) {
423 DWORD const error = GetLastError();
424 lyxerr << "LyXComm: Could not connect pipe "
425 << external_path(pipeName(index))
426 << "\nLyXComm: " << errormsg(error) << endl;
427 return false;
430 switch (GetLastError()) {
431 case ERROR_IO_PENDING:
432 // The overlapped connection is in progress.
433 pipe_[index].pending_io = true;
434 break;
436 case ERROR_PIPE_CONNECTED:
437 // Client is already connected, so signal an event.
438 if (SetEvent(pipe_[index].overlap.hEvent))
439 break;
440 // fall through
441 default:
442 // Anything else is an error.
443 DWORD const error = GetLastError();
444 lyxerr << "LyXComm: An error occurred while connecting pipe "
445 << external_path(pipeName(index))
446 << "\nLyXComm: " << errormsg(error) << endl;
447 return false;
450 return true;
454 bool LyXComm::resetPipe(DWORD index, bool close_handle)
456 // This method is called when an error occurs or when a client
457 // closes the connection. We first disconnect the pipe instance,
458 // then reconnect it, ready to wait for another client.
460 if (!DisconnectNamedPipe(pipe_[index].handle)) {
461 DWORD const error = GetLastError();
462 lyxerr << "LyXComm: Could not disconnect pipe "
463 << external_path(pipeName(index))
464 << "\nLyXComm: " << errormsg(error) << endl;
465 // What to do now? Let's try whether re-creating the pipe helps.
466 close_handle = true;
469 bool const is_outpipe = index >= MAX_CLIENTS;
471 if (close_handle) {
472 DWORD const open_mode = is_outpipe ? PIPE_ACCESS_OUTBOUND
473 : PIPE_ACCESS_INBOUND;
474 string const name = external_path(pipeName(index));
476 CloseHandle(pipe_[index].handle);
478 pipe_[index].iobuf.erase();
479 pipe_[index].handle = CreateNamedPipe(name.c_str(),
480 open_mode | FILE_FLAG_OVERLAPPED, PIPE_WAIT,
481 MAX_CLIENTS, PIPE_BUFSIZE, PIPE_BUFSIZE,
482 PIPE_TIMEOUT, NULL);
484 if (pipe_[index].handle == INVALID_HANDLE_VALUE) {
485 DWORD const error = GetLastError();
486 lyxerr << "LyXComm: Could not reset pipe " << name
487 << "\nLyXComm: " << errormsg(error) << endl;
488 return false;
492 if (!startPipe(index))
493 return false;
494 pipe_[index].state = pipe_[index].pending_io ?
495 CONNECTING_STATE : (is_outpipe ? WRITING_STATE
496 : READING_STATE);
497 return true;
501 void LyXComm::openConnection()
503 LYXERR(Debug::LYXSERVER, "LyXComm: Opening connection");
505 // If we are up, that's an error
506 if (ready_) {
507 LYXERR(Debug::LYXSERVER, "LyXComm: Already connected");
508 return;
511 if (pipename_.empty()) {
512 LYXERR(Debug::LYXSERVER, "LyXComm: server is disabled, nothing to do");
513 return;
516 // Check whether the pipe name is being used by some other program.
517 if (!stopserver_ && WaitNamedPipe(inPipeName().c_str(), 0)) {
518 lyxerr << "LyXComm: Pipe " << external_path(inPipeName())
519 << " already exists.\nMaybe another instance of LyX"
520 " is using it." << endl;
521 pipename_.erase();
522 return;
525 // Mutex with no initial owner for synchronized access to outbuf_
526 outbuf_mutex_ = CreateMutex(NULL, FALSE, NULL);
527 if (!outbuf_mutex_) {
528 DWORD const error = GetLastError();
529 lyxerr << "LyXComm: Could not create output buffer mutex"
530 << "\nLyXComm: " << errormsg(error) << endl;
531 pipename_.erase();
532 return;
535 // Manual-reset event, initial state = not signaled
536 stopserver_ = CreateEvent(NULL, TRUE, FALSE, NULL);
537 if (!stopserver_) {
538 DWORD const error = GetLastError();
539 lyxerr << "LyXComm: Could not create stop server event"
540 << "\nLyXComm: " << errormsg(error) << endl;
541 pipename_.erase();
542 CloseHandle(outbuf_mutex_);
543 return;
546 server_thread_ = CreateThread(NULL, 0, pipeServerWrapper,
547 static_cast<void *>(this), 0, NULL);
548 if (!server_thread_) {
549 DWORD const error = GetLastError();
550 lyxerr << "LyXComm: Could not create pipe server thread"
551 << "\nLyXComm: " << errormsg(error) << endl;
552 pipename_.erase();
553 CloseHandle(stopserver_);
554 CloseHandle(outbuf_mutex_);
555 return;
560 /// Close pipes
561 void LyXComm::closeConnection()
563 LYXERR(Debug::LYXSERVER, "LyXComm: Closing connection");
565 if (pipename_.empty()) {
566 LYXERR(Debug::LYXSERVER, "LyXComm: server is disabled, nothing to do");
567 return;
570 if (!ready_) {
571 LYXERR(Debug::LYXSERVER, "LyXComm: Already disconnected");
572 return;
575 SetEvent(stopserver_);
576 // Wait for the pipe server to finish
577 WaitForSingleObject(server_thread_, INFINITE);
578 CloseHandle(server_thread_);
579 ResetEvent(stopserver_);
580 CloseHandle(stopserver_);
581 CloseHandle(outbuf_mutex_);
585 void LyXComm::emergencyCleanup()
587 if (ready_) {
588 SetEvent(stopserver_);
589 // Forcibly terminate the pipe server thread if it does
590 // not finish quickly.
591 if (WaitForSingleObject(server_thread_, 200) != WAIT_OBJECT_0) {
592 TerminateThread(server_thread_, 0);
593 ready_ = false;
594 closeHandles();
596 CloseHandle(server_thread_);
597 ResetEvent(stopserver_);
598 CloseHandle(stopserver_);
599 CloseHandle(outbuf_mutex_);
604 void LyXComm::read_ready(DWORD inpipe)
606 // Turn the pipe buffer into a C string
607 DWORD const nbytes = pipe_[inpipe].nbytes;
608 pipe_[inpipe].readbuf[nbytes] = '\0';
610 pipe_[inpipe].iobuf += rtrim(pipe_[inpipe].readbuf, "\r");
612 // Commit any commands read
613 while (pipe_[inpipe].iobuf.find('\n') != string::npos) {
614 // split() grabs the entire string if
615 // the delim /wasn't/ found. ?:-P
616 string cmd;
617 pipe_[inpipe].iobuf = split(pipe_[inpipe].iobuf, cmd, '\n');
618 cmd = rtrim(cmd, "\r");
619 LYXERR(Debug::LYXSERVER, "LyXComm: nbytes:" << nbytes
620 << ", iobuf:" << pipe_[inpipe].iobuf
621 << ", cmd:" << cmd);
622 if (!cmd.empty())
623 clientcb_(client_, cmd);
624 //\n or not \n?
626 // Signal that we are done.
627 pipe_[inpipe].nbytes = 0;
631 void LyXComm::send(string const & msg)
633 if (msg.empty()) {
634 lyxerr << "LyXComm: Request to send empty string. Ignoring."
635 << endl;
636 return;
639 LYXERR(Debug::LYXSERVER, "LyXComm: Sending '" << msg << '\'');
641 if (pipename_.empty())
642 return;
644 if (!ready_) {
645 lyxerr << "LyXComm: Pipes are closed. Could not send "
646 << msg << endl;
647 return;
650 // Request ownership of the outbuf_mutex_
651 DWORD result = WaitForSingleObject(outbuf_mutex_, PIPE_TIMEOUT);
653 if (result == WAIT_OBJECT_0) {
654 // If a client doesn't care to read a reply (JabRef is one
655 // such client), the output buffer could grow without limit.
656 // So, we empty it when its size is larger than PIPE_BUFSIZE.
657 if (outbuf_.size() > PIPE_BUFSIZE)
658 outbuf_.erase();
659 outbuf_ += msg;
660 ReleaseMutex(outbuf_mutex_);
661 } else {
662 // Something is fishy, better resetting the connection.
663 DWORD const error = GetLastError();
664 lyxerr << "LyXComm: Error sending message: " << msg
665 << "\nLyXComm: " << errormsg(error)
666 << "\nLyXComm: Resetting connection" << endl;
667 ReleaseMutex(outbuf_mutex_);
668 closeConnection();
669 openConnection();
674 string const LyXComm::pipeName(DWORD index) const
676 return index < MAX_CLIENTS ? inPipeName() : outPipeName();
680 #elif !defined (HAVE_MKFIFO)
681 // We provide a stub class that disables the lyxserver.
683 LyXComm::LyXComm(string const &, Server *, ClientCallbackfct)
686 void LyXComm::openConnection()
690 void LyXComm::closeConnection()
694 int LyXComm::startPipe(string const & filename, bool write)
696 return -1;
700 void LyXComm::endPipe(int & fd, string const & filename, bool write)
704 void LyXComm::emergencyCleanup()
707 void LyXComm::read_ready()
711 void LyXComm::send(string const & msg)
715 #else // defined (HAVE_MKFIFO)
718 LyXComm::LyXComm(string const & pip, Server * cli, ClientCallbackfct ccb)
719 : pipename_(pip), client_(cli), clientcb_(ccb)
721 ready_ = false;
722 openConnection();
726 void LyXComm::openConnection()
728 LYXERR(Debug::LYXSERVER, "LyXComm: Opening connection");
730 // If we are up, that's an error
731 if (ready_) {
732 lyxerr << "LyXComm: Already connected" << endl;
733 return;
735 // We assume that we don't make it
736 ready_ = false;
738 if (pipename_.empty()) {
739 LYXERR(Debug::LYXSERVER, "LyXComm: server is disabled, nothing to do");
740 return;
743 infd_ = startPipe(inPipeName(), false);
744 if (infd_ == -1)
745 return;
747 outfd_ = startPipe(outPipeName(), true);
748 if (outfd_ == -1) {
749 endPipe(infd_, inPipeName(), false);
750 return;
753 if (fcntl(outfd_, F_SETFL, O_NONBLOCK) < 0) {
754 lyxerr << "LyXComm: Could not set flags on pipe " << outPipeName()
755 << '\n' << strerror(errno) << endl;
756 return;
759 // We made it!
760 ready_ = true;
761 LYXERR(Debug::LYXSERVER, "LyXComm: Connection established");
765 /// Close pipes
766 void LyXComm::closeConnection()
768 LYXERR(Debug::LYXSERVER, "LyXComm: Closing connection");
770 if (pipename_.empty()) {
771 LYXERR(Debug::LYXSERVER, "LyXComm: server is disabled, nothing to do");
772 return;
775 if (!ready_) {
776 LYXERR0("LyXComm: Already disconnected");
777 return;
780 endPipe(infd_, inPipeName(), false);
781 endPipe(outfd_, outPipeName(), true);
783 ready_ = false;
787 int LyXComm::startPipe(string const & file, bool write)
789 static bool stalepipe = false;
790 FileName const filename(file);
791 if (filename.exists()) {
792 if (!write) {
793 // Let's see whether we have a stale pipe.
794 int fd = ::open(filename.toFilesystemEncoding().c_str(),
795 O_WRONLY | O_NONBLOCK);
796 if (fd >= 0) {
797 // Another LyX instance is using it.
798 ::close(fd);
799 } else if (errno == ENXIO) {
800 // No process is reading from the other end.
801 stalepipe = true;
802 LYXERR(Debug::LYXSERVER,
803 "LyXComm: trying to remove "
804 << filename);
805 filename.removeFile();
807 } else if (stalepipe) {
808 LYXERR(Debug::LYXSERVER, "LyXComm: trying to remove "
809 << filename);
810 filename.removeFile();
811 stalepipe = false;
813 if (filename.exists()) {
814 lyxerr << "LyXComm: Pipe " << filename
815 << " already exists.\nIf no other LyX program"
816 " is active, please delete the pipe by hand"
817 " and try again."
818 << endl;
819 pipename_.erase();
820 return -1;
824 if (::mkfifo(filename.toFilesystemEncoding().c_str(), 0600) < 0) {
825 lyxerr << "LyXComm: Could not create pipe " << filename << '\n'
826 << strerror(errno) << endl;
827 return -1;
829 int const fd = ::open(filename.toFilesystemEncoding().c_str(),
830 write ? (O_RDWR) : (O_RDONLY|O_NONBLOCK));
832 if (fd < 0) {
833 lyxerr << "LyXComm: Could not open pipe " << filename << '\n'
834 << strerror(errno) << endl;
835 filename.removeFile();
836 return -1;
839 if (!write) {
840 theApp()->registerSocketCallback(fd,
841 boost::bind(&LyXComm::read_ready, this));
844 return fd;
848 void LyXComm::endPipe(int & fd, string const & filename, bool write)
850 if (fd < 0)
851 return;
853 if (!write)
854 theApp()->unregisterSocketCallback(fd);
856 if (::close(fd) < 0) {
857 lyxerr << "LyXComm: Could not close pipe " << filename
858 << '\n' << strerror(errno) << endl;
861 if (FileName(filename).removeFile() < 0) {
862 lyxerr << "LyXComm: Could not remove pipe " << filename
863 << '\n' << strerror(errno) << endl;
866 fd = -1;
870 void LyXComm::emergencyCleanup()
872 if (!pipename_.empty()) {
873 endPipe(infd_, inPipeName(), false);
874 endPipe(outfd_, outPipeName(), true);
879 // Receives messages and sends then to client
880 void LyXComm::read_ready()
882 // FIXME: make read_buffer_ a class-member for multiple sessions
883 static string read_buffer_;
884 read_buffer_.erase();
886 int const charbuf_size = 100;
887 char charbuf[charbuf_size];
889 // As O_NONBLOCK is set, until no data is available for reading,
890 // read() doesn't block but returns -1 and set errno to EAGAIN.
891 // After a client that opened the pipe for writing, closes it
892 // (and no other client is using the pipe), read() would always
893 // return 0 and thus the connection has to be reset.
895 errno = 0;
896 int status;
897 // the single = is intended here.
898 while ((status = ::read(infd_, charbuf, charbuf_size - 1))) {
900 if (status > 0) {
901 charbuf[status] = '\0'; // turn it into a c string
902 read_buffer_ += rtrim(charbuf, "\r");
903 // commit any commands read
904 while (read_buffer_.find('\n') != string::npos) {
905 // split() grabs the entire string if
906 // the delim /wasn't/ found. ?:-P
907 string cmd;
908 read_buffer_= split(read_buffer_, cmd,'\n');
909 LYXERR(Debug::LYXSERVER, "LyXComm: status:" << status
910 << ", read_buffer_:" << read_buffer_
911 << ", cmd:" << cmd);
912 if (!cmd.empty())
913 clientcb_(client_, cmd);
914 //\n or not \n?
916 } else {
917 if (errno == EAGAIN) {
918 // Nothing to read, continue
919 errno = 0;
920 return;
922 // An error occurred, better bailing out
923 LYXERR0("LyXComm: " << strerror(errno));
924 if (!read_buffer_.empty()) {
925 LYXERR0("LyXComm: truncated command: " << read_buffer_);
926 read_buffer_.erase();
928 break; // reset connection
932 // The connection gets reset when read() returns 0 (meaning that the
933 // last client closed the pipe) or an error occurred, in which case
934 // read() returns -1 and errno != EAGAIN.
935 closeConnection();
936 openConnection();
937 errno = 0;
941 void LyXComm::send(string const & msg)
943 if (msg.empty()) {
944 LYXERR0("LyXComm: Request to send empty string. Ignoring.");
945 return;
948 LYXERR(Debug::LYXSERVER, "LyXComm: Sending '" << msg << '\'');
950 if (pipename_.empty()) return;
952 if (!ready_) {
953 LYXERR0("LyXComm: Pipes are closed. Could not send " << msg);
954 } else if (::write(outfd_, msg.c_str(), msg.length()) < 0) {
955 lyxerr << "LyXComm: Error sending message: " << msg
956 << '\n' << strerror(errno)
957 << "\nLyXComm: Resetting connection" << endl;
958 closeConnection();
959 openConnection();
963 #endif // defined (HAVE_MKFIFO)
966 string const LyXComm::inPipeName() const
968 return pipename_ + ".in";
972 string const LyXComm::outPipeName() const
974 return pipename_ + ".out";
978 /////////////////////////////////////////////////////////////////////
980 // Server
982 /////////////////////////////////////////////////////////////////////
984 void ServerCallback(Server * server, string const & msg)
986 server->callback(msg);
989 Server::Server(LyXFunc * f, string const & pipes)
990 : numclients_(0), func_(f), pipes_(pipes, this, &ServerCallback)
994 Server::~Server()
996 // say goodbye to clients so they stop sending messages
997 // send as many bye messages as there are clients,
998 // each with client's name.
999 string message;
1000 for (int i = 0; i != numclients_; ++i) {
1001 message = "LYXSRV:" + clients_[i] + ":bye\n";
1002 pipes_.send(message);
1007 int compare(char const * a, char const * b, unsigned int len)
1009 using namespace std;
1010 return strncmp(a, b, len);
1014 // Handle data gotten from communication, called by LyXComm
1015 void Server::callback(string const & msg)
1017 LYXERR(Debug::LYXSERVER, "Server: Received: '" << msg << '\'');
1019 char const * p = msg.c_str();
1021 // --- parse the string --------------------------------------------
1023 // Format: LYXCMD:<client>:<func>:<argstring>\n
1025 bool server_only = false;
1026 while (*p) {
1027 // --- 1. check 'header' ---
1029 if (compare(p, "LYXSRV:", 7) == 0) {
1030 server_only = true;
1031 } else if (0 != compare(p, "LYXCMD:", 7)) {
1032 lyxerr << "Server: Unknown request \""
1033 << p << '"' << endl;
1034 return;
1036 p += 7;
1038 // --- 2. for the moment ignore the client name ---
1039 string client;
1040 while (*p && *p != ':')
1041 client += char(*p++);
1042 if (*p == ':')
1043 ++p;
1044 if (!*p)
1045 return;
1047 // --- 3. get function name ---
1048 string cmd;
1049 while (*p && *p != ':')
1050 cmd += char(*p++);
1052 // --- 4. parse the argument ---
1053 string arg;
1054 if (!server_only && *p == ':' && *(++p)) {
1055 while (*p && *p != '\n')
1056 arg += char(*p++);
1057 if (*p) ++p;
1060 LYXERR(Debug::LYXSERVER, "Server: Client: '" << client
1061 << "' Command: '" << cmd << "' Argument: '" << arg << '\'');
1063 // --- lookup and exec the command ------------------
1065 if (server_only) {
1066 string buf;
1067 // return the greeting to inform the client that
1068 // we are listening.
1069 if (cmd == "hello") {
1070 // One more client
1071 if (numclients_ == MAX_CLIENTS) { //paranoid check
1072 LYXERR(Debug::LYXSERVER, "Server: too many clients...");
1073 return;
1075 int i = 0;
1076 while (!clients_[i].empty() && i < numclients_)
1077 ++i;
1078 clients_[i] = client;
1079 ++numclients_;
1080 buf = "LYXSRV:" + client + ":hello\n";
1081 LYXERR(Debug::LYXSERVER, "Server: Greeting " << client);
1082 pipes_.send(buf);
1083 } else if (cmd == "bye") {
1084 // If clients_ == 0 maybe we should reset the pipes
1085 // to prevent fake callbacks
1086 int i = 0; //look if client is registered
1087 for (; i < numclients_; ++i) {
1088 if (clients_[i] == client)
1089 break;
1091 if (i < numclients_) {
1092 --numclients_;
1093 clients_[i].erase();
1094 LYXERR(Debug::LYXSERVER, "Server: Client "
1095 << client << " said goodbye");
1096 } else {
1097 LYXERR(Debug::LYXSERVER,
1098 "Server: ignoring bye messge from unregistered client" << client);
1100 } else {
1101 LYXERR0("Server: Undefined server command " << cmd << '.');
1103 return;
1106 if (!cmd.empty()) {
1107 // which lyxfunc should we let it connect to?
1108 // The correct solution would be to have a
1109 // specialized (non-gui) BufferView. But how do
1110 // we do it now? Probably we should just let it
1111 // connect to the lyxfunc in the single LyXView we
1112 // support currently. (Lgb)
1114 func_->dispatch(FuncRequest(lyxaction.lookupFunc(cmd), arg));
1115 string const rval = to_utf8(func_->getMessage());
1117 // all commands produce an INFO or ERROR message
1118 // in the output pipe, even if they do not return
1119 // anything. See chapter 4 of Customization doc.
1120 string buf;
1121 if (func_->errorStat())
1122 buf = "ERROR:";
1123 else
1124 buf = "INFO:";
1125 buf += client + ':' + cmd + ':' + rval + '\n';
1126 pipes_.send(buf);
1128 // !!! we don't do any error checking -
1129 // if the client won't listen, the
1130 // message is lost and others too
1131 // maybe; so the client should empty
1132 // the outpipe before issuing a request.
1134 // not found
1136 } // while *p
1140 // Send a notify message to a client, called by WorkAreaKeyPress
1141 void Server::notifyClient(string const & s)
1143 pipes_.send("NOTIFY:" + s + "\n");
1147 } // namespace lyx
1149 #ifdef _WIN32
1150 #include "moc_Server.cpp"
1151 #endif