]> git.lyx.org Git - lyx.git/blob - src/Server.cpp
Fix bug #11635
[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                 }
382         }
383
384         ready_ = false;
385         closeHandles();
386         return true;
387 }
388
389
390 void LyXComm::closeHandles()
391 {
392         for (int i = 0; i < MAX_PIPES; ++i) {
393                 if (event_[i]) {
394                         ResetEvent(event_[i]);
395                         CloseHandle(event_[i]);
396                         event_[i] = 0;
397                 }
398                 if (pipe_[i].handle != INVALID_HANDLE_VALUE) {
399                         CloseHandle(pipe_[i].handle);
400                         pipe_[i].handle = INVALID_HANDLE_VALUE;
401                 }
402         }
403 }
404
405
406 bool LyXComm::event(QEvent * e)
407 {
408         if (e->type() == QEvent::User) {
409                 read_ready(static_cast<ReadReadyEvent *>(e)->inpipe());
410                 return true;
411         }
412         return false;
413 }
414
415
416 bool LyXComm::checkStopServer(DWORD timeout)
417 {
418         return WaitForSingleObject(stopserver_, timeout) == WAIT_OBJECT_0;
419 }
420
421
422 bool LyXComm::startPipe(DWORD index)
423 {
424         pipe_[index].pending_io = false;
425         pipe_[index].overlap.Offset = 0;
426         pipe_[index].overlap.OffsetHigh = 0;
427
428         // Overlapped ConnectNamedPipe should return zero.
429         if (ConnectNamedPipe(pipe_[index].handle, &pipe_[index].overlap)) {
430                 DWORD const error = GetLastError();
431                 lyxerr << "LyXComm: Could not connect pipe "
432                        << external_path(pipeName(index))
433                        << "\nLyXComm: " << errormsg(error) << endl;
434                 return false;
435         }
436
437         switch (GetLastError()) {
438         case ERROR_IO_PENDING:
439                 // The overlapped connection is in progress.
440                 pipe_[index].pending_io = true;
441                 break;
442
443         case ERROR_PIPE_CONNECTED:
444                 // Client is already connected, so signal an event.
445                 if (SetEvent(pipe_[index].overlap.hEvent))
446                         break;
447                 // fall through
448         default:
449                 // Anything else is an error.
450                 DWORD const error = GetLastError();
451                 lyxerr << "LyXComm: An error occurred while connecting pipe "
452                        << external_path(pipeName(index))
453                        << "\nLyXComm: " << errormsg(error) << endl;
454                 return false;
455         }
456
457         return true;
458 }
459
460
461 bool LyXComm::resetPipe(DWORD index, bool close_handle)
462 {
463         // This method is called when an error occurs or when a client
464         // closes the connection. We first disconnect the pipe instance,
465         // then reconnect it, ready to wait for another client.
466
467         if (!DisconnectNamedPipe(pipe_[index].handle)) {
468                 DWORD const error = GetLastError();
469                 lyxerr << "LyXComm: Could not disconnect pipe "
470                        << external_path(pipeName(index))
471                        << "\nLyXComm: " << errormsg(error) << endl;
472                 // What to do now? Let's try whether re-creating the pipe helps.
473                 close_handle = true;
474         }
475
476         bool const is_outpipe = index >= MAX_CLIENTS;
477
478         if (close_handle) {
479                 DWORD const open_mode = is_outpipe ? PIPE_ACCESS_OUTBOUND
480                                                    : PIPE_ACCESS_INBOUND;
481                 string const name = external_path(pipeName(index));
482
483                 CloseHandle(pipe_[index].handle);
484
485                 pipe_[index].iobuf.erase();
486                 pipe_[index].handle = CreateNamedPipe(name.c_str(),
487                                 open_mode | FILE_FLAG_OVERLAPPED, PIPE_WAIT,
488                                 MAX_CLIENTS, PIPE_BUFSIZE, PIPE_BUFSIZE,
489                                 PIPE_TIMEOUT, NULL);
490
491                 if (pipe_[index].handle == INVALID_HANDLE_VALUE) {
492                         DWORD const error = GetLastError();
493                         lyxerr << "LyXComm: Could not reset pipe " << name
494                                << "\nLyXComm: " << errormsg(error) << endl;
495                         return false;
496                 }
497         }
498
499         if (!startPipe(index))
500                 return false;
501         pipe_[index].state = pipe_[index].pending_io ?
502                         CONNECTING_STATE : (is_outpipe ? WRITING_STATE
503                                                        : READING_STATE);
504         return true;
505 }
506
507
508 void LyXComm::openConnection()
509 {
510         LYXERR(Debug::LYXSERVER, "LyXComm: Opening connection");
511
512         // If we are up, that's an error
513         if (ready_) {
514                 LYXERR(Debug::LYXSERVER, "LyXComm: Already connected");
515                 return;
516         }
517
518         if (pipename_.empty()) {
519                 LYXERR(Debug::LYXSERVER, "LyXComm: server is disabled, nothing to do");
520                 return;
521         }
522
523         // Check whether the pipe name is being used by some other instance.
524         if (!stopserver_ && WaitNamedPipe(inPipeName().c_str(), 0)) {
525                 // Tell the running instance to load the files
526                 if (run_mode == USE_REMOTE && loadFilesInOtherInstance()) {
527                         deferred_loading_ = true;
528                         pipename_.erase();
529                         return;
530                 }
531                 lyxerr << "LyXComm: Pipe " << external_path(inPipeName())
532                        << " already exists.\nMaybe another instance of LyX"
533                           " is using it." << endl;
534                 pipename_.erase();
535                 return;
536         }
537
538         // Mutex with no initial owner for synchronized access to outbuf_
539         outbuf_mutex_ = CreateMutex(NULL, FALSE, NULL);
540         if (!outbuf_mutex_) {
541                 DWORD const error = GetLastError();
542                 lyxerr << "LyXComm: Could not create output buffer mutex"
543                        << "\nLyXComm: " << errormsg(error) << endl;
544                 pipename_.erase();
545                 return;
546         }
547
548         // Manual-reset event, initial state = not signaled
549         stopserver_ = CreateEvent(NULL, TRUE, FALSE, NULL);
550         if (!stopserver_) {
551                 DWORD const error = GetLastError();
552                 lyxerr << "LyXComm: Could not create stop server event"
553                        << "\nLyXComm: " << errormsg(error) << endl;
554                 pipename_.erase();
555                 CloseHandle(outbuf_mutex_);
556                 return;
557         }
558
559         server_thread_ = CreateThread(NULL, 0, pipeServerWrapper,
560                                      static_cast<void *>(this), 0, NULL);
561         if (!server_thread_) {
562                 DWORD const error = GetLastError();
563                 lyxerr << "LyXComm: Could not create pipe server thread"
564                        << "\nLyXComm: " << errormsg(error) << endl;
565                 pipename_.erase();
566                 CloseHandle(stopserver_);
567                 CloseHandle(outbuf_mutex_);
568                 return;
569         }
570 }
571
572
573 /// Close pipes
574 void LyXComm::closeConnection()
575 {
576         LYXERR(Debug::LYXSERVER, "LyXComm: Closing connection");
577
578         if (pipename_.empty()) {
579                 LYXERR(Debug::LYXSERVER, "LyXComm: server is disabled, nothing to do");
580                 return;
581         }
582
583         if (!ready_) {
584                 LYXERR(Debug::LYXSERVER, "LyXComm: Already disconnected");
585                 return;
586         }
587
588         SetEvent(stopserver_);
589         // Wait for the pipe server to finish
590         WaitForSingleObject(server_thread_, INFINITE);
591         CloseHandle(server_thread_);
592         ResetEvent(stopserver_);
593         CloseHandle(stopserver_);
594         CloseHandle(outbuf_mutex_);
595 }
596
597
598 void LyXComm::emergencyCleanup()
599 {
600         if (ready_) {
601                 SetEvent(stopserver_);
602                 // Forcibly terminate the pipe server thread if it does
603                 // not finish quickly.
604                 if (WaitForSingleObject(server_thread_, 200) != WAIT_OBJECT_0) {
605                         TerminateThread(server_thread_, 0);
606                         ready_ = false;
607                         closeHandles();
608                 }
609                 CloseHandle(server_thread_);
610                 ResetEvent(stopserver_);
611                 CloseHandle(stopserver_);
612                 CloseHandle(outbuf_mutex_);
613         }
614 }
615
616
617 void LyXComm::read_ready(DWORD inpipe)
618 {
619         // Turn the pipe buffer into a C string
620         DWORD const nbytes = pipe_[inpipe].nbytes;
621         pipe_[inpipe].readbuf[nbytes] = '\0';
622
623         pipe_[inpipe].iobuf += rtrim(pipe_[inpipe].readbuf, "\r");
624
625         // Commit any commands read
626         while (pipe_[inpipe].iobuf.find('\n') != string::npos) {
627                 // split() grabs the entire string if
628                 // the delim /wasn't/ found. ?:-P
629                 string cmd;
630                 pipe_[inpipe].iobuf = split(pipe_[inpipe].iobuf, cmd, '\n');
631                 cmd = rtrim(cmd, "\r");
632                 LYXERR(Debug::LYXSERVER, "LyXComm: nbytes:" << nbytes
633                         << ", iobuf:" << pipe_[inpipe].iobuf
634                         << ", cmd:" << cmd);
635                 if (!cmd.empty())
636                         clientcb_(client_, cmd);
637                         //\n or not \n?
638         }
639         // Signal that we are done.
640         pipe_[inpipe].nbytes = 0;
641 }
642
643
644 void LyXComm::send(string const & msg)
645 {
646         if (msg.empty()) {
647                 lyxerr << "LyXComm: Request to send empty string. Ignoring."
648                        << endl;
649                 return;
650         }
651
652         LYXERR(Debug::LYXSERVER, "LyXComm: Sending '" << msg << '\'');
653
654         if (pipename_.empty())
655                 return;
656
657         if (!ready_) {
658                 lyxerr << "LyXComm: Pipes are closed. Could not send "
659                        << msg << endl;
660                 return;
661         }
662
663         // Request ownership of the outbuf_mutex_
664         DWORD result = WaitForSingleObject(outbuf_mutex_, PIPE_TIMEOUT);
665
666         if (result == WAIT_OBJECT_0) {
667                 // If a client doesn't care to read a reply (JabRef is one
668                 // such client), the output buffer could grow without limit.
669                 // So, we empty it when its size is larger than PIPE_BUFSIZE.
670                 if (outbuf_.size() > PIPE_BUFSIZE)
671                         outbuf_.erase();
672                 outbuf_ += msg;
673                 ReleaseMutex(outbuf_mutex_);
674         } else {
675                 // Something is fishy, better resetting the connection.
676                 DWORD const error = GetLastError();
677                 lyxerr << "LyXComm: Error sending message: " << msg
678                        << "\nLyXComm: " << errormsg(error)
679                        << "\nLyXComm: Resetting connection" << endl;
680                 ReleaseMutex(outbuf_mutex_);
681                 closeConnection();
682                 openConnection();
683         }
684 }
685
686
687 string const LyXComm::pipeName(DWORD index) const
688 {
689         return index < MAX_CLIENTS ? inPipeName() : outPipeName();
690 }
691
692
693 #elif !defined (HAVE_MKFIFO)
694 // We provide a stub class that disables the lyxserver.
695
696 LyXComm::LyXComm(string const &, Server *, ClientCallbackfct)
697 {}
698
699
700 void LyXComm::openConnection()
701 {}
702
703
704 void LyXComm::closeConnection()
705 {}
706
707
708 int LyXComm::startPipe(string const & filename, bool write)
709 {
710         return -1;
711 }
712
713
714 void LyXComm::endPipe(int & fd, string const & filename, bool write)
715 {}
716
717
718 void LyXComm::emergencyCleanup()
719 {}
720
721
722 void LyXComm::read_ready()
723 {}
724
725
726 void LyXComm::send(string const & msg)
727 {}
728
729
730 #else // defined (HAVE_MKFIFO)
731
732 LyXComm::LyXComm(string const & pip, Server * cli, ClientCallbackfct ccb)
733         : infd_(-1), outfd_(-1),
734           ready_(false), pipename_(pip), client_(cli), clientcb_(ccb),
735           deferred_loading_(false)
736 {
737         openConnection();
738 }
739
740
741 void LyXComm::openConnection()
742 {
743         LYXERR(Debug::LYXSERVER, "LyXComm: Opening connection");
744
745         // If we are up, that's an error
746         if (ready_) {
747                 lyxerr << "LyXComm: Already connected" << endl;
748                 return;
749         }
750         // We assume that we don't make it
751         ready_ = false;
752
753         if (pipename_.empty()) {
754                 LYXERR(Debug::LYXSERVER, "LyXComm: server is disabled, nothing to do");
755                 return;
756         }
757
758         infd_ = startPipe(inPipeName(), false);
759         if (infd_ == -1)
760                 return;
761
762         outfd_ = startPipe(outPipeName(), true);
763         if (outfd_ == -1) {
764                 endPipe(infd_, inPipeName(), false);
765                 return;
766         }
767
768         if (fcntl(outfd_, F_SETFL, O_NONBLOCK) < 0) {
769                 lyxerr << "LyXComm: Could not set flags on pipe " << outPipeName()
770                        << '\n' << strerror(errno) << endl;
771                 return;
772         }
773
774         // We made it!
775         ready_ = true;
776         LYXERR(Debug::LYXSERVER, "LyXComm: Connection established");
777 }
778
779
780 /// Close pipes
781 void LyXComm::closeConnection()
782 {
783         LYXERR(Debug::LYXSERVER, "LyXComm: Closing connection");
784
785         if (pipename_.empty()) {
786                 LYXERR(Debug::LYXSERVER, "LyXComm: server is disabled, nothing to do");
787                 return;
788         }
789
790         if (!ready_) {
791                 LYXERR0("LyXComm: Already disconnected");
792                 return;
793         }
794
795         endPipe(infd_, inPipeName(), false);
796         endPipe(outfd_, outPipeName(), true);
797
798         ready_ = false;
799 }
800
801
802 int LyXComm::startPipe(string const & file, bool write)
803 {
804         static bool stalepipe = false;
805         FileName const filename(file);
806         if (filename.exists()) {
807                 if (!write) {
808                         // Let's see whether we have a stale pipe.
809                         int fd = ::open(filename.toFilesystemEncoding().c_str(),
810                                         O_WRONLY | O_NONBLOCK);
811                         if (fd >= 0) {
812                                 // Another LyX instance is using it.
813                                 ::close(fd);
814                                 // Tell the running instance to load the files
815                                 if (run_mode == USE_REMOTE && loadFilesInOtherInstance()) {
816                                         deferred_loading_ = true;
817                                         pipename_.erase();
818                                         return -1;
819                                 }
820                         } else if (errno == ENXIO) {
821                                 // No process is reading from the other end.
822                                 stalepipe = true;
823                                 LYXERR(Debug::LYXSERVER,
824                                         "LyXComm: trying to remove "
825                                         << filename);
826                                 filename.removeFile();
827                         }
828                 } else if (stalepipe) {
829                         LYXERR(Debug::LYXSERVER, "LyXComm: trying to remove "
830                                 << filename);
831                         filename.removeFile();
832                         stalepipe = false;
833                 }
834                 if (filename.exists()) {
835                         lyxerr << "LyXComm: Pipe " << filename
836                                << " already exists.\nIf no other LyX program"
837                                   " is active, please delete the pipe by hand"
838                                   " and try again."
839                                << endl;
840                         pipename_.erase();
841                         return -1;
842                 }
843         }
844
845         if (::mkfifo(filename.toFilesystemEncoding().c_str(), 0600) < 0) {
846                 lyxerr << "LyXComm: Could not create pipe " << filename << '\n'
847                        << strerror(errno) << endl;
848                 return -1;
849         }
850         int const fd = ::open(filename.toFilesystemEncoding().c_str(),
851                               write ? (O_RDWR) : (O_RDONLY|O_NONBLOCK));
852
853         if (fd < 0) {
854                 lyxerr << "LyXComm: Could not open pipe " << filename << '\n'
855                        << strerror(errno) << endl;
856                 filename.removeFile();
857                 return -1;
858         }
859
860         if (!write) {
861                 // Make sure not to call read_ready after destruction.
862                 weak_ptr<void> tracker = tracker_.p();
863                 theApp()->registerSocketCallback(fd, [=](){
864                                 if (!tracker.expired())
865                                         read_ready();
866                         });
867         }
868
869         return fd;
870 }
871
872
873 void LyXComm::endPipe(int & fd, string const & filename, bool write)
874 {
875         if (fd < 0)
876                 return;
877
878         if (!write)
879                 theApp()->unregisterSocketCallback(fd);
880
881         if (::close(fd) < 0) {
882                 lyxerr << "LyXComm: Could not close pipe " << filename
883                        << '\n' << strerror(errno) << endl;
884         }
885
886         if (!FileName(filename).removeFile()) {
887                 lyxerr << "LyXComm: Could not remove pipe " << filename
888                        << '\n' << strerror(errno) << endl;
889         }
890
891         fd = -1;
892 }
893
894
895 void LyXComm::emergencyCleanup()
896 {
897         if (!pipename_.empty()) {
898                 endPipe(infd_, inPipeName(), false);
899                 endPipe(outfd_, outPipeName(), true);
900         }
901 }
902
903
904 // Receives messages and sends then to client
905 void LyXComm::read_ready()
906 {
907         // FIXME: make read_buffer_ a class-member for multiple sessions
908         static string read_buffer_;
909         read_buffer_.erase();
910
911         int const charbuf_size = 100;
912         char charbuf[charbuf_size];
913
914         // As O_NONBLOCK is set, until no data is available for reading,
915         // read() doesn't block but returns -1 and set errno to EAGAIN.
916         // After a client that opened the pipe for writing, closes it
917         // (and no other client is using the pipe), read() would always
918         // return 0 and thus the connection has to be reset.
919
920         errno = 0;
921         int status;
922         // the single = is intended here.
923         while ((status = ::read(infd_, charbuf, charbuf_size - 1))) {
924                 if (status > 0) {
925                         charbuf[status] = '\0'; // turn it into a c string
926                         read_buffer_ += rtrim(charbuf, "\r");
927                         // commit any commands read
928                         while (read_buffer_.find('\n') != string::npos) {
929                                 // split() grabs the entire string if
930                                 // the delim /wasn't/ found. ?:-P
931                                 string cmd;
932                                 read_buffer_= split(read_buffer_, cmd,'\n');
933                                 LYXERR(Debug::LYXSERVER, "LyXComm: status:" << status
934                                         << ", read_buffer_:" << read_buffer_
935                                         << ", cmd:" << cmd);
936                                 if (!cmd.empty())
937                                         clientcb_(client_, cmd);
938                                         //\n or not \n?
939                         }
940                 } else {
941                         if (errno == EAGAIN) {
942                                 // Nothing to read, continue
943                                 errno = 0;
944                                 return;
945                         }
946                         // An error occurred, better bailing out
947                         LYXERR0("LyXComm: " << strerror(errno));
948                         if (!read_buffer_.empty()) {
949                                 LYXERR0("LyXComm: truncated command: " << read_buffer_);
950                                 read_buffer_.erase();
951                         }
952                         break; // reset connection
953                 }
954         }
955
956         // The connection gets reset when read() returns 0 (meaning that the
957         // last client closed the pipe) or an error occurred, in which case
958         // read() returns -1 and errno != EAGAIN.
959         closeConnection();
960         openConnection();
961         errno = 0;
962 }
963
964
965 void LyXComm::send(string const & msg)
966 {
967         if (msg.empty()) {
968                 LYXERR0("LyXComm: Request to send empty string. Ignoring.");
969                 return;
970         }
971
972         LYXERR(Debug::LYXSERVER, "LyXComm: Sending '" << msg << '\'');
973
974         if (pipename_.empty())
975                 return;
976
977         if (!ready_) {
978                 LYXERR0("LyXComm: Pipes are closed. Could not send " << msg);
979         } else if (::write(outfd_, msg.c_str(), msg.length()) < 0) {
980                 lyxerr << "LyXComm: Error sending message: " << msg
981                        << '\n' << strerror(errno)
982                        << "\nLyXComm: Resetting connection" << endl;
983                 closeConnection();
984                 openConnection();
985         }
986 }
987
988 #endif // defined (HAVE_MKFIFO)
989
990 namespace {
991
992 struct Sleep : QThread
993 {
994         static void millisec(unsigned long ms)
995         {
996                 QThread::usleep(ms * 1000);
997         }
998 };
999
1000 } // namespace
1001
1002
1003 bool LyXComm::loadFilesInOtherInstance()
1004 {
1005         if (theFilesToLoad().size() == 0)
1006                 return true;
1007
1008         int pipefd;
1009         int loaded_files = 0;
1010         FileName const pipe(inPipeName());
1011         vector<string>::iterator it = theFilesToLoad().begin();
1012         while (it != theFilesToLoad().end()) {
1013                 FileName fname = fileSearch(string(), os::internal_path(*it),
1014                                                 "lyx", may_not_exist);
1015                 if (fname.empty()) {
1016                         ++it;
1017                         continue;
1018                 }
1019                 // Wait a while to allow time for the other
1020                 // instance to reset the connection
1021                 Sleep::millisec(200);
1022                 pipefd = ::open(pipe.toFilesystemEncoding().c_str(), O_WRONLY);
1023                 if (pipefd < 0)
1024                         break;
1025                 string const cmd = "LYXCMD:pipe:file-open:" +
1026                                         fname.absFileName() + '\n';
1027                 if (::write(pipefd, cmd.c_str(), cmd.length()) < 0)
1028                         LYXERR0("Cannot write to pipe!");
1029                 ::close(pipefd);
1030                 ++loaded_files;
1031                 it = theFilesToLoad().erase(it);
1032         }
1033         return loaded_files > 0;
1034 }
1035
1036
1037 string const LyXComm::inPipeName() const
1038 {
1039         return pipename_ + ".in";
1040 }
1041
1042
1043 string const LyXComm::outPipeName() const
1044 {
1045         return pipename_ + ".out";
1046 }
1047
1048
1049 /////////////////////////////////////////////////////////////////////
1050 //
1051 // Server
1052 //
1053 /////////////////////////////////////////////////////////////////////
1054
1055 void ServerCallback(Server * server, string const & msg)
1056 {
1057         server->callback(msg);
1058 }
1059
1060 Server::Server(string const & pipes)
1061         : numclients_(0), pipes_(pipes, this, &ServerCallback)
1062 {}
1063
1064
1065 Server::~Server()
1066 {
1067         // say goodbye to clients so they stop sending messages
1068         // send as many bye messages as there are clients,
1069         // each with client's name.
1070         string message;
1071         for (int i = 0; i != numclients_; ++i) {
1072                 message = "LYXSRV:" + clients_[i] + ":bye\n";
1073                 pipes_.send(message);
1074         }
1075 }
1076
1077
1078 int compare(char const * a, char const * b, unsigned int len)
1079 {
1080         return strncmp(a, b, len);
1081 }
1082
1083
1084 // Handle data gotten from communication, called by LyXComm
1085 void Server::callback(string const & msg)
1086 {
1087         LYXERR(Debug::LYXSERVER, "Server: Received: '" << msg << '\'');
1088
1089         char const * p = msg.c_str();
1090
1091         // --- parse the string --------------------------------------------
1092         //
1093         //  Format: LYXCMD:<client>:<func>:<argstring>\n
1094         //
1095         bool server_only = false;
1096         while (*p) {
1097                 // --- 1. check 'header' ---
1098
1099                 if (compare(p, "LYXSRV:", 7) == 0) {
1100                         server_only = true;
1101                 } else if (0 != compare(p, "LYXCMD:", 7)) {
1102                         lyxerr << "Server: Unknown request \""
1103                                << p << '"' << endl;
1104                         return;
1105                 }
1106                 p += 7;
1107
1108                 // --- 2. for the moment ignore the client name ---
1109                 string client;
1110                 while (*p && *p != ':')
1111                         client += char(*p++);
1112                 if (*p == ':')
1113                         ++p;
1114                 if (!*p)
1115                         return;
1116
1117                 // --- 3. get function name ---
1118                 string cmd;
1119                 while (*p && *p != ':')
1120                         cmd += char(*p++);
1121
1122                 // --- 4. parse the argument ---
1123                 string arg;
1124                 if (!server_only && *p == ':' && *(++p)) {
1125                         while (*p && *p != '\n')
1126                                 arg += char(*p++);
1127                         if (*p) ++p;
1128                 }
1129
1130                 LYXERR(Debug::LYXSERVER, "Server: Client: '" << client
1131                         << "' Command: '" << cmd << "' Argument: '" << arg << '\'');
1132
1133                 // --- lookup and exec the command ------------------
1134
1135                 if (server_only) {
1136                         string buf;
1137                         // return the greeting to inform the client that
1138                         // we are listening.
1139                         if (cmd == "hello") {
1140                                 // One more client
1141                                 if (numclients_ == MAX_CLIENTS) { //paranoid check
1142                                         LYXERR(Debug::LYXSERVER, "Server: too many clients...");
1143                                         return;
1144                                 }
1145                                 int i = 0;
1146                                 while (!clients_[i].empty() && i < numclients_)
1147                                         ++i;
1148                                 clients_[i] = client;
1149                                 ++numclients_;
1150                                 buf = "LYXSRV:" + client + ":hello\n";
1151                                 LYXERR(Debug::LYXSERVER, "Server: Greeting " << client);
1152                                 pipes_.send(buf);
1153                         } else if (cmd == "bye") {
1154                                 // If clients_ == 0 maybe we should reset the pipes
1155                                 // to prevent fake callbacks
1156                                 int i = 0; //look if client is registered
1157                                 for (; i < numclients_; ++i) {
1158                                         if (clients_[i] == client)
1159                                                 break;
1160                                 }
1161                                 if (i < numclients_) {
1162                                         --numclients_;
1163                                         clients_[i].erase();
1164                                         LYXERR(Debug::LYXSERVER, "Server: Client "
1165                                                 << client << " said goodbye");
1166                                 } else {
1167                                         LYXERR(Debug::LYXSERVER,
1168                                                 "Server: ignoring bye message from unregistered client" << client);
1169                                 }
1170                         } else {
1171                                 LYXERR0("Server: Undefined server command " << cmd << '.');
1172                         }
1173                         return;
1174                 }
1175
1176                 if (!cmd.empty()) {
1177                         // which lyxfunc should we let it connect to?
1178                         // The correct solution would be to have a
1179                         // specialized (non-gui) BufferView. But how do
1180                         // we do it now? Probably we should just let it
1181                         // connect to the lyxfunc in the single GuiView we
1182                         // support currently. (Lgb)
1183
1184                         FuncRequest fr(lyxaction.lookupFunc(cmd), from_utf8(arg));
1185                         fr.setOrigin(FuncRequest::LYXSERVER);
1186                         DispatchResult dr;
1187                         theApp()->dispatch(fr, dr);
1188                         string const rval = to_utf8(dr.message());
1189
1190                         // all commands produce an INFO or ERROR message
1191                         // in the output pipe, even if they do not return
1192                         // anything. See chapter 4 of Customization doc.
1193                         string buf;
1194                         if (dr.error())
1195                                 buf = "ERROR:";
1196                         else
1197                                 buf = "INFO:";
1198                         buf += client + ':' + cmd + ':' +  rval + '\n';
1199                         pipes_.send(buf);
1200
1201                         // !!! we don't do any error checking -
1202                         //  if the client won't listen, the
1203                         //  message is lost and others too
1204                         //  maybe; so the client should empty
1205                         //  the outpipe before issuing a request.
1206
1207                         // not found
1208                 }
1209         }  // while *p
1210 }
1211
1212
1213 // Send a notify message to a client, called by WorkAreaKeyPress
1214 void Server::notifyClient(string const & s)
1215 {
1216         pipes_.send("NOTIFY:" + s + "\n");
1217 }
1218
1219
1220 } // namespace lyx
1221
1222 #ifdef _WIN32
1223 #include "moc_Server.cpp"
1224 #endif