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