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