]> git.lyx.org Git - features.git/blob - src/Server.h
2f26b8aef7d1eabe3ef58a46b325000223359772
[features.git] / src / Server.h
1 // -*- C++ -*-
2 /**
3  * \file Server.h
4  * This file is part of LyX, the document processor.
5  * Licence details can be found in the file COPYING.
6  *
7  * \author Lars Gullik Bjønnes
8  * \author Jean-Marc Lasgouttes
9  * \author Enrico Forestieri
10  *
11  * Full author contact details are available in file CREDITS.
12  */
13
14 #ifndef SERVER_H
15 #define SERVER_H
16
17 #include <memory>
18 #include <vector>
19
20 #ifdef _WIN32
21 #include <windows.h>
22 #include <QObject>
23 #include <QEvent>
24 #endif
25
26
27 namespace lyx {
28
29 class Server;
30
31
32 /// A small utility to track the lifetime of an object.
33 class Trackable {
34 public:
35         Trackable() : p_(std::make_shared<int>(0)) {}
36         Trackable(Trackable const &) : Trackable() {}
37         Trackable(Trackable &&) : Trackable() {}
38         Trackable & operator=(Trackable const &) { return *this; }
39         Trackable & operator=(Trackable &&) { return *this; }
40         // This weak pointer lets you know if the parent object has been destroyed
41         std::weak_ptr<void> p() const { return p_; }
42 private:
43         std::shared_ptr<void> const p_;
44 };
45
46
47 /** This class manages the pipes used for communicating with clients.
48  Usage: Initialize with pipe-filename-base, client class to receive
49  messages, and callback-function that will be called with the messages.
50  When you want to send, use "send()".
51  This class encapsulates all the dirty communication and thus provides
52  a clean string interface.
53  */
54 #ifndef _WIN32
55 class LyXComm {
56 #else
57 class LyXComm : public QObject {
58         Q_OBJECT
59
60         friend DWORD WINAPI pipeServerWrapper(void *);
61
62 public:
63         /// Max number of clients
64         enum { MAX_CLIENTS = 10 };
65
66 private:
67         /// Max number of pipe instances
68         enum { MAX_PIPES = 2 * MAX_CLIENTS };
69
70         /// I/O buffer size
71         enum { PIPE_BUFSIZE = 512 };
72
73         /// Pipe client time-out
74         enum { PIPE_TIMEOUT = 5000 };
75
76         /// Pipe states
77         enum PipeState {
78                 CONNECTING_STATE,
79                 READING_STATE,
80                 WRITING_STATE
81         };
82
83         /// Pipe instances
84         typedef struct {
85                 OVERLAPPED overlap;
86                 HANDLE handle;
87                 std::string iobuf;
88                 char readbuf[PIPE_BUFSIZE];
89                 DWORD nbytes;
90                 PipeState state;
91                 bool pending_io;
92         } PipeInst;
93 #endif
94 public:
95         /** When we receive a message, we send it to a client.
96           This is one of the small things that would have been a lot
97           cleaner with a Signal/Slot thing.
98          */
99         typedef void (*ClientCallbackfct)(Server *, std::string const &);
100
101         /// Construct with pipe-basename and callback to receive messages
102         LyXComm(std::string const & pip, Server * cli, ClientCallbackfct ccb = 0);
103
104         ///
105         ~LyXComm() { closeConnection(); }
106
107         /// clean up in emergency
108         void emergencyCleanup();
109
110         /// Send message
111         void send(std::string const &);
112
113         /// asynch ready-to-be-read notification
114 #ifndef _WIN32
115         void read_ready();
116 #else
117         void read_ready(DWORD);
118 #endif
119
120         /// Tell whether we asked another instance of LyX to open the files
121         bool deferredLoading() const { return deferred_loading_; }
122
123 private:
124         /// the filename of the in pipe
125         std::string const inPipeName() const;
126
127         /// the filename of the out pipe
128         std::string const outPipeName() const;
129
130         /// Open pipes
131         void openConnection();
132
133         /// Close pipes
134         void closeConnection();
135
136         /// Load files in another running instance of LyX
137         bool loadFilesInOtherInstance() const;
138
139 #ifndef _WIN32
140         /// start a pipe
141         int startPipe(std::string const &, bool);
142
143         /// finish a pipe
144         void endPipe(int &, std::string const &, bool);
145
146         /// This is -1 if not open
147         int infd_;
148
149         /// This is -1 if not open
150         int outfd_;
151 #else
152         /// The pipe server returns false when exiting due to an error
153         bool pipeServer();
154
155         /// Start an overlapped connection
156         bool startPipe(DWORD);
157
158         /// Reset an overlapped connection
159         bool resetPipe(DWORD, bool close_handle = false);
160
161         /// Close event and pipe handles
162         void closeHandles();
163
164         /// Catch pipe ready-to-be-read notification
165         bool event(QEvent *);
166
167         /// Check whether the pipe server must be stopped
168         bool checkStopServer(DWORD timeout = 0);
169
170         /// The filename of a (in or out) pipe instance
171         std::string const pipeName(DWORD) const;
172
173         /// Pipe instances
174         PipeInst pipe_[MAX_PIPES];
175
176         /// Pipe server control events
177         HANDLE event_[MAX_PIPES + 1];
178
179         /// Reply buffer
180         std::string outbuf_;
181
182         /// Synchronize access to outbuf_
183         HANDLE outbuf_mutex_;
184
185         /// Windows event for stopping the pipe server
186         HANDLE stopserver_;
187
188         /// Pipe server thread handle
189         HANDLE server_thread_;
190 #endif
191
192         /// Are we up and running?
193         bool ready_;
194
195         /// Base of pipename including path
196         std::string pipename_;
197
198         /// The client
199         Server * client_;
200
201         /// The client callback function
202         ClientCallbackfct clientcb_;
203
204         /// Did we defer loading of files to another instance?
205         bool deferred_loading_;
206
207         /// Track object's liveness
208         Trackable tracker_;
209 };
210
211
212 ///
213 class Server {
214 public:
215         // FIXME IN 0.13
216         // Hack! This should be changed in 0.13
217
218         // IMO lyxserver is atypical, and for the moment the only one, non-gui
219         // bufferview. We just have to find a way to handle situations like if
220         // lyxserver is using a buffer that is being edited with a bufferview.
221         // With a common buffer list this is not a problem, maybe. (Alejandro)
222         ///
223         Server(std::string const & pipes);
224         ///
225         ~Server();
226         ///
227         void notifyClient(std::string const &);
228         ///
229         bool deferredLoadingToOtherInstance() const { return pipes_.deferredLoading(); }
230
231         /// whilst crashing etc.
232         void emergencyCleanup() { pipes_.emergencyCleanup(); }
233         ///
234         void callback(std::string const & msg);
235
236 private:
237         /// Names and number of current clients
238 #ifndef _WIN32
239         enum { MAX_CLIENTS = 10 };
240 #else
241         enum { MAX_CLIENTS = LyXComm::MAX_CLIENTS };
242 #endif
243         ///
244         std::string clients_[MAX_CLIENTS];
245         ///
246         int numclients_;
247         ///
248         LyXComm pipes_;
249 };
250
251 /// Implementation is in LyX.cpp
252 Server & theServer();
253
254 /// Implementation is in LyX.cpp
255 extern std::vector<std::string> & theFilesToLoad();
256
257
258 } // namespace lyx
259
260 #endif // SERVER_H