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