Open Lighting Architecture
 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  private:
152  int m_fd;
154  UnmanagedFileDescriptor& operator=(const UnmanagedFileDescriptor &other);
155 };
156 
157 
158 // Comparison operation.
160  bool operator()(const ola::io::UnmanagedFileDescriptor *d1,
161  const ola::io::UnmanagedFileDescriptor *d2) const {
162  return d1->ReadDescriptor() < d2->ReadDescriptor();
163  }
164 };
165 
166 
167 /*
168  * A ConnectedDescriptor is a BidirectionalFileDescriptor that also generates
169  * notifications when it's closed.
170  */
172  public:
173  ConnectedDescriptor(): BidirectionalFileDescriptor(), m_on_close(NULL) {}
174  virtual ~ConnectedDescriptor() {
175  if (m_on_close)
176  delete m_on_close;
177  }
178 
179  virtual ssize_t Send(const uint8_t *buffer, unsigned int size);
180  virtual ssize_t Send(IOQueue *data);
181 
182  virtual int Receive(uint8_t *buffer,
183  unsigned int size,
184  unsigned int &data_read);
185 
186  virtual bool SetReadNonBlocking() {
187  return SetNonBlocking(ReadDescriptor());
188  }
189 
190  virtual bool Close() = 0;
191  int DataRemaining() const;
192  bool IsClosed() const;
193 
195 
196  // Set the OnClose closure
197  void SetOnClose(OnCloseCallback *on_close) {
198  if (m_on_close)
199  delete m_on_close;
200  m_on_close = on_close;
201  }
202 
214  OnCloseCallback *on_close = m_on_close;
215  m_on_close = NULL;
216  return on_close;
217  }
218 
219  static bool SetNonBlocking(int fd);
220 
221  protected:
222  virtual bool IsSocket() const = 0;
223  bool SetNoSigPipe(int fd);
224 
226  ConnectedDescriptor& operator=(const ConnectedDescriptor &other);
227 
228  private:
229  OnCloseCallback *m_on_close;
230 };
231 
232 
233 /*
234  * A loopback socket.
235  * Everything written is available for reading.
236  */
238  public:
240  m_fd_pair[0] = INVALID_DESCRIPTOR;
241  m_fd_pair[1] = INVALID_DESCRIPTOR;
242  }
243  ~LoopbackDescriptor() { Close(); }
244  bool Init();
245  int ReadDescriptor() const { return m_fd_pair[0]; }
246  int WriteDescriptor() const { return m_fd_pair[1]; }
247  bool Close();
248  bool CloseClient();
249 
250  protected:
251  bool IsSocket() const { return false; }
252 
253  private:
254  int m_fd_pair[2];
256  LoopbackDescriptor& operator=(const LoopbackDescriptor &other);
257 };
258 
259 
260 /*
261  * A descriptor that uses unix pipes. You can get the 'other end' of the
262  * PipeDescriptor by calling OppositeEnd().
263  */
265  public:
266  PipeDescriptor():
267  m_other_end(NULL) {
268  m_in_pair[0] = m_in_pair[1] = INVALID_DESCRIPTOR;
269  m_out_pair[0] = m_out_pair[1] = INVALID_DESCRIPTOR;
270  }
271  ~PipeDescriptor() { Close(); }
272 
273  bool Init();
274  PipeDescriptor *OppositeEnd();
275  int ReadDescriptor() const { return m_in_pair[0]; }
276  int WriteDescriptor() const { return m_out_pair[1]; }
277  bool Close();
278  bool CloseClient();
279 
280  protected:
281  bool IsSocket() const { return false; }
282 
283  private:
284  int m_in_pair[2];
285  int m_out_pair[2];
286  PipeDescriptor *m_other_end;
287  PipeDescriptor(int in_pair[2], int out_pair[2], PipeDescriptor *other_end) {
288  m_in_pair[0] = in_pair[0];
289  m_in_pair[1] = in_pair[1];
290  m_out_pair[0] = out_pair[0];
291  m_out_pair[1] = out_pair[1];
292  m_other_end = other_end;
293  }
294  PipeDescriptor(const PipeDescriptor &other);
295  PipeDescriptor& operator=(const PipeDescriptor &other);
296 };
297 
298 
299 /*
300  * A unix domain socket pair.
301  */
303  public:
304  UnixSocket():
305  m_other_end(NULL) {
306  m_fd = INVALID_DESCRIPTOR;
307  }
308  ~UnixSocket() { Close(); }
309 
310  bool Init();
311  UnixSocket *OppositeEnd();
312  int ReadDescriptor() const { return m_fd; }
313  int WriteDescriptor() const { return m_fd; }
314  bool Close();
315  bool CloseClient();
316 
317  protected:
318  bool IsSocket() const { return true; }
319 
320  private:
321  int m_fd;
322  UnixSocket *m_other_end;
323  UnixSocket(int socket, UnixSocket *other_end) {
324  m_fd = socket;
325  m_other_end = other_end;
326  }
327  UnixSocket(const UnixSocket &other);
328  UnixSocket& operator=(const UnixSocket &other);
329 };
330 
331 
332 /*
333  * A descriptor which represents a connection to a device
334  */
336  public:
337  explicit DeviceDescriptor(int fd): m_fd(fd) {}
338  ~DeviceDescriptor() { Close(); }
339 
340  int ReadDescriptor() const { return m_fd; }
341  int WriteDescriptor() const { return m_fd; }
342  bool Close();
343 
344  protected:
345  bool IsSocket() const { return false; }
346 
347  private:
348  int m_fd;
349  DeviceDescriptor(const DeviceDescriptor &other);
350  DeviceDescriptor& operator=(const DeviceDescriptor &other);
351 };
352 } // namespace io
353 } // namespace ola
354 #endif // INCLUDE_OLA_IO_DESCRIPTOR_H_