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