Open Lighting Architecture  0.9.1
 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
15  *
16  * Descriptor.h
17  * The Descriptor classes
18  * Copyright (C) 2005 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 // The following section of code defines the various types and helper functions
58 // needed for the Descriptor infrastructure.
59 // On *nix, there's the "everything is a file" philosophy, so we can just use
60 // ints as handles.
61 // On Windows, the situation is more complicated, so we need to treat sockets,
62 // files, devices, pipes, etc. in special ways.
63 #ifdef _WIN32
64 // Internal use only. Semantic type of the descriptor.
65 enum DescriptorType {
66  GENERIC_DESCRIPTOR = 0, // Catch-all type without special handling
67  SOCKET_DESCRIPTOR, // WinSock socket
68  PIPE_DESCRIPTOR // Named Pipe handle
69 };
70 
71 // Consider this to be an opaque type.
72 struct DescriptorHandle {
73  // The actual OS handle
74  union {
75  int m_fd;
76  void* m_handle;
77  } m_handle;
78  // Type of this descriptor's handle
79  DescriptorType m_type;
80  // Handler to an event for async I/O
81  void* m_event_handle;
82  // Pointer to read result of an async I/O call
83  uint8_t* m_read_data;
84  // Pointer to size of read result data
85  uint32_t* m_read_data_size;
86 
87  DescriptorHandle()
88  : m_type(GENERIC_DESCRIPTOR),
89  m_event_handle(0),
90  m_read_data(NULL),
91  m_read_data_size(NULL) {
92  m_handle.m_fd = -1;
93  }
94 };
95 
96 static DescriptorHandle INVALID_DESCRIPTOR;
97 static const size_t READ_DATA_BUFFER_SIZE = 1024;
98 bool operator!=(const DescriptorHandle &lhs, const DescriptorHandle &rhs);
99 bool operator==(const DescriptorHandle &lhs, const DescriptorHandle &rhs);
100 bool operator<(const DescriptorHandle &lhs, const DescriptorHandle &rhs);
101 std::ostream& operator<<(std::ostream &stream, const DescriptorHandle &data);
102 #else
103 typedef int DescriptorHandle;
104 static DescriptorHandle INVALID_DESCRIPTOR = -1;
105 #endif
106 
107 /*
108  * A FileDescriptor which can be read from.
109  */
111  public:
112  virtual ~ReadFileDescriptor() {}
113 
114  // Returns the read descriptor for this socket
115  virtual DescriptorHandle ReadDescriptor() const = 0;
116 
117  // True if the read descriptor is valid
118  bool ValidReadDescriptor() const {
119  return ReadDescriptor() != INVALID_DESCRIPTOR;
120  }
121 
122  // Called when there is data to be read from this fd
123  virtual void PerformRead() = 0;
124 };
125 
126 
127 /*
128  * A FileDescriptor which can be written to.
129  */
131  public:
132  virtual ~WriteFileDescriptor() {}
133  virtual DescriptorHandle WriteDescriptor() const = 0;
134 
135  // True if the write descriptor is valid
136  bool ValidWriteDescriptor() const {
137  return WriteDescriptor() != INVALID_DESCRIPTOR;
138  }
139 
140  // This is called when the socket is ready to be written to
141  virtual void PerformWrite() = 0;
142 };
143 
144 
145 /*
146  * A bi-directional file descriptor. This can be registered with the
147  * SelectServer for both Read and Write events.
148  */
150  public WriteFileDescriptor {
151  public :
152  BidirectionalFileDescriptor(): m_on_read(NULL), m_on_write(NULL) {}
153  virtual ~BidirectionalFileDescriptor() {
154  if (m_on_read)
155  delete m_on_read;
156 
157  if (m_on_write)
158  delete m_on_write;
159  }
160 
161  // Set the OnData closure
162  void SetOnData(ola::Callback0<void> *on_read) {
163  if (m_on_read)
164  delete m_on_read;
165  m_on_read = on_read;
166  }
167 
168  // Set the OnWrite closure
169  void SetOnWritable(ola::Callback0<void> *on_write) {
170  if (m_on_write)
171  delete m_on_write;
172  m_on_write = on_write;
173  }
174 
175  void PerformRead();
176  void PerformWrite();
177 
178  private:
179  ola::Callback0<void> *m_on_read;
180  ola::Callback0<void> *m_on_write;
181 };
182 
183 
184 /*
185  * An UnmanagedFileDescriptor allows file descriptors from other software to
186  * use the SelectServer. This class doesn't define any read/write methods, it
187  * simply allows a third-party fd to be registered with a callback.
188  */
190  public :
191  explicit UnmanagedFileDescriptor(int fd);
193  DescriptorHandle ReadDescriptor() const { return m_handle; }
194  DescriptorHandle WriteDescriptor() const { return m_handle; }
195  // Closing is left to something else
196  bool Close() { return true; }
197 
198  private:
199  DescriptorHandle m_handle;
201  UnmanagedFileDescriptor& operator=(const UnmanagedFileDescriptor &other);
202 };
203 
204 
205 // Comparison operation.
207  bool operator()(const ola::io::UnmanagedFileDescriptor *d1,
208  const ola::io::UnmanagedFileDescriptor *d2) const {
209  return d1->ReadDescriptor() < d2->ReadDescriptor();
210  }
211 };
212 
213 
214 /*
215  * A ConnectedDescriptor is a BidirectionalFileDescriptor that also generates
216  * notifications when it's closed.
217  */
219  public:
220  ConnectedDescriptor(): BidirectionalFileDescriptor(), m_on_close(NULL) {}
221  virtual ~ConnectedDescriptor() {
222  if (m_on_close)
223  delete m_on_close;
224  }
225 
226  virtual ssize_t Send(const uint8_t *buffer, unsigned int size);
227  virtual ssize_t Send(IOQueue *data);
228 
229  virtual int Receive(uint8_t *buffer,
230  unsigned int size,
231  unsigned int &data_read); // NOLINT
232 
233  virtual bool SetReadNonBlocking() {
234  return SetNonBlocking(ReadDescriptor());
235  }
236 
237  virtual bool Close() = 0;
238  int DataRemaining() const;
239  bool IsClosed() const;
240 
242 
243  // Set the OnClose closure
244  void SetOnClose(OnCloseCallback *on_close) {
245  if (m_on_close)
246  delete m_on_close;
247  m_on_close = on_close;
248  }
249 
261  OnCloseCallback *on_close = m_on_close;
262  m_on_close = NULL;
263  return on_close;
264  }
265 
266  static bool SetNonBlocking(DescriptorHandle fd);
267 
268  protected:
269  virtual bool IsSocket() const = 0;
270  bool SetNoSigPipe(DescriptorHandle fd);
271 
273  ConnectedDescriptor& operator=(const ConnectedDescriptor &other);
274 
275  private:
276  OnCloseCallback *m_on_close;
277 };
278 
279 
280 /*
281  * A loopback socket.
282  * Everything written is available for reading.
283  */
285  public:
287  m_handle_pair[0] = INVALID_DESCRIPTOR;
288  m_handle_pair[1] = INVALID_DESCRIPTOR;
289 #ifdef _WIN32
290  memset(m_read_data, 0, READ_DATA_BUFFER_SIZE);
291  m_read_data_size = 0;
292 #endif
293  }
294  ~LoopbackDescriptor() { Close(); }
295  bool Init();
296  DescriptorHandle ReadDescriptor() const { return m_handle_pair[0]; }
297  DescriptorHandle WriteDescriptor() const { return m_handle_pair[1]; }
298  bool Close();
299  bool CloseClient();
300 
301  protected:
302  bool IsSocket() const { return false; }
303 
304  private:
305  DescriptorHandle m_handle_pair[2];
307  LoopbackDescriptor& operator=(const LoopbackDescriptor &other);
308 #ifdef _WIN32
309  uint8_t m_read_data[READ_DATA_BUFFER_SIZE];
310  uint32_t m_read_data_size;
311 #endif
312 };
313 
314 
315 /*
316  * A descriptor that uses unix pipes. You can get the 'other end' of the
317  * PipeDescriptor by calling OppositeEnd().
318  */
320  public:
321  PipeDescriptor():
322  m_other_end(NULL) {
323  m_in_pair[0] = m_in_pair[1] = INVALID_DESCRIPTOR;
324  m_out_pair[0] = m_out_pair[1] = INVALID_DESCRIPTOR;
325 #ifdef _WIN32
326  memset(m_read_data, 0, READ_DATA_BUFFER_SIZE);
327  m_read_data_size = 0;
328 #endif
329  }
330  ~PipeDescriptor() { Close(); }
331 
332  bool Init();
333  PipeDescriptor *OppositeEnd();
334  DescriptorHandle ReadDescriptor() const { return m_in_pair[0]; }
335  DescriptorHandle WriteDescriptor() const { return m_out_pair[1]; }
336  bool Close();
337  bool CloseClient();
338 
339  protected:
340  bool IsSocket() const { return false; }
341 
342  private:
343  DescriptorHandle m_in_pair[2];
344  DescriptorHandle m_out_pair[2];
345  PipeDescriptor *m_other_end;
346  PipeDescriptor(DescriptorHandle in_pair[2],
347  DescriptorHandle out_pair[2],
348  PipeDescriptor *other_end) {
349  m_in_pair[0] = in_pair[0];
350  m_in_pair[1] = in_pair[1];
351  m_out_pair[0] = out_pair[0];
352  m_out_pair[1] = out_pair[1];
353  m_other_end = other_end;
354 #ifdef _WIN32
355  m_in_pair[0].m_read_data = m_read_data;
356  m_in_pair[0].m_read_data_size = &m_read_data_size;
357 #endif
358  }
359  PipeDescriptor(const PipeDescriptor &other);
360  PipeDescriptor& operator=(const PipeDescriptor &other);
361 #ifdef _WIN32
362  uint8_t m_read_data[READ_DATA_BUFFER_SIZE];
363  uint32_t m_read_data_size;
364 #endif
365 };
366 
367 /*
368  * A unix domain socket pair.
369  */
371  public:
372  UnixSocket():
373  m_other_end(NULL) {
374  m_handle = INVALID_DESCRIPTOR;
375  }
376  ~UnixSocket() { Close(); }
377 
378  bool Init();
379  UnixSocket *OppositeEnd();
380  DescriptorHandle ReadDescriptor() const { return m_handle; }
381  DescriptorHandle WriteDescriptor() const { return m_handle; }
382  bool Close();
383  bool CloseClient();
384 
385  protected:
386  bool IsSocket() const { return true; }
387 
388  private:
389  DescriptorHandle m_handle;
390  UnixSocket *m_other_end;
391  UnixSocket(int socket, UnixSocket *other_end) {
392 #ifdef _WIN32
393  m_handle.m_handle.m_fd = socket;
394 #else
395  m_handle = socket;
396 #endif
397  m_other_end = other_end;
398  }
399  UnixSocket(const UnixSocket &other);
400  UnixSocket& operator=(const UnixSocket &other);
401 };
402 
403 /*
404  * A descriptor which represents a connection to a device
405  */
407  public:
408  explicit DeviceDescriptor(int fd);
409  ~DeviceDescriptor() { Close(); }
410 
411  DescriptorHandle ReadDescriptor() const { return m_handle; }
412  DescriptorHandle WriteDescriptor() const { return m_handle; }
413  bool Close();
414 
415  protected:
416  bool IsSocket() const { return false; }
417 
418  private:
419  DescriptorHandle m_handle;
420  DeviceDescriptor(const DeviceDescriptor &other);
421  DeviceDescriptor& operator=(const DeviceDescriptor &other);
422 };
423 } // namespace io
424 } // namespace ola
425 #endif // INCLUDE_OLA_IO_DESCRIPTOR_H_