]> git.lyx.org Git - lyx.git/blob - src/Server.cpp
Quit notification from Qt is not needed anymore.
[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         emergencyCleanup();
506 }
507
508
509 void LyXComm::emergencyCleanup()
510 {
511         if (ready_) {
512                 SetEvent(stopserver_);
513                 // Wait for the pipe server to finish
514                 WaitForSingleObject(server_thread_, INFINITE);
515                 CloseHandle(server_thread_);
516                 ResetEvent(stopserver_);
517                 CloseHandle(stopserver_);
518         }
519 }
520
521
522 void LyXComm::read_ready(DWORD inpipe)
523 {
524         // Turn the pipe buffer into a C string
525         DWORD const nbytes = pipe_[inpipe].nbytes;
526         pipe_[inpipe].pipebuf[nbytes] = '\0';
527
528         readbuf_[inpipe] += rtrim(pipe_[inpipe].pipebuf, "\r");
529
530         // Commit any commands read
531         while (readbuf_[inpipe].find('\n') != string::npos) {
532                 // split() grabs the entire string if
533                 // the delim /wasn't/ found. ?:-P
534                 string cmd;
535                 readbuf_[inpipe] = split(readbuf_[inpipe], cmd, '\n');
536                 cmd = rtrim(cmd, "\r");
537                 LYXERR(Debug::LYXSERVER, "LyXComm: status:" << nbytes
538                         << ", readbuf_:" << readbuf_[inpipe]
539                         << ", cmd:" << cmd);
540                 if (!cmd.empty())
541                         clientcb_(client_, cmd);
542                         //\n or not \n?
543         }
544         // Signal that we are done.
545         pipe_[inpipe].nbytes = 0;
546 }
547
548
549 void LyXComm::send(string const & msg)
550 {
551         if (msg.empty()) {
552                 LYXERR0("LyXComm: Request to send empty string. Ignoring.");
553                 return;
554         }
555
556         LYXERR(Debug::LYXSERVER, "LyXComm: Sending '" << msg << '\'');
557
558         if (pipename_.empty())
559                 return;
560
561         if (!ready_) {
562                 LYXERR0("LyXComm: Pipes are closed. Could not send " << msg);
563                 return;
564         }
565
566         // Wait a couple of secs for completion of a previous write operation.
567         for (int count = 0; writebuf_.length() && count < 20; ++count)
568                 Sleep(100);
569
570         if (!writebuf_.length()) {
571                 writebuf_ = msg;
572                 // Tell the pipe server he has a job to do.
573                 SetEvent(pipe_[MAX_PIPES].overlap.hEvent);
574         } else {
575                 // Nope, output pipe is still busy. Most likely, a bad client
576                 // did not care to read the answer (JabRef is one such client).
577                 // Let's do a reset, otherwise the output pipe could remain
578                 // stalled if the pipe server failed to reset it.
579                 // This will remedy the output pipe stall, but the client will
580                 // get a broken pipe error.
581                 LYXERR0("LyXComm: Error sending message: " << msg
582                         << "\nLyXComm: Output pipe is stalled\n"
583                            "LyXComm: Resetting connection");
584                 closeConnection();
585                 if (!checkStopServer())
586                         openConnection();
587         }
588 }
589
590
591 string const LyXComm::pipeName(DWORD index) const
592 {
593         return index < MAX_PIPES ? inPipeName() : outPipeName();
594 }
595
596
597 #elif !defined (HAVE_MKFIFO)
598 // We provide a stub class that disables the lyxserver.
599
600 LyXComm::LyXComm(string const &, Server *, ClientCallbackfct)
601 {}
602
603 void LyXComm::openConnection()
604 {}
605
606
607 void LyXComm::closeConnection()
608 {}
609
610
611 int LyXComm::startPipe(string const & filename, bool write)
612 {
613         return -1;
614 }
615
616
617 void LyXComm::endPipe(int & fd, string const & filename, bool write)
618 {}
619
620
621 void LyXComm::emergencyCleanup()
622 {}
623
624 void LyXComm::read_ready()
625 {}
626
627
628 void LyXComm::send(string const & msg)
629 {}
630
631
632 #else // defined (HAVE_MKFIFO)
633
634
635 LyXComm::LyXComm(string const & pip, Server * cli, ClientCallbackfct ccb)
636         : pipename_(pip), client_(cli), clientcb_(ccb)
637 {
638         ready_ = false;
639         openConnection();
640 }
641
642
643 void LyXComm::openConnection()
644 {
645         LYXERR(Debug::LYXSERVER, "LyXComm: Opening connection");
646
647         // If we are up, that's an error
648         if (ready_) {
649                 lyxerr << "LyXComm: Already connected" << endl;
650                 return;
651         }
652         // We assume that we don't make it
653         ready_ = false;
654
655         if (pipename_.empty()) {
656                 LYXERR(Debug::LYXSERVER, "LyXComm: server is disabled, nothing to do");
657                 return;
658         }
659
660         infd_ = startPipe(inPipeName(), false);
661         if (infd_ == -1)
662                 return;
663
664         outfd_ = startPipe(outPipeName(), true);
665         if (outfd_ == -1) {
666                 endPipe(infd_, inPipeName(), false);
667                 return;
668         }
669
670         if (fcntl(outfd_, F_SETFL, O_NONBLOCK) < 0) {
671                 lyxerr << "LyXComm: Could not set flags on pipe " << outPipeName()
672                        << '\n' << strerror(errno) << endl;
673                 return;
674         }
675
676         // We made it!
677         ready_ = true;
678         LYXERR(Debug::LYXSERVER, "LyXComm: Connection established");
679 }
680
681
682 /// Close pipes
683 void LyXComm::closeConnection()
684 {
685         LYXERR(Debug::LYXSERVER, "LyXComm: Closing connection");
686
687         if (pipename_.empty()) {
688                 LYXERR(Debug::LYXSERVER, "LyXComm: server is disabled, nothing to do");
689                 return;
690         }
691
692         if (!ready_) {
693                 LYXERR0("LyXComm: Already disconnected");
694                 return;
695         }
696
697         endPipe(infd_, inPipeName(), false);
698         endPipe(outfd_, outPipeName(), true);
699
700         ready_ = false;
701 }
702
703
704 int LyXComm::startPipe(string const & file, bool write)
705 {
706         static bool stalepipe = false;
707         FileName const filename(file);
708         if (filename.exists()) {
709                 if (!write) {
710                         // Let's see whether we have a stale pipe.
711                         int fd = ::open(filename.toFilesystemEncoding().c_str(),
712                                         O_WRONLY | O_NONBLOCK);
713                         if (fd >= 0) {
714                                 // Another LyX instance is using it.
715                                 ::close(fd);
716                         } else if (errno == ENXIO) {
717                                 // No process is reading from the other end.
718                                 stalepipe = true;
719                                 LYXERR(Debug::LYXSERVER,
720                                         "LyXComm: trying to remove "
721                                         << filename);
722                                 filename.removeFile();
723                         }
724                 } else if (stalepipe) {
725                         LYXERR(Debug::LYXSERVER, "LyXComm: trying to remove "
726                                 << filename);
727                         filename.removeFile();
728                         stalepipe = false;
729                 }
730                 if (filename.exists()) {
731                         lyxerr << "LyXComm: Pipe " << filename
732                                << " already exists.\nIf no other LyX program"
733                                   " is active, please delete the pipe by hand"
734                                   " and try again."
735                                << endl;
736                         pipename_.erase();
737                         return -1;
738                 }
739         }
740
741         if (::mkfifo(filename.toFilesystemEncoding().c_str(), 0600) < 0) {
742                 lyxerr << "LyXComm: Could not create pipe " << filename << '\n'
743                        << strerror(errno) << endl;
744                 return -1;
745         }
746         int const fd = ::open(filename.toFilesystemEncoding().c_str(),
747                               write ? (O_RDWR) : (O_RDONLY|O_NONBLOCK));
748
749         if (fd < 0) {
750                 lyxerr << "LyXComm: Could not open pipe " << filename << '\n'
751                        << strerror(errno) << endl;
752                 filename.removeFile();
753                 return -1;
754         }
755
756         if (!write) {
757                 theApp()->registerSocketCallback(fd,
758                         boost::bind(&LyXComm::read_ready, this));
759         }
760
761         return fd;
762 }
763
764
765 void LyXComm::endPipe(int & fd, string const & filename, bool write)
766 {
767         if (fd < 0)
768                 return;
769
770         if (!write)
771                 theApp()->unregisterSocketCallback(fd);
772
773         if (::close(fd) < 0) {
774                 lyxerr << "LyXComm: Could not close pipe " << filename
775                        << '\n' << strerror(errno) << endl;
776         }
777
778         if (FileName(filename).removeFile() < 0) {
779                 lyxerr << "LyXComm: Could not remove pipe " << filename
780                        << '\n' << strerror(errno) << endl;
781         }
782
783         fd = -1;
784 }
785
786
787 void LyXComm::emergencyCleanup()
788 {
789         if (!pipename_.empty()) {
790                 endPipe(infd_, inPipeName(), false);
791                 endPipe(outfd_, outPipeName(), true);
792         }
793 }
794
795
796 // Receives messages and sends then to client
797 void LyXComm::read_ready()
798 {
799         // FIXME: make read_buffer_ a class-member for multiple sessions
800         static string read_buffer_;
801         read_buffer_.erase();
802
803         int const charbuf_size = 100;
804         char charbuf[charbuf_size];
805
806         // As O_NONBLOCK is set, until no data is available for reading,
807         // read() doesn't block but returns -1 and set errno to EAGAIN.
808         // After a client that opened the pipe for writing, closes it
809         // (and no other client is using the pipe), read() would always
810         // return 0 and thus the connection has to be reset.
811
812         errno = 0;
813         int status;
814         // the single = is intended here.
815         while ((status = ::read(infd_, charbuf, charbuf_size - 1))) {
816
817                 if (status > 0) {
818                         charbuf[status] = '\0'; // turn it into a c string
819                         read_buffer_ += rtrim(charbuf, "\r");
820                         // commit any commands read
821                         while (read_buffer_.find('\n') != string::npos) {
822                                 // split() grabs the entire string if
823                                 // the delim /wasn't/ found. ?:-P
824                                 string cmd;
825                                 read_buffer_= split(read_buffer_, cmd,'\n');
826                                 LYXERR(Debug::LYXSERVER, "LyXComm: status:" << status
827                                         << ", read_buffer_:" << read_buffer_
828                                         << ", cmd:" << cmd);
829                                 if (!cmd.empty())
830                                         clientcb_(client_, cmd);
831                                         //\n or not \n?
832                         }
833                 } else {
834                         if (errno == EAGAIN) {
835                                 // Nothing to read, continue
836                                 errno = 0;
837                                 return;
838                         }
839                         // An error occurred, better bailing out
840                         LYXERR0("LyXComm: " << strerror(errno));
841                         if (!read_buffer_.empty()) {
842                                 LYXERR0("LyXComm: truncated command: " << read_buffer_);
843                                 read_buffer_.erase();
844                         }
845                         break; // reset connection
846                 }
847         }
848
849         // The connection gets reset when read() returns 0 (meaning that the
850         // last client closed the pipe) or an error occurred, in which case
851         // read() returns -1 and errno != EAGAIN.
852         closeConnection();
853         openConnection();
854         errno = 0;
855 }
856
857
858 void LyXComm::send(string const & msg)
859 {
860         if (msg.empty()) {
861                 LYXERR0("LyXComm: Request to send empty string. Ignoring.");
862                 return;
863         }
864
865         LYXERR(Debug::LYXSERVER, "LyXComm: Sending '" << msg << '\'');
866
867         if (pipename_.empty()) return;
868
869         if (!ready_) {
870                 LYXERR0("LyXComm: Pipes are closed. Could not send " << msg);
871         } else if (::write(outfd_, msg.c_str(), msg.length()) < 0) {
872                 lyxerr << "LyXComm: Error sending message: " << msg
873                        << '\n' << strerror(errno)
874                        << "\nLyXComm: Resetting connection" << endl;
875                 closeConnection();
876                 openConnection();
877         }
878 }
879
880 #endif // defined (HAVE_MKFIFO)
881
882
883 string const LyXComm::inPipeName() const
884 {
885         return pipename_ + ".in";
886 }
887
888
889 string const LyXComm::outPipeName() const
890 {
891         return pipename_ + ".out";
892 }
893
894
895 /////////////////////////////////////////////////////////////////////
896 //
897 // Server
898 //
899 /////////////////////////////////////////////////////////////////////
900
901 void ServerCallback(Server * server, string const & msg)
902 {
903         server->callback(msg);
904 }
905
906 Server::Server(LyXFunc * f, string const & pipes)
907         : numclients_(0), func_(f), pipes_(pipes, this, &ServerCallback)
908 {}
909
910
911 Server::~Server()
912 {
913         // say goodbye to clients so they stop sending messages
914         // send as many bye messages as there are clients,
915         // each with client's name.
916         string message;
917         for (int i = 0; i != numclients_; ++i) {
918                 message = "LYXSRV:" + clients_[i] + ":bye\n";
919                 pipes_.send(message);
920         }
921 }
922
923
924 int compare(char const * a, char const * b, unsigned int len)
925 {
926         using namespace std;
927         return strncmp(a, b, len);
928 }
929
930
931 // Handle data gotten from communication, called by LyXComm
932 void Server::callback(string const & msg)
933 {
934         LYXERR(Debug::LYXSERVER, "Server: Received: '" << msg << '\'');
935
936         char const * p = msg.c_str();
937
938         // --- parse the string --------------------------------------------
939         //
940         //  Format: LYXCMD:<client>:<func>:<argstring>\n
941         //
942         bool server_only = false;
943         while (*p) {
944                 // --- 1. check 'header' ---
945
946                 if (compare(p, "LYXSRV:", 7) == 0) {
947                         server_only = true;
948                 } else if (0 != compare(p, "LYXCMD:", 7)) {
949                         lyxerr << "Server: Unknown request \""
950                                << p << '"' << endl;
951                         return;
952                 }
953                 p += 7;
954
955                 // --- 2. for the moment ignore the client name ---
956                 string client;
957                 while (*p && *p != ':')
958                         client += char(*p++);
959                 if (*p == ':')
960                         ++p;
961                 if (!*p)
962                         return;
963
964                 // --- 3. get function name ---
965                 string cmd;
966                 while (*p && *p != ':')
967                         cmd += char(*p++);
968
969                 // --- 4. parse the argument ---
970                 string arg;
971                 if (!server_only && *p == ':' && *(++p)) {
972                         while (*p && *p != '\n')
973                                 arg += char(*p++);
974                         if (*p) ++p;
975                 }
976
977                 LYXERR(Debug::LYXSERVER, "Server: Client: '" << client
978                         << "' Command: '" << cmd << "' Argument: '" << arg << '\'');
979
980                 // --- lookup and exec the command ------------------
981
982                 if (server_only) {
983                         string buf;
984                         // return the greeting to inform the client that
985                         // we are listening.
986                         if (cmd == "hello") {
987                                 // One more client
988                                 if (numclients_ == MAX_CLIENTS) { //paranoid check
989                                         LYXERR(Debug::LYXSERVER, "Server: too many clients...");
990                                         return;
991                                 }
992                                 int i = 0;
993                                 while (!clients_[i].empty() && i < numclients_)
994                                         ++i;
995                                 clients_[i] = client;
996                                 ++numclients_;
997                                 buf = "LYXSRV:" + client + ":hello\n";
998                                 LYXERR(Debug::LYXSERVER, "Server: Greeting " << client);
999                                 pipes_.send(buf);
1000                         } else if (cmd == "bye") {
1001                                 // If clients_ == 0 maybe we should reset the pipes
1002                                 // to prevent fake callbacks
1003                                 int i = 0; //look if client is registered
1004                                 for (; i < numclients_; ++i) {
1005                                         if (clients_[i] == client)
1006                                                 break;
1007                                 }
1008                                 if (i < numclients_) {
1009                                         --numclients_;
1010                                         clients_[i].erase();
1011                                         LYXERR(Debug::LYXSERVER, "Server: Client "
1012                                                 << client << " said goodbye");
1013                                 } else {
1014                                         LYXERR(Debug::LYXSERVER,
1015                                                 "Server: ignoring bye messge from unregistered client" << client);
1016                                 }
1017                         } else {
1018                                 LYXERR0("Server: Undefined server command " << cmd << '.');
1019                         }
1020                         return;
1021                 }
1022
1023                 if (!cmd.empty()) {
1024                         // which lyxfunc should we let it connect to?
1025                         // The correct solution would be to have a
1026                         // specialized (non-gui) BufferView. But how do
1027                         // we do it now? Probably we should just let it
1028                         // connect to the lyxfunc in the single LyXView we
1029                         // support currently. (Lgb)
1030
1031                         func_->dispatch(FuncRequest(lyxaction.lookupFunc(cmd), arg));
1032                         string const rval = to_utf8(func_->getMessage());
1033
1034                         // all commands produce an INFO or ERROR message
1035                         // in the output pipe, even if they do not return
1036                         // anything. See chapter 4 of Customization doc.
1037                         string buf;
1038                         if (func_->errorStat())
1039                                 buf = "ERROR:";
1040                         else
1041                                 buf = "INFO:";
1042                         buf += client + ':' + cmd + ':' +  rval + '\n';
1043                         pipes_.send(buf);
1044
1045                         // !!! we don't do any error checking -
1046                         //  if the client won't listen, the
1047                         //  message is lost and others too
1048                         //  maybe; so the client should empty
1049                         //  the outpipe before issuing a request.
1050
1051                         // not found
1052                 }
1053         }  // while *p
1054 }
1055
1056
1057 // Send a notify message to a client, called by WorkAreaKeyPress
1058 void Server::notifyClient(string const & s)
1059 {
1060         pipes_.send("NOTIFY:" + s + "\n");
1061 }
1062
1063
1064 } // namespace lyx
1065
1066 #ifdef _WIN32
1067 #include "moc_Server.cpp"
1068 #endif