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