]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/portsmplexer.cc
Merge pull request #8223 from PowerDNS/omoerbeek-patch-1
[thirdparty/pdns.git] / pdns / portsmplexer.cc
CommitLineData
653a5d5d 1#if defined(__sun__) && defined(__svr4__)
870a0fe4
AT
2#ifdef HAVE_CONFIG_H
3#include "config.h"
4#endif
653a5d5d
BH
5#include <port.h>
6#include <sys/port_impl.h>
7#endif
8#include <unistd.h>
c4c08d4d
BH
9#include "mplexer.hh"
10#include "sstuff.hh"
11#include <iostream>
653a5d5d 12
c4c08d4d 13#include "misc.hh"
581d2da7 14
10f4eea8 15#include "namespaces.hh"
c4c08d4d 16
c4c08d4d
BH
17class PortsFDMultiplexer : public FDMultiplexer
18{
19public:
20 PortsFDMultiplexer();
21 virtual ~PortsFDMultiplexer()
22 {
0d0f9fab 23 close(d_portfd);
c4c08d4d
BH
24 }
25
0e663c3b 26 virtual int run(struct timeval* tv, int timeout=500);
c4c08d4d 27
27ae2e3c 28 virtual void addFD(callbackmap_t& cbmap, int fd, callbackfunc_t toDo, const boost::any& parameter, const struct timeval* ttd=nullptr);
c4c08d4d
BH
29 virtual void removeFD(callbackmap_t& cbmap, int fd);
30 string getName()
31 {
32 return "solaris completion ports";
33 }
34private:
35 int d_portfd;
36 boost::shared_array<port_event_t> d_pevents;
37 static int s_maxevents; // not a hard maximum
38};
39
40
41static FDMultiplexer* makePorts()
42{
43 return new PortsFDMultiplexer();
44}
45
46static struct PortsRegisterOurselves
47{
48 PortsRegisterOurselves() {
49 FDMultiplexer::getMultiplexerMap().insert(make_pair(0, &makePorts)); // priority 0!
50 }
51} doItPorts;
52
53
54int PortsFDMultiplexer::s_maxevents=1024;
55PortsFDMultiplexer::PortsFDMultiplexer() : d_pevents(new port_event_t[s_maxevents])
56{
57 d_portfd=port_create(); // not hard max
58 if(d_portfd < 0)
59 throw FDMultiplexerException("Setting up port: "+stringerror());
60}
61
27ae2e3c 62void PortsFDMultiplexer::addFD(callbackmap_t& cbmap, int fd, callbackfunc_t toDo, const boost::any& parameter, const struct timeval* ttd)
c4c08d4d 63{
27ae2e3c 64 accountingAddFD(cbmap, fd, toDo, parameter, ttd);
c4c08d4d 65
0d0f9fab 66 if(port_associate(d_portfd, PORT_SOURCE_FD, fd, (&cbmap == &d_readCallbacks) ? POLLIN : POLLOUT, 0) < 0) {
c4c08d4d
BH
67 cbmap.erase(fd);
68 throw FDMultiplexerException("Adding fd to port set: "+stringerror());
69 }
70}
71
72void PortsFDMultiplexer::removeFD(callbackmap_t& cbmap, int fd)
73{
74 if(!cbmap.erase(fd))
335da0ba 75 throw FDMultiplexerException("Tried to remove unlisted fd "+std::to_string(fd)+ " from multiplexer");
c4c08d4d 76
692209f2 77 if(port_dissociate(d_portfd, PORT_SOURCE_FD, fd) < 0 && errno != ENOENT) // it appears under some circumstances, ENOENT will be returned, without this being an error. Apache has this same "fix"
c4c08d4d
BH
78 throw FDMultiplexerException("Removing fd from port set: "+stringerror());
79}
80
0e663c3b 81int PortsFDMultiplexer::run(struct timeval* now, int timeout)
c4c08d4d
BH
82{
83 if(d_inrun) {
84 throw FDMultiplexerException("FDMultiplexer::run() is not reentrant!\n");
85 }
86
0e663c3b
RG
87 struct timespec timeoutspec;
88 timeoutspec.tv_sec = time / 1000;
89 timeoutspec.tv_nsec = (time % 1000) * 1000000;
0d0f9fab 90 unsigned int numevents=1;
0e663c3b 91 int ret= port_getn(d_portfd, d_pevents.get(), min(PORT_MAX_LIST, s_maxevents), &numevents, &timeoutspec);
c4c08d4d 92
273d3305
BH
93 /* port_getn has an unusual API - (ret == -1, errno == ETIME) can
94 mean partial success; you must check (*numevents) in this case
95 and process anything in there, otherwise you'll never see any
96 events from that object again. We don't care about pure timeouts
97 (ret == -1, errno == ETIME, *numevents == 0) so we don't bother
98 with that case. */
645ee6e4 99 if(ret == -1 && errno!=ETIME) {
273d3305 100 if(errno!=EINTR)
625db1cc 101 throw FDMultiplexerException("completion port_getn returned error: "+stringerror());
273d3305 102 // EINTR is not really an error
1c0af70d 103 gettimeofday(now,0);
625db1cc
BH
104 return 0;
105 }
1c0af70d 106 gettimeofday(now,0);
625db1cc 107 if(!numevents) // nothing
c4c08d4d
BH
108 return 0;
109
110 d_inrun=true;
111
0d0f9fab
BH
112 for(unsigned int n=0; n < numevents; ++n) {
113 d_iter=d_readCallbacks.find(d_pevents[n].portev_object);
c4c08d4d
BH
114
115 if(d_iter != d_readCallbacks.end()) {
ac3da0c2 116 d_iter->d_callback(d_iter->d_fd, d_iter->d_parameter);
0d0f9fab 117 if(d_readCallbacks.count(d_pevents[n].portev_object) && port_associate(d_portfd, PORT_SOURCE_FD, d_pevents[n].portev_object,
232f0877 118 POLLIN, 0) < 0)
4957a608 119 throw FDMultiplexerException("Unable to add fd back to ports (read): "+stringerror());
abbd6830 120 continue; // so we don't find ourselves as writable again
c4c08d4d
BH
121 }
122
0d0f9fab 123 d_iter=d_writeCallbacks.find(d_pevents[n].portev_object);
c4c08d4d
BH
124
125 if(d_iter != d_writeCallbacks.end()) {
ac3da0c2 126 d_iter->d_callback(d_iter->d_fd, d_iter->d_parameter);
0d0f9fab 127 if(d_writeCallbacks.count(d_pevents[n].portev_object) && port_associate(d_portfd, PORT_SOURCE_FD, d_pevents[n].portev_object,
232f0877 128 POLLOUT, 0) < 0)
4957a608 129 throw FDMultiplexerException("Unable to add fd back to ports (write): "+stringerror());
c4c08d4d 130 }
c4c08d4d
BH
131
132 }
133
134 d_inrun=false;
0e663c3b 135 return numevents;
c4c08d4d
BH
136}
137
138#if 0
139void acceptData(int fd, boost::any& parameter)
140{
141 cout<<"Have data on fd "<<fd<<endl;
142 Socket* sock=boost::any_cast<Socket*>(parameter);
143 string packet;
144 IPEndpoint rem;
145 sock->recvFrom(packet, rem);
146 cout<<"Received "<<packet.size()<<" bytes!\n";
147}
148
149
150int main()
151{
a5794017 152 Socket s(AF_INET, SOCK_DGRAM);
c4c08d4d
BH
153
154 IPEndpoint loc("0.0.0.0", 2000);
155 s.bind(loc);
156
157 PortsFDMultiplexer sfm;
158
159 sfm.addReadFD(s.getHandle(), &acceptData, &s);
160
161 for(int n=0; n < 100 ; ++n) {
162 sfm.run();
163 }
164 sfm.removeReadFD(s.getHandle());
165 sfm.removeReadFD(s.getHandle());
166}
167#endif
168
169