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