Open Lighting Architecture  0.9.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Descriptor.h
1 /*
2  * This library is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU Lesser General Public
4  * License as published by the Free Software Foundation; either
5  * version 2.1 of the License, or (at your option) any later version.
6  *
7  * This library is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10  * Lesser General Public License for more details.
11  *
12  * You should have received a copy of the GNU Lesser General Public
13  * License along with this library; if not, write to the Free Software
14  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15  *
16  * Descriptor.h
17  * The Descriptor classes
18  * Copyright (C) 2005-2012 Simon Newton
19  *
20  * This defines all the different types of file descriptors that can be used by
21  * the SelectServer. At the top level, the ReadFileDescriptor /
22  * WriteFileDescriptor interfaces provide the minimum functionality needed to
23  * register a socket with the SelectServer to handle read / write events.
24  * The BidirectionalFileDescriptor extends this interface to handle
25  * both reading and writing.
26  *
27  * The UnmanagedFileDescriptor allows socket descriptors controller by other
28  * libraries to be used with the SelectServer.
29  *
30  * ConnectedDescriptor is a socket with tighter intergration with the
31  * SelectServer. This allows the SelectServer to detect when the socket is
32  * closed and call the OnClose() handler. It also provides methods to disable
33  * SIGPIPE, control the blocking attributes and check how much data remains to
34  * be read. ConnectedDescriptor has the following sub-classes:
35  *
36  * - LoopbackDescriptor this socket is just a pipe(). Data written to the
37  * socket is available to be read.
38  * - PipeDescriptor allows a pair of sockets to be created. Data written to
39  * socket A is available at FileDescriptor B and visa versa.
40  * - UnixSocket, similar to PipeDescriptor but uses unix domain sockets.
41  * - DeviceDescriptor, this is a generic ConnectedDescriptor. It can be used
42  * with file descriptors to handle local devices.
43  */
44 
45 #ifndef INCLUDE_OLA_IO_DESCRIPTOR_H_
46 #define INCLUDE_OLA_IO_DESCRIPTOR_H_
47 
48 #include <stdint.h>
49 #include <unistd.h>
50 #include <ola/Callback.h>
51 #include <ola/io/IOQueue.h>
52 #include <string>
53 
54 namespace ola {
55 namespace io {
56 
57 static const int INVALID_DESCRIPTOR = -1;
58 
59 /*
60  * A FileDescriptor which can be read from.
61  */
63  public:
64  virtual ~ReadFileDescriptor() {}
65 
66  // Returns the read descriptor for this socket
67  virtual int ReadDescriptor() const = 0;
68 
69  // True if the read descriptor is valid
70  bool ValidReadDescriptor() const {
71  return ReadDescriptor() != INVALID_DESCRIPTOR;
72  }
73 
74  // Called when there is data to be read from this fd
75  virtual void PerformRead() = 0;
76 };
77 
78 
79 /*
80  * A FileDescriptor which can be written to.
81  */
83  public:
84  virtual ~WriteFileDescriptor() {}
85  virtual int WriteDescriptor() const = 0;
86 
87  // True if the write descriptor is valid
88  bool ValidWriteDescriptor() const {
89  return WriteDescriptor() != INVALID_DESCRIPTOR;
90  }
91 
92  // This is called when the socket is ready to be written to
93  virtual void PerformWrite() = 0;
94 };
95 
96 
97 /*
98  * A bi-directional file descriptor. This can be registered with the
99  * SelectServer for both Read and Write events.
100  */
102  public WriteFileDescriptor {
103  public :
104  BidirectionalFileDescriptor(): m_on_read(NULL), m_on_write(NULL) {}
105  virtual ~BidirectionalFileDescriptor() {
106  if (m_on_read)
107  delete m_on_read;
108 
109  if (m_on_write)
110  delete m_on_write;
111  }
112 
113  // Set the OnData closure
114  void SetOnData(ola::Callback0<void> *on_read) {
115  if (m_on_read)
116  delete m_on_read;
117  m_on_read = on_read;
118  }
119 
120  // Set the OnWrite closure
121  void SetOnWritable(ola::Callback0<void> *on_write) {
122  if (m_on_write)
123  delete m_on_write;
124  m_on_write = on_write;
125  }
126 
127  void PerformRead();
128  void PerformWrite();
129 
130  private:
131  ola::Callback0<void> *m_on_read;
132  ola::Callback0<void> *m_on_write;
133 };
134 
135 
136 /*
137  * An UnmanagedFileDescriptor allows file descriptors from other software to
138  * use the SelectServer. This class doesn't define any read/write methods, it
139  * simply allows a third-party sd to be registered with a callback.
140  */
142  public :
143  explicit UnmanagedFileDescriptor(int fd)
145  m_fd(fd) {}
147  int ReadDescriptor() const { return m_fd; }
148  int WriteDescriptor() const { return m_fd; }
149  // Closing is left to something else
150  bool Close() { return true; }
151 
152  private:
153  int m_fd;
155  UnmanagedFileDescriptor& operator=(const UnmanagedFileDescriptor &other);
156 };
157 
158 
159 // Comparison operation.
161  bool operator()(const ola::io::UnmanagedFileDescriptor *d1,
162  const ola::io::UnmanagedFileDescriptor *d2) const {
163  return d1->ReadDescriptor() < d2->ReadDescriptor();
164  }
165 };
166 
167 
168 /*
169  * A ConnectedDescriptor is a BidirectionalFileDescriptor that also generates
170  * notifications when it's closed.
171  */
173  public:
174  ConnectedDescriptor(): BidirectionalFileDescriptor(), m_on_close(NULL) {}
175  virtual ~ConnectedDescriptor() {
176  if (m_on_close)
177  delete m_on_close;
178  }
179 
180  virtual ssize_t Send(const uint8_t *buffer, unsigned int size);
181  virtual ssize_t Send(IOQueue *data);
182 
183  virtual int Receive(uint8_t *buffer,
184  unsigned int size,
185  unsigned int &data_read); // NOLINT
186 
187  virtual bool SetReadNonBlocking() {
188  return SetNonBlocking(ReadDescriptor());
189  }
190 
191  virtual bool Close() = 0;
192  int DataRemaining() const;
193  bool IsClosed() const;
194 
196 
197  // Set the OnClose closure
198  void SetOnClose(OnCloseCallback *on_close) {
199  if (m_on_close)
200  delete m_on_close;
201  m_on_close = on_close;
202  }
203 
215  OnCloseCallback *on_close = m_on_close;
216  m_on_close = NULL;
217  return on_close;
218  }
219 
220  static bool SetNonBlocking(int fd);
221 
222  protected:
223  virtual bool IsSocket() const = 0;
224  bool SetNoSigPipe(int fd);
225 
227  ConnectedDescriptor& operator=(const ConnectedDescriptor &other);
228 
229  private:
230  OnCloseCallback *m_on_close;
231 };
232 
233 
234 /*
235  * A loopback socket.
236  * Everything written is available for reading.
237  */
239  public:
241  m_fd_pair[0] = INVALID_DESCRIPTOR;
242  m_fd_pair[1] = INVALID_DESCRIPTOR;
243  }
244  ~LoopbackDescriptor() { Close(); }
245  bool Init();
246  int ReadDescriptor() const { return m_fd_pair[0]; }
247  int WriteDescriptor() const { return m_fd_pair[1]; }
248  bool Close();
249  bool CloseClient();
250 
251  protected:
252  bool IsSocket() const { return false; }
253 
254  private:
255  int m_fd_pair[2];
257  LoopbackDescriptor& operator=(const LoopbackDescriptor &other);
258 };
259 
260 
261 /*
262  * A descriptor that uses unix pipes. You can get the 'other end' of the
263  * PipeDescriptor by calling OppositeEnd().
264  */
266  public:
267  PipeDescriptor():
268  m_other_end(NULL) {
269  m_in_pair[0] = m_in_pair[1] = INVALID_DESCRIPTOR;
270  m_out_pair[0] = m_out_pair[1] = INVALID_DESCRIPTOR;
271  }
272  ~PipeDescriptor() { Close(); }
273 
274  bool Init();
275  PipeDescriptor *OppositeEnd();
276  int ReadDescriptor() const { return m_in_pair[0]; }
277  int WriteDescriptor() const { return m_out_pair[1]; }
278  bool Close();
279  bool CloseClient();
280 
281  protected:
282  bool IsSocket() const { return false; }
283 
284  private:
285  int m_in_pair[2];
286  int m_out_pair[2];
287  PipeDescriptor *m_other_end;
288  PipeDescriptor(int in_pair[2], int out_pair[2], PipeDescriptor *other_end) {
289  m_in_pair[0] = in_pair[0];
290  m_in_pair[1] = in_pair[1];
291  m_out_pair[0] = out_pair[0];
292  m_out_pair[1] = out_pair[1];
293  m_other_end = other_end;
294  }
295  PipeDescriptor(const PipeDescriptor &other);
296  PipeDescriptor& operator=(const PipeDescriptor &other);
297 };
298 
299 
300 /*
301  * A unix domain socket pair.
302  */
304  public:
305  UnixSocket():
306  m_other_end(NULL) {
307  m_fd = INVALID_DESCRIPTOR;
308  }
309  ~UnixSocket() { Close(); }
310 
311  bool Init();
312  UnixSocket *OppositeEnd();
313  int ReadDescriptor() const { return m_fd; }
314  int WriteDescriptor() const { return m_fd; }
315  bool Close();
316  bool CloseClient();
317 
318  protected:
319  bool IsSocket() const { return true; }
320 
321  private:
322  int m_fd;
323  UnixSocket *m_other_end;
324  UnixSocket(int socket, UnixSocket *other_end) {
325  m_fd = socket;
326  m_other_end = other_end;
327  }
328  UnixSocket(const UnixSocket &other);
329  UnixSocket& operator=(const UnixSocket &other);
330 };
331 
332 
333 /*
334  * A descriptor which represents a connection to a device
335  */
337  public:
338  explicit DeviceDescriptor(int fd): m_fd(fd) {}
339  ~DeviceDescriptor() { Close(); }
340 
341  int ReadDescriptor() const { return m_fd; }
342  int WriteDescriptor() const { return m_fd; }
343  bool Close();
344 
345  protected:
346  bool IsSocket() const { return false; }
347 
348  private:
349  int m_fd;
350  DeviceDescriptor(const DeviceDescriptor &other);
351  DeviceDescriptor& operator=(const DeviceDescriptor &other);
352 };
353 } // namespace io
354 } // namespace ola
355 #endif // INCLUDE_OLA_IO_DESCRIPTOR_H_