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