]> git.lyx.org Git - lyx.git/blob - src/Server.cpp
Amend 3093789e for cmake build
[lyx.git] / src / Server.cpp
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.
5  *
6  * \author Lars Gullik Bjønnes
7  * \author Jean-Marc Lasgouttes
8  * \author Angus Leeming
9  * \author John Levon
10  * \author Enrico Forestieri
11  *
12  * Full author contact details are available in file CREDITS.
13  */
14
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.
36
37            See development/lyxserver/server_monitor.cpp for an example client.
38   Purpose: implement a client/server lib for LyX
39 */
40
41 #include <config.h>
42
43 #include "Server.h"
44
45 #include "DispatchResult.h"
46 #include "FuncRequest.h"
47 #include "LyX.h"
48 #include "LyXAction.h"
49
50 #include "frontends/Application.h"
51
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"
58 #include "support/signals.h"
59
60 #include <iostream>
61
62 #ifdef _WIN32
63 #include <io.h>
64 #include <QCoreApplication>
65 #endif
66 #include <QThread>
67
68 #include <cerrno>
69 #ifdef HAVE_SYS_STAT_H
70 # include <sys/stat.h>
71 #endif
72 #include <fcntl.h>
73
74 using namespace std;
75 using namespace lyx::support;
76 using os::external_path;
77
78 namespace lyx {
79
80 /////////////////////////////////////////////////////////////////////
81 //
82 // LyXComm
83 //
84 /////////////////////////////////////////////////////////////////////
85
86 #if defined(_WIN32)
87
88 class ReadReadyEvent : public QEvent {
89 public:
90         ///
91         ReadReadyEvent(DWORD inpipe) : QEvent(QEvent::User), inpipe_(inpipe)
92         {}
93         ///
94         DWORD inpipe() const { return inpipe_; }
95
96 private:
97         DWORD inpipe_;
98 };
99
100 namespace {
101
102 string errormsg(DWORD const error)
103 {
104         void * msgbuf;
105         string message;
106         if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
107                           FORMAT_MESSAGE_FROM_SYSTEM |
108                           FORMAT_MESSAGE_IGNORE_INSERTS,
109                           NULL, error,
110                           MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
111                           (LPTSTR) &msgbuf, 0, NULL)) {
112                 message = static_cast<char *>(msgbuf);
113                 LocalFree(msgbuf);
114         } else
115                 message = "Unknown error";
116
117         return message;
118 }
119
120 } // namespace
121
122
123 DWORD WINAPI pipeServerWrapper(void * arg)
124 {
125         LyXComm * lyxcomm = reinterpret_cast<LyXComm *>(arg);
126         if (!lyxcomm->pipeServer()) {
127                 // Error exit; perform cleanup.
128                 lyxcomm->ready_ = false;
129                 lyxcomm->closeHandles();
130                 CloseHandle(lyxcomm->server_thread_);
131                 CloseHandle(lyxcomm->stopserver_);
132                 CloseHandle(lyxcomm->outbuf_mutex_);
133                 lyxerr << "LyXComm: Closing connection" << endl;
134         }
135         return 1;
136 }
137
138
139 LyXComm::LyXComm(string const & pip, Server * cli, ClientCallbackfct ccb)
140         : stopserver_(0),
141           ready_(false), pipename_(pip), client_(cli), clientcb_(ccb),
142           deferred_loading_(false)
143 {
144         for (int i = 0; i < MAX_PIPES; ++i) {
145                 event_[i] = 0;
146                 pipe_[i].handle = INVALID_HANDLE_VALUE;
147         }
148         openConnection();
149 }
150
151
152 bool LyXComm::pipeServer()
153 {
154         DWORD i;
155         DWORD error;
156
157         for (i = 0; i < MAX_PIPES; ++i) {
158                 bool const is_outpipe = i >= MAX_CLIENTS;
159                 DWORD const open_mode = is_outpipe ? PIPE_ACCESS_OUTBOUND
160                                                    : PIPE_ACCESS_INBOUND;
161                 string const pipename = external_path(pipeName(i));
162
163                 // Manual-reset event, initial state = signaled
164                 event_[i] = CreateEvent(NULL, TRUE, TRUE, NULL);
165                 if (!event_[i]) {
166                         error = GetLastError();
167                         lyxerr << "LyXComm: Could not create event for pipe "
168                                << pipename << "\nLyXComm: "
169                                << errormsg(error) << endl;
170                         return false;
171                 }
172
173                 pipe_[i].overlap.hEvent = event_[i];
174                 pipe_[i].iobuf.erase();
175                 pipe_[i].handle = CreateNamedPipe(pipename.c_str(),
176                                 open_mode | FILE_FLAG_OVERLAPPED, PIPE_WAIT,
177                                 MAX_CLIENTS, PIPE_BUFSIZE, PIPE_BUFSIZE,
178                                 PIPE_TIMEOUT, NULL);
179
180                 if (pipe_[i].handle == INVALID_HANDLE_VALUE) {
181                         error = GetLastError();
182                         lyxerr << "LyXComm: Could not create pipe "
183                                << pipename << "\nLyXComm: "
184                                << errormsg(error) << endl;
185                         return false;
186                 }
187
188                 if (!startPipe(i))
189                         return false;
190                 pipe_[i].state = pipe_[i].pending_io ?
191                         CONNECTING_STATE : (is_outpipe ? WRITING_STATE
192                                                        : READING_STATE);
193         }
194
195         // Add the stopserver_ event
196         event_[MAX_PIPES] = stopserver_;
197
198         // We made it!
199         LYXERR(Debug::LYXSERVER, "LyXComm: Connection established");
200         ready_ = true;
201         outbuf_.erase();
202         DWORD status = 0;
203         bool success = false;
204
205         while (!checkStopServer()) {
206                 // Indefinitely wait for the completion of an overlapped
207                 // read, write, or connect operation.
208                 DWORD wait = WaitForMultipleObjects(MAX_PIPES + 1, event_,
209                                                     FALSE, INFINITE);
210
211                 // Determine which pipe instance completed the operation.
212                 i = wait - WAIT_OBJECT_0;
213                 LASSERT(i <= MAX_PIPES, /**/);
214
215                 // Check whether we were waked up for stopping the pipe server.
216                 if (i == MAX_PIPES)
217                         break;
218
219                 bool const is_outpipe = i >= MAX_CLIENTS;
220
221                 // Get the result if the operation was pending.
222                 if (pipe_[i].pending_io) {
223                         success = GetOverlappedResult(pipe_[i].handle,
224                                         &pipe_[i].overlap, &status, FALSE);
225
226                         switch (pipe_[i].state) {
227                         case CONNECTING_STATE:
228                                 // Pending connect operation
229                                 if (!success) {
230                                         error = GetLastError();
231                                         lyxerr << "LyXComm: "
232                                                << errormsg(error) << endl;
233                                         if (!resetPipe(i, true))
234                                                 return false;
235                                         continue;
236                                 }
237                                 pipe_[i].state = is_outpipe ? WRITING_STATE
238                                                             : READING_STATE;
239                                 break;
240
241                         case READING_STATE:
242                                 // Pending read operation
243                                 LASSERT(!is_outpipe, /**/);
244                                 if (!success || status == 0) {
245                                         if (!resetPipe(i, !success))
246                                                 return false;
247                                         continue;
248                                 }
249                                 pipe_[i].nbytes = status;
250                                 pipe_[i].state = WRITING_STATE;
251                                 break;
252
253                         case WRITING_STATE:
254                                 // Pending write operation
255                                 LASSERT(is_outpipe, /**/);
256                                 // Let's see whether we have a reply
257                                 if (!outbuf_.empty()) {
258                                         // Yep. Deliver it to all pipe
259                                         // instances if we get ownership
260                                         // of the mutex, otherwise we'll
261                                         // try again the next round.
262                                         DWORD result = WaitForSingleObject(
263                                                         outbuf_mutex_, 200);
264                                         if (result == WAIT_OBJECT_0) {
265                                                 DWORD j = MAX_CLIENTS;
266                                                 while (j < MAX_PIPES) {
267                                                         pipe_[j].iobuf = outbuf_;
268                                                         ++j;
269                                                 }
270                                                 outbuf_.erase();
271                                         }
272                                         ReleaseMutex(outbuf_mutex_);
273                                 }
274                                 if (pipe_[i].iobuf.empty())
275                                         pipe_[i].pending_io = false;
276                                 break;
277                         }
278                 }
279
280                 // Operate according to the pipe state
281                 switch (pipe_[i].state) {
282                 case READING_STATE:
283                         // The pipe instance is connected to a client
284                         // and is ready to read a request.
285                         LASSERT(!is_outpipe, /**/);
286                         success = ReadFile(pipe_[i].handle,
287                                         pipe_[i].readbuf, PIPE_BUFSIZE - 1,
288                                         &pipe_[i].nbytes, &pipe_[i].overlap);
289
290                         if (success && pipe_[i].nbytes != 0) {
291                                 // The read operation completed successfully.
292                                 pipe_[i].pending_io = false;
293                                 pipe_[i].state = WRITING_STATE;
294                                 continue;
295                         }
296
297                         error = GetLastError();
298
299                         if (!success && error == ERROR_IO_PENDING) {
300                                 // The read operation is still pending.
301                                 pipe_[i].pending_io = true;
302                                 continue;
303                         }
304
305                         success = error == ERROR_BROKEN_PIPE;
306
307                         // Client closed connection (ERROR_BROKEN_PIPE) or
308                         // an error occurred; in either case, reset the pipe.
309                         if (!success) {
310                                 lyxerr << "LyXComm: " << errormsg(error) << endl;
311                                 if (!pipe_[i].iobuf.empty()) {
312                                         lyxerr << "LyXComm: truncated command: "
313                                                << pipe_[i].iobuf << endl;
314                                         pipe_[i].iobuf.erase();
315                                 }
316                         }
317                         if (!resetPipe(i, !success))
318                                 return false;
319                         break;
320
321                 case WRITING_STATE:
322                         if (!is_outpipe) {
323                                 // The request was successfully read
324                                 // from the client; commit it.
325                                 ReadReadyEvent * event = new ReadReadyEvent(i);
326                                 QCoreApplication::postEvent(this,
327                                                 static_cast<QEvent *>(event));
328                                 // Wait for completion
329                                 while (pipe_[i].nbytes && !checkStopServer(100))
330                                         ;
331                                 pipe_[i].pending_io = false;
332                                 pipe_[i].state = READING_STATE;
333                                 continue;
334                         }
335
336                         // This is an output pipe instance. Initiate the
337                         // overlapped write operation or monitor its progress.
338
339                         if (pipe_[i].pending_io) {
340                                 success = WriteFile(pipe_[i].handle,
341                                                 pipe_[i].iobuf.c_str(),
342                                                 pipe_[i].iobuf.length(),
343                                                 &status,
344                                                 &pipe_[i].overlap);
345                         }
346
347                         if (success && !pipe_[i].iobuf.empty()
348                             && status == pipe_[i].iobuf.length()) {
349                                 // The write operation completed successfully.
350                                 pipe_[i].iobuf.erase();
351                                 pipe_[i].pending_io = false;
352                                 if (!resetPipe(i))
353                                         return false;
354                                 continue;
355                         }
356
357                         error = GetLastError();
358
359                         if (success && (error == ERROR_IO_PENDING || error == NO_ERROR)) {
360                                 // The write operation is still pending.
361                                 // We get here when a reader is started
362                                 // well before a reply is ready, so delay
363                                 // a bit in order to not burden the cpu.
364                                 checkStopServer(100);
365                                 pipe_[i].pending_io = true;
366                                 continue;
367                         }
368
369                         success = error == ERROR_NO_DATA;
370
371                         // Client closed connection (ERROR_NO_DATA) or
372                         // an error occurred; in either case, reset the pipe.
373                         if (!success) {
374                                 lyxerr << "LyXComm: Error sending message: "
375                                        << pipe_[i].iobuf << "\nLyXComm: "
376                                        << errormsg(error) << endl;
377                         }
378                         if (!resetPipe(i, !success))
379                                 return false;
380                         break;
381                 case CONNECTING_STATE:
382                         LYXERR0("Wrong pipe state");
383                         break;
384                 }
385         }
386
387         ready_ = false;
388         closeHandles();
389         return true;
390 }
391
392
393 void LyXComm::closeHandles()
394 {
395         for (int i = 0; i < MAX_PIPES; ++i) {
396                 if (event_[i]) {
397                         ResetEvent(event_[i]);
398                         CloseHandle(event_[i]);
399                         event_[i] = 0;
400                 }
401                 if (pipe_[i].handle != INVALID_HANDLE_VALUE) {
402                         CloseHandle(pipe_[i].handle);
403                         pipe_[i].handle = INVALID_HANDLE_VALUE;
404                 }
405         }
406 }
407
408
409 bool LyXComm::event(QEvent * e)
410 {
411         if (e->type() == QEvent::User) {
412                 read_ready(static_cast<ReadReadyEvent *>(e)->inpipe());
413                 return true;
414         }
415         return false;
416 }
417
418
419 bool LyXComm::checkStopServer(DWORD timeout)
420 {
421         return WaitForSingleObject(stopserver_, timeout) == WAIT_OBJECT_0;
422 }
423
424
425 bool LyXComm::startPipe(DWORD index)
426 {
427         pipe_[index].pending_io = false;
428         pipe_[index].overlap.Offset = 0;
429         pipe_[index].overlap.OffsetHigh = 0;
430
431         // Overlapped ConnectNamedPipe should return zero.
432         if (ConnectNamedPipe(pipe_[index].handle, &pipe_[index].overlap)) {
433                 DWORD const error = GetLastError();
434                 lyxerr << "LyXComm: Could not connect pipe "
435                        << external_path(pipeName(index))
436                        << "\nLyXComm: " << errormsg(error) << endl;
437                 return false;
438         }
439
440         switch (GetLastError()) {
441         case ERROR_IO_PENDING:
442                 // The overlapped connection is in progress.
443                 pipe_[index].pending_io = true;
444                 break;
445
446         case ERROR_PIPE_CONNECTED:
447                 // Client is already connected, so signal an event.
448                 if (SetEvent(pipe_[index].overlap.hEvent))
449                         break;
450                 // fall through
451         default:
452                 // Anything else is an error.
453                 DWORD const error = GetLastError();
454                 lyxerr << "LyXComm: An error occurred while connecting pipe "
455                        << external_path(pipeName(index))
456                        << "\nLyXComm: " << errormsg(error) << endl;
457                 return false;
458         }
459
460         return true;
461 }
462
463
464 bool LyXComm::resetPipe(DWORD index, bool close_handle)
465 {
466         // This method is called when an error occurs or when a client
467         // closes the connection. We first disconnect the pipe instance,
468         // then reconnect it, ready to wait for another client.
469
470         if (!DisconnectNamedPipe(pipe_[index].handle)) {
471                 DWORD const error = GetLastError();
472                 lyxerr << "LyXComm: Could not disconnect pipe "
473                        << external_path(pipeName(index))
474                        << "\nLyXComm: " << errormsg(error) << endl;
475                 // What to do now? Let's try whether re-creating the pipe helps.
476                 close_handle = true;
477         }
478
479         bool const is_outpipe = index >= MAX_CLIENTS;
480
481         if (close_handle) {
482                 DWORD const open_mode = is_outpipe ? PIPE_ACCESS_OUTBOUND
483                                                    : PIPE_ACCESS_INBOUND;
484                 string const name = external_path(pipeName(index));
485
486                 CloseHandle(pipe_[index].handle);
487
488                 pipe_[index].iobuf.erase();
489                 pipe_[index].handle = CreateNamedPipe(name.c_str(),
490                                 open_mode | FILE_FLAG_OVERLAPPED, PIPE_WAIT,
491                                 MAX_CLIENTS, PIPE_BUFSIZE, PIPE_BUFSIZE,
492                                 PIPE_TIMEOUT, NULL);
493
494                 if (pipe_[index].handle == INVALID_HANDLE_VALUE) {
495                         DWORD const error = GetLastError();
496                         lyxerr << "LyXComm: Could not reset pipe " << name
497                                << "\nLyXComm: " << errormsg(error) << endl;
498                         return false;
499                 }
500         }
501
502         if (!startPipe(index))
503                 return false;
504         pipe_[index].state = pipe_[index].pending_io ?
505                         CONNECTING_STATE : (is_outpipe ? WRITING_STATE
506                                                        : READING_STATE);
507         return true;
508 }
509
510
511 void LyXComm::openConnection()
512 {
513         LYXERR(Debug::LYXSERVER, "LyXComm: Opening connection");
514
515         // If we are up, that's an error
516         if (ready_) {
517                 LYXERR(Debug::LYXSERVER, "LyXComm: Already connected");
518                 return;
519         }
520
521         if (pipename_.empty()) {
522                 LYXERR(Debug::LYXSERVER, "LyXComm: server is disabled, nothing to do");
523                 return;
524         }
525
526         // Check whether the pipe name is being used by some other instance.
527         if (!stopserver_ && WaitNamedPipe(inPipeName().c_str(), 0)) {
528                 // Tell the running instance to load the files
529                 if (run_mode == USE_REMOTE && loadFilesInOtherInstance()) {
530                         deferred_loading_ = true;
531                         pipename_.erase();
532                         return;
533                 }
534                 lyxerr << "LyXComm: Pipe " << external_path(inPipeName())
535                        << " already exists.\nMaybe another instance of LyX"
536                           " is using it." << endl;
537                 pipename_.erase();
538                 return;
539         }
540
541         // Mutex with no initial owner for synchronized access to outbuf_
542         outbuf_mutex_ = CreateMutex(NULL, FALSE, NULL);
543         if (!outbuf_mutex_) {
544                 DWORD const error = GetLastError();
545                 lyxerr << "LyXComm: Could not create output buffer mutex"
546                        << "\nLyXComm: " << errormsg(error) << endl;
547                 pipename_.erase();
548                 return;
549         }
550
551         // Manual-reset event, initial state = not signaled
552         stopserver_ = CreateEvent(NULL, TRUE, FALSE, NULL);
553         if (!stopserver_) {
554                 DWORD const error = GetLastError();
555                 lyxerr << "LyXComm: Could not create stop server event"
556                        << "\nLyXComm: " << errormsg(error) << endl;
557                 pipename_.erase();
558                 CloseHandle(outbuf_mutex_);
559                 return;
560         }
561
562         server_thread_ = CreateThread(NULL, 0, pipeServerWrapper,
563                                      static_cast<void *>(this), 0, NULL);
564         if (!server_thread_) {
565                 DWORD const error = GetLastError();
566                 lyxerr << "LyXComm: Could not create pipe server thread"
567                        << "\nLyXComm: " << errormsg(error) << endl;
568                 pipename_.erase();
569                 CloseHandle(stopserver_);
570                 CloseHandle(outbuf_mutex_);
571                 return;
572         }
573 }
574
575
576 /// Close pipes
577 void LyXComm::closeConnection()
578 {
579         LYXERR(Debug::LYXSERVER, "LyXComm: Closing connection");
580
581         if (pipename_.empty()) {
582                 LYXERR(Debug::LYXSERVER, "LyXComm: server is disabled, nothing to do");
583                 return;
584         }
585
586         if (!ready_) {
587                 LYXERR(Debug::LYXSERVER, "LyXComm: Already disconnected");
588                 return;
589         }
590
591         SetEvent(stopserver_);
592         // Wait for the pipe server to finish
593         WaitForSingleObject(server_thread_, INFINITE);
594         CloseHandle(server_thread_);
595         ResetEvent(stopserver_);
596         CloseHandle(stopserver_);
597         CloseHandle(outbuf_mutex_);
598 }
599
600
601 void LyXComm::emergencyCleanup()
602 {
603         if (ready_) {
604                 SetEvent(stopserver_);
605                 // Forcibly terminate the pipe server thread if it does
606                 // not finish quickly.
607                 if (WaitForSingleObject(server_thread_, 200) != WAIT_OBJECT_0) {
608                         TerminateThread(server_thread_, 0);
609                         ready_ = false;
610                         closeHandles();
611                 }
612                 CloseHandle(server_thread_);
613                 ResetEvent(stopserver_);
614                 CloseHandle(stopserver_);
615                 CloseHandle(outbuf_mutex_);
616         }
617 }
618
619
620 void LyXComm::read_ready(DWORD inpipe)
621 {
622         // Turn the pipe buffer into a C string
623         DWORD const nbytes = pipe_[inpipe].nbytes;
624         pipe_[inpipe].readbuf[nbytes] = '\0';
625
626         pipe_[inpipe].iobuf += rtrim(pipe_[inpipe].readbuf, "\r");
627
628         // Commit any commands read
629         while (pipe_[inpipe].iobuf.find('\n') != string::npos) {
630                 // split() grabs the entire string if
631                 // the delim /wasn't/ found. ?:-P
632                 string cmd;
633                 pipe_[inpipe].iobuf = split(pipe_[inpipe].iobuf, cmd, '\n');
634                 cmd = rtrim(cmd, "\r");
635                 LYXERR(Debug::LYXSERVER, "LyXComm: nbytes:" << nbytes
636                         << ", iobuf:" << pipe_[inpipe].iobuf
637                         << ", cmd:" << cmd);
638                 if (!cmd.empty())
639                         clientcb_(client_, cmd);
640                         //\n or not \n?
641         }
642         // Signal that we are done.
643         pipe_[inpipe].nbytes = 0;
644 }
645
646
647 void LyXComm::send(string const & msg)
648 {
649         if (msg.empty()) {
650                 lyxerr << "LyXComm: Request to send empty string. Ignoring."
651                        << endl;
652                 return;
653         }
654
655         LYXERR(Debug::LYXSERVER, "LyXComm: Sending '" << msg << '\'');
656
657         if (pipename_.empty())
658                 return;
659
660         if (!ready_) {
661                 lyxerr << "LyXComm: Pipes are closed. Could not send "
662                        << msg << endl;
663                 return;
664         }
665
666         // Request ownership of the outbuf_mutex_
667         DWORD result = WaitForSingleObject(outbuf_mutex_, PIPE_TIMEOUT);
668
669         if (result == WAIT_OBJECT_0) {
670                 // If a client doesn't care to read a reply (JabRef is one
671                 // such client), the output buffer could grow without limit.
672                 // So, we empty it when its size is larger than PIPE_BUFSIZE.
673                 if (outbuf_.size() > PIPE_BUFSIZE)
674                         outbuf_.erase();
675                 outbuf_ += msg;
676                 ReleaseMutex(outbuf_mutex_);
677         } else {
678                 // Something is fishy, better resetting the connection.
679                 DWORD const error = GetLastError();
680                 lyxerr << "LyXComm: Error sending message: " << msg
681                        << "\nLyXComm: " << errormsg(error)
682                        << "\nLyXComm: Resetting connection" << endl;
683                 ReleaseMutex(outbuf_mutex_);
684                 closeConnection();
685                 openConnection();
686         }
687 }
688
689
690 string const LyXComm::pipeName(DWORD index) const
691 {
692         return index < MAX_CLIENTS ? inPipeName() : outPipeName();
693 }
694
695
696 #elif !defined (HAVE_MKFIFO)
697 // We provide a stub class that disables the lyxserver.
698
699 LyXComm::LyXComm(string const &, Server *, ClientCallbackfct)
700 {}
701
702
703 void LyXComm::openConnection()
704 {}
705
706
707 void LyXComm::closeConnection()
708 {}
709
710
711 int LyXComm::startPipe(string const & filename, bool write)
712 {
713         return -1;
714 }
715
716
717 void LyXComm::endPipe(int & fd, string const & filename, bool write)
718 {}
719
720
721 void LyXComm::emergencyCleanup()
722 {}
723
724
725 void LyXComm::read_ready()
726 {}
727
728
729 void LyXComm::send(string const & msg)
730 {}
731
732
733 #else // defined (HAVE_MKFIFO)
734
735 LyXComm::LyXComm(string const & pip, Server * cli, ClientCallbackfct ccb)
736         : infd_(-1), outfd_(-1),
737           ready_(false), pipename_(pip), client_(cli), clientcb_(ccb),
738           deferred_loading_(false)
739 {
740         openConnection();
741 }
742
743
744 void LyXComm::openConnection()
745 {
746         LYXERR(Debug::LYXSERVER, "LyXComm: Opening connection");
747
748         // If we are up, that's an error
749         if (ready_) {
750                 lyxerr << "LyXComm: Already connected" << endl;
751                 return;
752         }
753         // We assume that we don't make it
754         ready_ = false;
755
756         if (pipename_.empty()) {
757                 LYXERR(Debug::LYXSERVER, "LyXComm: server is disabled, nothing to do");
758                 return;
759         }
760
761         infd_ = startPipe(inPipeName(), false);
762         if (infd_ == -1)
763                 return;
764
765         outfd_ = startPipe(outPipeName(), true);
766         if (outfd_ == -1) {
767                 endPipe(infd_, inPipeName(), false);
768                 return;
769         }
770
771         if (fcntl(outfd_, F_SETFL, O_NONBLOCK) < 0) {
772                 lyxerr << "LyXComm: Could not set flags on pipe " << outPipeName()
773                        << '\n' << strerror(errno) << endl;
774                 return;
775         }
776
777         // We made it!
778         ready_ = true;
779         LYXERR(Debug::LYXSERVER, "LyXComm: Connection established");
780 }
781
782
783 /// Close pipes
784 void LyXComm::closeConnection()
785 {
786         LYXERR(Debug::LYXSERVER, "LyXComm: Closing connection");
787
788         if (pipename_.empty()) {
789                 LYXERR(Debug::LYXSERVER, "LyXComm: server is disabled, nothing to do");
790                 return;
791         }
792
793         if (!ready_) {
794                 LYXERR0("LyXComm: Already disconnected");
795                 return;
796         }
797
798         endPipe(infd_, inPipeName(), false);
799         endPipe(outfd_, outPipeName(), true);
800
801         ready_ = false;
802 }
803
804
805 int LyXComm::startPipe(string const & file, bool write)
806 {
807         static bool stalepipe = false;
808         FileName const filename(file);
809         if (filename.exists()) {
810                 if (!write) {
811                         // Let's see whether we have a stale pipe.
812                         int fd = ::open(filename.toFilesystemEncoding().c_str(),
813                                         O_WRONLY | O_NONBLOCK);
814                         if (fd >= 0) {
815                                 // Another LyX instance is using it.
816                                 ::close(fd);
817                                 // Tell the running instance to load the files
818                                 if (run_mode == USE_REMOTE && loadFilesInOtherInstance()) {
819                                         deferred_loading_ = true;
820                                         pipename_.erase();
821                                         return -1;
822                                 }
823                         } else if (errno == ENXIO) {
824                                 // No process is reading from the other end.
825                                 stalepipe = true;
826                                 LYXERR(Debug::LYXSERVER,
827                                         "LyXComm: trying to remove "
828                                         << filename);
829                                 filename.removeFile();
830                         }
831                 } else if (stalepipe) {
832                         LYXERR(Debug::LYXSERVER, "LyXComm: trying to remove "
833                                 << filename);
834                         filename.removeFile();
835                         stalepipe = false;
836                 }
837                 if (filename.exists()) {
838                         lyxerr << "LyXComm: Pipe " << filename
839                                << " already exists.\nIf no other LyX program"
840                                   " is active, please delete the pipe by hand"
841                                   " and try again."
842                                << endl;
843                         pipename_.erase();
844                         return -1;
845                 }
846         }
847
848         if (::mkfifo(filename.toFilesystemEncoding().c_str(), 0600) < 0) {
849                 lyxerr << "LyXComm: Could not create pipe " << filename << '\n'
850                        << strerror(errno) << endl;
851                 return -1;
852         }
853         int const fd = ::open(filename.toFilesystemEncoding().c_str(),
854                               write ? (O_RDWR) : (O_RDONLY|O_NONBLOCK));
855
856         if (fd < 0) {
857                 lyxerr << "LyXComm: Could not open pipe " << filename << '\n'
858                        << strerror(errno) << endl;
859                 filename.removeFile();
860                 return -1;
861         }
862
863         if (!write) {
864                 // Make sure not to call read_ready after destruction.
865                 weak_ptr<void> tracker = tracker_.p();
866                 theApp()->registerSocketCallback(fd, [=](){
867                                 if (!tracker.expired())
868                                         read_ready();
869                         });
870         }
871
872         return fd;
873 }
874
875
876 void LyXComm::endPipe(int & fd, string const & filename, bool write)
877 {
878         if (fd < 0)
879                 return;
880
881         if (!write)
882                 theApp()->unregisterSocketCallback(fd);
883
884         if (::close(fd) < 0) {
885                 lyxerr << "LyXComm: Could not close pipe " << filename
886                        << '\n' << strerror(errno) << endl;
887         }
888
889         if (!FileName(filename).removeFile()) {
890                 lyxerr << "LyXComm: Could not remove pipe " << filename
891                        << '\n' << strerror(errno) << endl;
892         }
893
894         fd = -1;
895 }
896
897
898 void LyXComm::emergencyCleanup()
899 {
900         if (!pipename_.empty()) {
901                 endPipe(infd_, inPipeName(), false);
902                 endPipe(outfd_, outPipeName(), true);
903         }
904 }
905
906
907 // Receives messages and sends then to client
908 void LyXComm::read_ready()
909 {
910         // FIXME: make read_buffer_ a class-member for multiple sessions
911         static string read_buffer_;
912         read_buffer_.erase();
913
914         int const charbuf_size = 100;
915         char charbuf[charbuf_size];
916
917         // As O_NONBLOCK is set, until no data is available for reading,
918         // read() doesn't block but returns -1 and set errno to EAGAIN.
919         // After a client that opened the pipe for writing, closes it
920         // (and no other client is using the pipe), read() would always
921         // return 0 and thus the connection has to be reset.
922
923         errno = 0;
924         int status;
925         // the single = is intended here.
926         while ((status = ::read(infd_, charbuf, charbuf_size - 1))) {
927                 if (status > 0) {
928                         charbuf[status] = '\0'; // turn it into a c string
929                         read_buffer_ += rtrim(charbuf, "\r");
930                         // commit any commands read
931                         while (read_buffer_.find('\n') != string::npos) {
932                                 // split() grabs the entire string if
933                                 // the delim /wasn't/ found. ?:-P
934                                 string cmd;
935                                 read_buffer_= split(read_buffer_, cmd,'\n');
936                                 LYXERR(Debug::LYXSERVER, "LyXComm: status:" << status
937                                         << ", read_buffer_:" << read_buffer_
938                                         << ", cmd:" << cmd);
939                                 if (!cmd.empty())
940                                         clientcb_(client_, cmd);
941                                         //\n or not \n?
942                         }
943                 } else {
944                         if (errno == EAGAIN) {
945                                 // Nothing to read, continue
946                                 errno = 0;
947                                 return;
948                         }
949                         // An error occurred, better bailing out
950                         LYXERR0("LyXComm: " << strerror(errno));
951                         if (!read_buffer_.empty()) {
952                                 LYXERR0("LyXComm: truncated command: " << read_buffer_);
953                                 read_buffer_.erase();
954                         }
955                         break; // reset connection
956                 }
957         }
958
959         // The connection gets reset when read() returns 0 (meaning that the
960         // last client closed the pipe) or an error occurred, in which case
961         // read() returns -1 and errno != EAGAIN.
962         closeConnection();
963         openConnection();
964         errno = 0;
965 }
966
967
968 void LyXComm::send(string const & msg)
969 {
970         if (msg.empty()) {
971                 LYXERR0("LyXComm: Request to send empty string. Ignoring.");
972                 return;
973         }
974
975         LYXERR(Debug::LYXSERVER, "LyXComm: Sending '" << msg << '\'');
976
977         if (pipename_.empty())
978                 return;
979
980         if (!ready_) {
981                 LYXERR0("LyXComm: Pipes are closed. Could not send " << msg);
982         } else if (::write(outfd_, msg.c_str(), msg.length()) < 0) {
983                 lyxerr << "LyXComm: Error sending message: " << msg
984                        << '\n' << strerror(errno)
985                        << "\nLyXComm: Resetting connection" << endl;
986                 closeConnection();
987                 openConnection();
988         }
989 }
990
991 #endif // defined (HAVE_MKFIFO)
992
993 namespace {
994
995 struct Sleep : QThread
996 {
997         static void millisec(unsigned long ms)
998         {
999                 QThread::usleep(ms * 1000);
1000         }
1001 };
1002
1003 } // namespace
1004
1005
1006 bool LyXComm::loadFilesInOtherInstance() const
1007 {
1008         int pipefd;
1009         FileName const pipe(inPipeName());
1010
1011         if (theFilesToLoad().empty()) {
1012                 LYXERR0("LyX is already running in another instance\n"
1013                         "and 'use single instance' is active.");
1014                 // Wait a while for the other instance to reset the connection
1015                 Sleep::millisec(200);
1016                 pipefd = ::open(pipe.toFilesystemEncoding().c_str(), O_WRONLY);
1017                 if (pipefd >= 0) {
1018                         string const cmd = "LYXCMD:pipe:window-raise\n";
1019                         if (::write(pipefd, cmd.c_str(), cmd.length()) < 0)
1020                                 LYXERR0("Cannot communicate with running instance!");
1021                         ::close(pipefd);
1022                 }
1023                 return true;
1024         }
1025
1026         int loaded_files = 0;
1027         vector<string>::iterator it = theFilesToLoad().begin();
1028         while (it != theFilesToLoad().end()) {
1029                 FileName fname = fileSearch(string(), os::internal_path(*it),
1030                                                 "lyx", may_not_exist);
1031                 if (fname.empty()) {
1032                         ++it;
1033                         continue;
1034                 }
1035                 // Wait a while to allow time for the other
1036                 // instance to reset the connection
1037                 Sleep::millisec(200);
1038                 pipefd = ::open(pipe.toFilesystemEncoding().c_str(), O_WRONLY);
1039                 if (pipefd < 0)
1040                         break;
1041                 string const cmd = "LYXCMD:pipe:file-open:" +
1042                                         fname.absFileName() + '\n';
1043                 if (::write(pipefd, cmd.c_str(), cmd.length()) < 0)
1044                         LYXERR0("Cannot write to pipe!");
1045                 ::close(pipefd);
1046                 ++loaded_files;
1047                 it = theFilesToLoad().erase(it);
1048         }
1049         return loaded_files > 0;
1050 }
1051
1052
1053 string const LyXComm::inPipeName() const
1054 {
1055         return pipename_ + ".in";
1056 }
1057
1058
1059 string const LyXComm::outPipeName() const
1060 {
1061         return pipename_ + ".out";
1062 }
1063
1064
1065 /////////////////////////////////////////////////////////////////////
1066 //
1067 // Server
1068 //
1069 /////////////////////////////////////////////////////////////////////
1070
1071 void ServerCallback(Server * server, string const & msg)
1072 {
1073         server->callback(msg);
1074 }
1075
1076 Server::Server(string const & pipes)
1077         : numclients_(0), pipes_(pipes, this, &ServerCallback)
1078 {}
1079
1080
1081 Server::~Server()
1082 {
1083         // say goodbye to clients so they stop sending messages
1084         // send as many bye messages as there are clients,
1085         // each with client's name.
1086         string message;
1087         for (int i = 0; i != numclients_; ++i) {
1088                 message = "LYXSRV:" + clients_[i] + ":bye\n";
1089                 pipes_.send(message);
1090         }
1091 }
1092
1093
1094 int compare(char const * a, char const * b, unsigned int len)
1095 {
1096         return strncmp(a, b, len);
1097 }
1098
1099
1100 // Handle data gotten from communication, called by LyXComm
1101 void Server::callback(string const & msg)
1102 {
1103         LYXERR(Debug::LYXSERVER, "Server: Received: '" << msg << '\'');
1104
1105         char const * p = msg.c_str();
1106
1107         // --- parse the string --------------------------------------------
1108         //
1109         //  Format: LYXCMD:<client>:<func>:<argstring>\n
1110         //
1111         bool server_only = false;
1112         while (*p) {
1113                 // --- 1. check 'header' ---
1114
1115                 if (compare(p, "LYXSRV:", 7) == 0) {
1116                         server_only = true;
1117                 } else if (0 != compare(p, "LYXCMD:", 7)) {
1118                         lyxerr << "Server: Unknown request \""
1119                                << p << '"' << endl;
1120                         return;
1121                 }
1122                 p += 7;
1123
1124                 // --- 2. for the moment ignore the client name ---
1125                 string client;
1126                 while (*p && *p != ':')
1127                         client += char(*p++);
1128                 if (*p == ':')
1129                         ++p;
1130                 if (!*p)
1131                         return;
1132
1133                 // --- 3. get function name ---
1134                 string cmd;
1135                 while (*p && *p != ':')
1136                         cmd += char(*p++);
1137
1138                 // --- 4. parse the argument ---
1139                 string arg;
1140                 if (!server_only && *p == ':' && *(++p)) {
1141                         while (*p && *p != '\n')
1142                                 arg += char(*p++);
1143                         if (*p) ++p;
1144                 }
1145
1146                 LYXERR(Debug::LYXSERVER, "Server: Client: '" << client
1147                         << "' Command: '" << cmd << "' Argument: '" << arg << '\'');
1148
1149                 // --- lookup and exec the command ------------------
1150
1151                 if (server_only) {
1152                         string buf;
1153                         // return the greeting to inform the client that
1154                         // we are listening.
1155                         if (cmd == "hello") {
1156                                 // One more client
1157                                 if (numclients_ == MAX_CLIENTS) { //paranoid check
1158                                         LYXERR(Debug::LYXSERVER, "Server: too many clients...");
1159                                         return;
1160                                 }
1161                                 int i = 0;
1162                                 while (!clients_[i].empty() && i < numclients_)
1163                                         ++i;
1164                                 clients_[i] = client;
1165                                 ++numclients_;
1166                                 buf = "LYXSRV:" + client + ":hello\n";
1167                                 LYXERR(Debug::LYXSERVER, "Server: Greeting " << client);
1168                                 pipes_.send(buf);
1169                         } else if (cmd == "bye") {
1170                                 // If clients_ == 0 maybe we should reset the pipes
1171                                 // to prevent fake callbacks
1172                                 int i = 0; //look if client is registered
1173                                 for (; i < numclients_; ++i) {
1174                                         if (clients_[i] == client)
1175                                                 break;
1176                                 }
1177                                 if (i < numclients_) {
1178                                         --numclients_;
1179                                         clients_[i].erase();
1180                                         LYXERR(Debug::LYXSERVER, "Server: Client "
1181                                                 << client << " said goodbye");
1182                                 } else {
1183                                         LYXERR(Debug::LYXSERVER,
1184                                                 "Server: ignoring bye message from unregistered client" << client);
1185                                 }
1186                         } else {
1187                                 LYXERR0("Server: Undefined server command " << cmd << '.');
1188                         }
1189                         return;
1190                 }
1191
1192                 if (!cmd.empty()) {
1193                         // which lyxfunc should we let it connect to?
1194                         // The correct solution would be to have a
1195                         // specialized (non-gui) BufferView. But how do
1196                         // we do it now? Probably we should just let it
1197                         // connect to the lyxfunc in the single GuiView we
1198                         // support currently. (Lgb)
1199
1200                         FuncRequest fr(lyxaction.lookupFunc(cmd), from_utf8(arg));
1201                         fr.setOrigin(FuncRequest::LYXSERVER);
1202                         DispatchResult dr;
1203                         theApp()->dispatch(fr, dr);
1204                         string const rval = to_utf8(dr.message());
1205
1206                         // all commands produce an INFO or ERROR message
1207                         // in the output pipe, even if they do not return
1208                         // anything. See chapter 4 of Customization doc.
1209                         string buf;
1210                         if (dr.error())
1211                                 buf = "ERROR:";
1212                         else
1213                                 buf = "INFO:";
1214                         buf += client + ':' + cmd + ':' +  rval + '\n';
1215                         pipes_.send(buf);
1216
1217                         // !!! we don't do any error checking -
1218                         //  if the client won't listen, the
1219                         //  message is lost and others too
1220                         //  maybe; so the client should empty
1221                         //  the outpipe before issuing a request.
1222
1223                         // not found
1224                 }
1225         }  // while *p
1226 }
1227
1228
1229 // Send a notify message to a client, called by WorkAreaKeyPress
1230 void Server::notifyClient(string const & s)
1231 {
1232         pipes_.send("NOTIFY:" + s + "\n");
1233 }
1234
1235
1236 } // namespace lyx
1237
1238 #ifdef _WIN32
1239 #include "moc_Server.cpp"
1240 #endif