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