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