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