libsocket
select.hpp
Go to the documentation of this file.
1 #ifndef LIBSOCKET_SELECT_H_7F761B91E8A84EB685E898542039D68F
2 #define LIBSOCKET_SELECT_H_7F761B91E8A84EB685E898542039D68F
3 
4 #include <cstring>
5 #include <list>
6 #include <map>
7 #include <utility>
8 #include <vector>
9 
10 #include <errno.h>
11 #include <sys/select.h>
12 #include <sys/time.h>
13 #include <sys/types.h>
14 #include <unistd.h>
15 
16 namespace poll {
17 #include <poll.h>
18 }
19 
20 #include "exception.hpp"
21 
46 /*
47  The committers of the libsocket project, all rights reserved
48  (c) 2012, dermesser <lbo@spheniscida.de>
49 
50  Redistribution and use in source and binary forms, with or without
51  modification, are permitted provided that the following conditions are met:
52 
53  1. Redistributions of source code must retain the above copyright notice,
54  this list of conditions and the following disclaimer.
55  2. Redistributions in binary form must reproduce the above copyright notice,
56  this list of conditions and the following disclaimer in the documentation
57  and/or other materials provided with the distribution.
58 
59  THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS “AS IS” AND ANY
60  EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
61  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
62  DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
63  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
64  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
65  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
66  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
67  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
68  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
69 
70 */
71 
72 #include "socket.hpp"
73 
74 namespace libsocket {
101 template <typename SocketT>
102 class selectset {
103  private:
104  std::map<int, SocketT*>
106 
108  bool set_up;
109 
110  std::vector<poll::pollfd> pollfd_set; // Set of pollfd structs to poll
111 
112  public:
113  selectset();
114 
115  void add_fd(const SocketT& sock, int method);
116 
117  std::pair<std::vector<SocketT*>, std::vector<SocketT*> > wait(
118  long long microsecs = 0);
119  typedef std::pair<std::vector<SocketT*>, std::vector<SocketT*> >
120  ready_socks;
121 };
126 extern int highestfd(const std::vector<int>& v);
127 
133 template <typename SockT>
134 selectset<SockT>::selectset(void) : set_up(false) {}
135 
145 template <typename SocketT>
146 void selectset<SocketT>::add_fd(const SocketT& sock, int method) {
147  int fd = sock.getfd();
148 
149  if (method == LIBSOCKET_READ) {
150  poll::pollfd fdinfo{fd, POLLIN, 0};
151  pollfd_set.push_back(fdinfo);
152  fdsockmap[fd] = const_cast<SocketT*>(&sock);
153  set_up = true;
154 
155  } else if (method == LIBSOCKET_WRITE) {
156  poll::pollfd fdinfo{fd, POLLOUT, 0};
157  pollfd_set.push_back(fdinfo);
158  fdsockmap[fd] = const_cast<SocketT*>(&sock);
159  set_up = true;
160  } else if (method ==
161  (LIBSOCKET_READ | LIBSOCKET_WRITE)) { // don't put the fd in our
162  // data structures twice.
163  poll::pollfd fdinfo{fd, (POLLIN | POLLOUT), 0};
164  pollfd_set.push_back(fdinfo);
165  fdsockmap[fd] = const_cast<SocketT*>(&sock);
166  set_up = true;
167  }
168 }
169 
184 template <typename SockT>
185 typename selectset<SockT>::ready_socks selectset<SockT>::wait(
186  long long microsecs) {
187  int n = 0;
188 
189  struct timespec* timeout = NULL;
190  struct timespec _timeout;
191 
192  if (microsecs != 0) {
193  timeout = &_timeout;
194 
195  long long nanosecs = microsecs * 1000;
196  long long nanopart = nanosecs % 1000000000;
197  long long secpart = (nanosecs - nanopart) / 1000000000;
198 
199  _timeout.tv_sec = secpart;
200  _timeout.tv_nsec = nanopart;
201  }
202 
203  n = ppoll((poll::pollfd*)pollfd_set.data(), pollfd_set.size(), timeout,
204  NULL);
205 
206  ready_socks rwfds;
207 
208  if (n < 0) {
209  std::string err(strerror(errno));
210 
211  throw socket_exception(__FILE__, __LINE__,
212  "selectset::wait(): Error at ppoll(): " + err);
213 
214  } else if (n == 0) // time is over, no filedescriptor is ready
215  {
216  rwfds.first.resize(0);
217  rwfds.second.resize(0);
218 
219  return rwfds;
220  }
221 
222  std::vector<poll::pollfd>::iterator end = pollfd_set.end();
223 
224  for (std::vector<poll::pollfd>::iterator iter = pollfd_set.begin();
225  iter != end; ++iter) {
226  if (iter->revents & POLLIN) rwfds.first.push_back(fdsockmap[iter->fd]);
227 
228  if (iter->revents & POLLOUT)
229  rwfds.second.push_back(fdsockmap[iter->fd]);
230  }
231 
232  return rwfds;
233 }
234 
235 } // namespace libsocket
236 
237 #endif
std::pair< std::vector< SocketT * >, std::vector< SocketT * > > wait(long long microsecs=0)
Waits for a possibility to read or write data to emerge.
Definition: select.hpp:185
Contains libsocket elements.
Definition: dgramclient.hpp:41
void add_fd(const SocketT &sock, int method)
Add a socket to the internal sets.
Definition: select.hpp:146
This class is instantiated and thrown when an error occurs. If there's an error somewhere in libsocke...
Definition: exception.hpp:52
selectset()
Constructor.
Definition: select.hpp:134
int highestfd(const std::vector< int > &v)
Utility function to find the highest number in a vector (typically, the highest file descriptor)
Definition: select.cpp:42
std::map< int, SocketT * > fdsockmap
Definition: select.hpp:105
bool set_up
Stores if the class has been initiated.
Definition: select.hpp:108
selectset provides a simple abstraction over – contrary to its name – poll(2).
Definition: select.hpp:102