]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/portsmplexer.cc
Add some notes explaining why some validations are not relevant in the dnstap case.
[thirdparty/pdns.git] / pdns / portsmplexer.cc
1 #if defined(__sun__) && defined(__svr4__)
2 #ifdef HAVE_CONFIG_H
3 #include "config.h"
4 #endif
5 #include <port.h>
6 #include <sys/port_impl.h>
7 #endif
8 #include <unistd.h>
9 #include "mplexer.hh"
10 #include "sstuff.hh"
11 #include <iostream>
12
13 #include "misc.hh"
14
15 #include "namespaces.hh"
16
17 class PortsFDMultiplexer : public FDMultiplexer
18 {
19 public:
20 PortsFDMultiplexer();
21 virtual ~PortsFDMultiplexer()
22 {
23 close(d_portfd);
24 }
25
26 virtual int run(struct timeval* tv, int timeout=500);
27
28 virtual void addFD(callbackmap_t& cbmap, int fd, callbackfunc_t toDo, const boost::any& parameter, const struct timeval* ttd=nullptr);
29 virtual void removeFD(callbackmap_t& cbmap, int fd);
30 string getName()
31 {
32 return "solaris completion ports";
33 }
34 private:
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
41 static FDMultiplexer* makePorts()
42 {
43 return new PortsFDMultiplexer();
44 }
45
46 static struct PortsRegisterOurselves
47 {
48 PortsRegisterOurselves() {
49 FDMultiplexer::getMultiplexerMap().insert(make_pair(0, &makePorts)); // priority 0!
50 }
51 } doItPorts;
52
53
54 int PortsFDMultiplexer::s_maxevents=1024;
55 PortsFDMultiplexer::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
62 void PortsFDMultiplexer::addFD(callbackmap_t& cbmap, int fd, callbackfunc_t toDo, const boost::any& parameter, const struct timeval* ttd)
63 {
64 accountingAddFD(cbmap, fd, toDo, parameter, ttd);
65
66 if(port_associate(d_portfd, PORT_SOURCE_FD, fd, (&cbmap == &d_readCallbacks) ? POLLIN : POLLOUT, 0) < 0) {
67 cbmap.erase(fd);
68 throw FDMultiplexerException("Adding fd to port set: "+stringerror());
69 }
70 }
71
72 void PortsFDMultiplexer::removeFD(callbackmap_t& cbmap, int fd)
73 {
74 if(!cbmap.erase(fd))
75 throw FDMultiplexerException("Tried to remove unlisted fd "+std::to_string(fd)+ " from multiplexer");
76
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"
78 throw FDMultiplexerException("Removing fd from port set: "+stringerror());
79 }
80
81 int PortsFDMultiplexer::run(struct timeval* now, int timeout)
82 {
83 if(d_inrun) {
84 throw FDMultiplexerException("FDMultiplexer::run() is not reentrant!\n");
85 }
86
87 struct timespec timeoutspec;
88 timeoutspec.tv_sec = time / 1000;
89 timeoutspec.tv_nsec = (time % 1000) * 1000000;
90 unsigned int numevents=1;
91 int ret= port_getn(d_portfd, d_pevents.get(), min(PORT_MAX_LIST, s_maxevents), &numevents, &timeoutspec);
92
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. */
99 if(ret == -1 && errno!=ETIME) {
100 if(errno!=EINTR)
101 throw FDMultiplexerException("completion port_getn returned error: "+stringerror());
102 // EINTR is not really an error
103 gettimeofday(now,0);
104 return 0;
105 }
106 gettimeofday(now,0);
107 if(!numevents) // nothing
108 return 0;
109
110 d_inrun=true;
111
112 for(unsigned int n=0; n < numevents; ++n) {
113 d_iter=d_readCallbacks.find(d_pevents[n].portev_object);
114
115 if(d_iter != d_readCallbacks.end()) {
116 d_iter->d_callback(d_iter->d_fd, d_iter->d_parameter);
117 if(d_readCallbacks.count(d_pevents[n].portev_object) && port_associate(d_portfd, PORT_SOURCE_FD, d_pevents[n].portev_object,
118 POLLIN, 0) < 0)
119 throw FDMultiplexerException("Unable to add fd back to ports (read): "+stringerror());
120 continue; // so we don't find ourselves as writable again
121 }
122
123 d_iter=d_writeCallbacks.find(d_pevents[n].portev_object);
124
125 if(d_iter != d_writeCallbacks.end()) {
126 d_iter->d_callback(d_iter->d_fd, d_iter->d_parameter);
127 if(d_writeCallbacks.count(d_pevents[n].portev_object) && port_associate(d_portfd, PORT_SOURCE_FD, d_pevents[n].portev_object,
128 POLLOUT, 0) < 0)
129 throw FDMultiplexerException("Unable to add fd back to ports (write): "+stringerror());
130 }
131
132 }
133
134 d_inrun=false;
135 return numevents;
136 }
137
138 #if 0
139 void 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
150 int main()
151 {
152 Socket s(AF_INET, SOCK_DGRAM);
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