]> git.lyx.org Git - features.git/blob - src/Server.cpp
Interrupt the wait if the stopserver event is triggered.
[features.git] / src / Server.cpp
1 /**
2  * \file Server.cpp
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Lars Gullik Bjønnes
7  * \author Jean-Marc Lasgouttes
8  * \author Angus Leeming
9  * \author John Levon
10  * \author Enrico Forestieri
11  *
12  * Full author contact details are available in file CREDITS.
13  */
14
15 /**
16   Docu   : To use the lyxserver define the name of the pipe in your
17            lyxrc:
18            \serverpipe "/home/myhome/.lyxpipe"
19            Then use .lyxpipe.in and .lyxpipe.out to communicate to LyX.
20            Each message consists of a single line in ASCII. Input lines
21            (client -> LyX) have the following format:
22             "LYXCMD:<clientname>:<functionname>:<argument>"
23            Answers from LyX look like this:
24            "INFO:<clientname>:<functionname>:<data>"
25  [asierra970531] Or like this in case of error:
26            "ERROR:<clientname>:<functionname>:<error message>"
27            where <clientname> and <functionname> are just echoed.
28            If LyX notifies about a user defined extension key-sequence,
29            the line looks like this:
30            "NOTIFY:<key-sequence>"
31  [asierra970531] New server-only messages to implement a simple protocol
32            "LYXSRV:<clientname>:<protocol message>"
33            where <protocol message> can be "hello" or "bye". If hello is
34            received LyX will inform the client that it's listening its
35            messages, and 'bye' will inform that lyx is closing.
36
37            See development/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                 if (!checkStopServer())
668                         openConnection();
669         }
670 }
671
672
673 string const LyXComm::pipeName(DWORD index) const
674 {
675         return index < MAX_CLIENTS ? inPipeName() : outPipeName();
676 }
677
678
679 #elif !defined (HAVE_MKFIFO)
680 // We provide a stub class that disables the lyxserver.
681
682 LyXComm::LyXComm(string const &, Server *, ClientCallbackfct)
683 {}
684
685 void LyXComm::openConnection()
686 {}
687
688
689 void LyXComm::closeConnection()
690 {}
691
692
693 int LyXComm::startPipe(string const & filename, bool write)
694 {
695         return -1;
696 }
697
698
699 void LyXComm::endPipe(int & fd, string const & filename, bool write)
700 {}
701
702
703 void LyXComm::emergencyCleanup()
704 {}
705
706 void LyXComm::read_ready()
707 {}
708
709
710 void LyXComm::send(string const & msg)
711 {}
712
713
714 #else // defined (HAVE_MKFIFO)
715
716
717 LyXComm::LyXComm(string const & pip, Server * cli, ClientCallbackfct ccb)
718         : pipename_(pip), client_(cli), clientcb_(ccb)
719 {
720         ready_ = false;
721         openConnection();
722 }
723
724
725 void LyXComm::openConnection()
726 {
727         LYXERR(Debug::LYXSERVER, "LyXComm: Opening connection");
728
729         // If we are up, that's an error
730         if (ready_) {
731                 lyxerr << "LyXComm: Already connected" << endl;
732                 return;
733         }
734         // We assume that we don't make it
735         ready_ = false;
736
737         if (pipename_.empty()) {
738                 LYXERR(Debug::LYXSERVER, "LyXComm: server is disabled, nothing to do");
739                 return;
740         }
741
742         infd_ = startPipe(inPipeName(), false);
743         if (infd_ == -1)
744                 return;
745
746         outfd_ = startPipe(outPipeName(), true);
747         if (outfd_ == -1) {
748                 endPipe(infd_, inPipeName(), false);
749                 return;
750         }
751
752         if (fcntl(outfd_, F_SETFL, O_NONBLOCK) < 0) {
753                 lyxerr << "LyXComm: Could not set flags on pipe " << outPipeName()
754                        << '\n' << strerror(errno) << endl;
755                 return;
756         }
757
758         // We made it!
759         ready_ = true;
760         LYXERR(Debug::LYXSERVER, "LyXComm: Connection established");
761 }
762
763
764 /// Close pipes
765 void LyXComm::closeConnection()
766 {
767         LYXERR(Debug::LYXSERVER, "LyXComm: Closing connection");
768
769         if (pipename_.empty()) {
770                 LYXERR(Debug::LYXSERVER, "LyXComm: server is disabled, nothing to do");
771                 return;
772         }
773
774         if (!ready_) {
775                 LYXERR0("LyXComm: Already disconnected");
776                 return;
777         }
778
779         endPipe(infd_, inPipeName(), false);
780         endPipe(outfd_, outPipeName(), true);
781
782         ready_ = false;
783 }
784
785
786 int LyXComm::startPipe(string const & file, bool write)
787 {
788         static bool stalepipe = false;
789         FileName const filename(file);
790         if (filename.exists()) {
791                 if (!write) {
792                         // Let's see whether we have a stale pipe.
793                         int fd = ::open(filename.toFilesystemEncoding().c_str(),
794                                         O_WRONLY | O_NONBLOCK);
795                         if (fd >= 0) {
796                                 // Another LyX instance is using it.
797                                 ::close(fd);
798                         } else if (errno == ENXIO) {
799                                 // No process is reading from the other end.
800                                 stalepipe = true;
801                                 LYXERR(Debug::LYXSERVER,
802                                         "LyXComm: trying to remove "
803                                         << filename);
804                                 filename.removeFile();
805                         }
806                 } else if (stalepipe) {
807                         LYXERR(Debug::LYXSERVER, "LyXComm: trying to remove "
808                                 << filename);
809                         filename.removeFile();
810                         stalepipe = false;
811                 }
812                 if (filename.exists()) {
813                         lyxerr << "LyXComm: Pipe " << filename
814                                << " already exists.\nIf no other LyX program"
815                                   " is active, please delete the pipe by hand"
816                                   " and try again."
817                                << endl;
818                         pipename_.erase();
819                         return -1;
820                 }
821         }
822
823         if (::mkfifo(filename.toFilesystemEncoding().c_str(), 0600) < 0) {
824                 lyxerr << "LyXComm: Could not create pipe " << filename << '\n'
825                        << strerror(errno) << endl;
826                 return -1;
827         }
828         int const fd = ::open(filename.toFilesystemEncoding().c_str(),
829                               write ? (O_RDWR) : (O_RDONLY|O_NONBLOCK));
830
831         if (fd < 0) {
832                 lyxerr << "LyXComm: Could not open pipe " << filename << '\n'
833                        << strerror(errno) << endl;
834                 filename.removeFile();
835                 return -1;
836         }
837
838         if (!write) {
839                 theApp()->registerSocketCallback(fd,
840                         boost::bind(&LyXComm::read_ready, this));
841         }
842
843         return fd;
844 }
845
846
847 void LyXComm::endPipe(int & fd, string const & filename, bool write)
848 {
849         if (fd < 0)
850                 return;
851
852         if (!write)
853                 theApp()->unregisterSocketCallback(fd);
854
855         if (::close(fd) < 0) {
856                 lyxerr << "LyXComm: Could not close pipe " << filename
857                        << '\n' << strerror(errno) << endl;
858         }
859
860         if (FileName(filename).removeFile() < 0) {
861                 lyxerr << "LyXComm: Could not remove pipe " << filename
862                        << '\n' << strerror(errno) << endl;
863         }
864
865         fd = -1;
866 }
867
868
869 void LyXComm::emergencyCleanup()
870 {
871         if (!pipename_.empty()) {
872                 endPipe(infd_, inPipeName(), false);
873                 endPipe(outfd_, outPipeName(), true);
874         }
875 }
876
877
878 // Receives messages and sends then to client
879 void LyXComm::read_ready()
880 {
881         // FIXME: make read_buffer_ a class-member for multiple sessions
882         static string read_buffer_;
883         read_buffer_.erase();
884
885         int const charbuf_size = 100;
886         char charbuf[charbuf_size];
887
888         // As O_NONBLOCK is set, until no data is available for reading,
889         // read() doesn't block but returns -1 and set errno to EAGAIN.
890         // After a client that opened the pipe for writing, closes it
891         // (and no other client is using the pipe), read() would always
892         // return 0 and thus the connection has to be reset.
893
894         errno = 0;
895         int status;
896         // the single = is intended here.
897         while ((status = ::read(infd_, charbuf, charbuf_size - 1))) {
898
899                 if (status > 0) {
900                         charbuf[status] = '\0'; // turn it into a c string
901                         read_buffer_ += rtrim(charbuf, "\r");
902                         // commit any commands read
903                         while (read_buffer_.find('\n') != string::npos) {
904                                 // split() grabs the entire string if
905                                 // the delim /wasn't/ found. ?:-P
906                                 string cmd;
907                                 read_buffer_= split(read_buffer_, cmd,'\n');
908                                 LYXERR(Debug::LYXSERVER, "LyXComm: status:" << status
909                                         << ", read_buffer_:" << read_buffer_
910                                         << ", cmd:" << cmd);
911                                 if (!cmd.empty())
912                                         clientcb_(client_, cmd);
913                                         //\n or not \n?
914                         }
915                 } else {
916                         if (errno == EAGAIN) {
917                                 // Nothing to read, continue
918                                 errno = 0;
919                                 return;
920                         }
921                         // An error occurred, better bailing out
922                         LYXERR0("LyXComm: " << strerror(errno));
923                         if (!read_buffer_.empty()) {
924                                 LYXERR0("LyXComm: truncated command: " << read_buffer_);
925                                 read_buffer_.erase();
926                         }
927                         break; // reset connection
928                 }
929         }
930
931         // The connection gets reset when read() returns 0 (meaning that the
932         // last client closed the pipe) or an error occurred, in which case
933         // read() returns -1 and errno != EAGAIN.
934         closeConnection();
935         openConnection();
936         errno = 0;
937 }
938
939
940 void LyXComm::send(string const & msg)
941 {
942         if (msg.empty()) {
943                 LYXERR0("LyXComm: Request to send empty string. Ignoring.");
944                 return;
945         }
946
947         LYXERR(Debug::LYXSERVER, "LyXComm: Sending '" << msg << '\'');
948
949         if (pipename_.empty()) return;
950
951         if (!ready_) {
952                 LYXERR0("LyXComm: Pipes are closed. Could not send " << msg);
953         } else if (::write(outfd_, msg.c_str(), msg.length()) < 0) {
954                 lyxerr << "LyXComm: Error sending message: " << msg
955                        << '\n' << strerror(errno)
956                        << "\nLyXComm: Resetting connection" << endl;
957                 closeConnection();
958                 openConnection();
959         }
960 }
961
962 #endif // defined (HAVE_MKFIFO)
963
964
965 string const LyXComm::inPipeName() const
966 {
967         return pipename_ + ".in";
968 }
969
970
971 string const LyXComm::outPipeName() const
972 {
973         return pipename_ + ".out";
974 }
975
976
977 /////////////////////////////////////////////////////////////////////
978 //
979 // Server
980 //
981 /////////////////////////////////////////////////////////////////////
982
983 void ServerCallback(Server * server, string const & msg)
984 {
985         server->callback(msg);
986 }
987
988 Server::Server(LyXFunc * f, string const & pipes)
989         : numclients_(0), func_(f), pipes_(pipes, this, &ServerCallback)
990 {}
991
992
993 Server::~Server()
994 {
995         // say goodbye to clients so they stop sending messages
996         // send as many bye messages as there are clients,
997         // each with client's name.
998         string message;
999         for (int i = 0; i != numclients_; ++i) {
1000                 message = "LYXSRV:" + clients_[i] + ":bye\n";
1001                 pipes_.send(message);
1002         }
1003 }
1004
1005
1006 int compare(char const * a, char const * b, unsigned int len)
1007 {
1008         using namespace std;
1009         return strncmp(a, b, len);
1010 }
1011
1012
1013 // Handle data gotten from communication, called by LyXComm
1014 void Server::callback(string const & msg)
1015 {
1016         LYXERR(Debug::LYXSERVER, "Server: Received: '" << msg << '\'');
1017
1018         char const * p = msg.c_str();
1019
1020         // --- parse the string --------------------------------------------
1021         //
1022         //  Format: LYXCMD:<client>:<func>:<argstring>\n
1023         //
1024         bool server_only = false;
1025         while (*p) {
1026                 // --- 1. check 'header' ---
1027
1028                 if (compare(p, "LYXSRV:", 7) == 0) {
1029                         server_only = true;
1030                 } else if (0 != compare(p, "LYXCMD:", 7)) {
1031                         lyxerr << "Server: Unknown request \""
1032                                << p << '"' << endl;
1033                         return;
1034                 }
1035                 p += 7;
1036
1037                 // --- 2. for the moment ignore the client name ---
1038                 string client;
1039                 while (*p && *p != ':')
1040                         client += char(*p++);
1041                 if (*p == ':')
1042                         ++p;
1043                 if (!*p)
1044                         return;
1045
1046                 // --- 3. get function name ---
1047                 string cmd;
1048                 while (*p && *p != ':')
1049                         cmd += char(*p++);
1050
1051                 // --- 4. parse the argument ---
1052                 string arg;
1053                 if (!server_only && *p == ':' && *(++p)) {
1054                         while (*p && *p != '\n')
1055                                 arg += char(*p++);
1056                         if (*p) ++p;
1057                 }
1058
1059                 LYXERR(Debug::LYXSERVER, "Server: Client: '" << client
1060                         << "' Command: '" << cmd << "' Argument: '" << arg << '\'');
1061
1062                 // --- lookup and exec the command ------------------
1063
1064                 if (server_only) {
1065                         string buf;
1066                         // return the greeting to inform the client that
1067                         // we are listening.
1068                         if (cmd == "hello") {
1069                                 // One more client
1070                                 if (numclients_ == MAX_CLIENTS) { //paranoid check
1071                                         LYXERR(Debug::LYXSERVER, "Server: too many clients...");
1072                                         return;
1073                                 }
1074                                 int i = 0;
1075                                 while (!clients_[i].empty() && i < numclients_)
1076                                         ++i;
1077                                 clients_[i] = client;
1078                                 ++numclients_;
1079                                 buf = "LYXSRV:" + client + ":hello\n";
1080                                 LYXERR(Debug::LYXSERVER, "Server: Greeting " << client);
1081                                 pipes_.send(buf);
1082                         } else if (cmd == "bye") {
1083                                 // If clients_ == 0 maybe we should reset the pipes
1084                                 // to prevent fake callbacks
1085                                 int i = 0; //look if client is registered
1086                                 for (; i < numclients_; ++i) {
1087                                         if (clients_[i] == client)
1088                                                 break;
1089                                 }
1090                                 if (i < numclients_) {
1091                                         --numclients_;
1092                                         clients_[i].erase();
1093                                         LYXERR(Debug::LYXSERVER, "Server: Client "
1094                                                 << client << " said goodbye");
1095                                 } else {
1096                                         LYXERR(Debug::LYXSERVER,
1097                                                 "Server: ignoring bye messge from unregistered client" << client);
1098                                 }
1099                         } else {
1100                                 LYXERR0("Server: Undefined server command " << cmd << '.');
1101                         }
1102                         return;
1103                 }
1104
1105                 if (!cmd.empty()) {
1106                         // which lyxfunc should we let it connect to?
1107                         // The correct solution would be to have a
1108                         // specialized (non-gui) BufferView. But how do
1109                         // we do it now? Probably we should just let it
1110                         // connect to the lyxfunc in the single LyXView we
1111                         // support currently. (Lgb)
1112
1113                         func_->dispatch(FuncRequest(lyxaction.lookupFunc(cmd), arg));
1114                         string const rval = to_utf8(func_->getMessage());
1115
1116                         // all commands produce an INFO or ERROR message
1117                         // in the output pipe, even if they do not return
1118                         // anything. See chapter 4 of Customization doc.
1119                         string buf;
1120                         if (func_->errorStat())
1121                                 buf = "ERROR:";
1122                         else
1123                                 buf = "INFO:";
1124                         buf += client + ':' + cmd + ':' +  rval + '\n';
1125                         pipes_.send(buf);
1126
1127                         // !!! we don't do any error checking -
1128                         //  if the client won't listen, the
1129                         //  message is lost and others too
1130                         //  maybe; so the client should empty
1131                         //  the outpipe before issuing a request.
1132
1133                         // not found
1134                 }
1135         }  // while *p
1136 }
1137
1138
1139 // Send a notify message to a client, called by WorkAreaKeyPress
1140 void Server::notifyClient(string const & s)
1141 {
1142         pipes_.send("NOTIFY:" + s + "\n");
1143 }
1144
1145
1146 } // namespace lyx
1147
1148 #ifdef _WIN32
1149 #include "moc_Server.cpp"
1150 #endif