]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/portsmplexer.cc
Merge pull request #5523 from rubenk/fix-typos-in-logmessage
[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 #include "syncres.hh"
15
16 #include "namespaces.hh"
17 #include "namespaces.hh"
18
19 class PortsFDMultiplexer : public FDMultiplexer
20 {
21 public:
22 PortsFDMultiplexer();
23 virtual ~PortsFDMultiplexer()
24 {
25 close(d_portfd);
26 }
27
28 virtual int run(struct timeval* tv);
29
30 virtual void addFD(callbackmap_t& cbmap, int fd, callbackfunc_t toDo, const boost::any& parameter);
31 virtual void removeFD(callbackmap_t& cbmap, int fd);
32 string getName()
33 {
34 return "solaris completion ports";
35 }
36 private:
37 int d_portfd;
38 boost::shared_array<port_event_t> d_pevents;
39 static int s_maxevents; // not a hard maximum
40 };
41
42
43 static FDMultiplexer* makePorts()
44 {
45 return new PortsFDMultiplexer();
46 }
47
48 static struct PortsRegisterOurselves
49 {
50 PortsRegisterOurselves() {
51 FDMultiplexer::getMultiplexerMap().insert(make_pair(0, &makePorts)); // priority 0!
52 }
53 } doItPorts;
54
55
56 int PortsFDMultiplexer::s_maxevents=1024;
57 PortsFDMultiplexer::PortsFDMultiplexer() : d_pevents(new port_event_t[s_maxevents])
58 {
59 d_portfd=port_create(); // not hard max
60 if(d_portfd < 0)
61 throw FDMultiplexerException("Setting up port: "+stringerror());
62 }
63
64 void PortsFDMultiplexer::addFD(callbackmap_t& cbmap, int fd, callbackfunc_t toDo, const boost::any& parameter)
65 {
66 accountingAddFD(cbmap, fd, toDo, parameter);
67
68 if(port_associate(d_portfd, PORT_SOURCE_FD, fd, (&cbmap == &d_readCallbacks) ? POLLIN : POLLOUT, 0) < 0) {
69 cbmap.erase(fd);
70 throw FDMultiplexerException("Adding fd to port set: "+stringerror());
71 }
72 }
73
74 void PortsFDMultiplexer::removeFD(callbackmap_t& cbmap, int fd)
75 {
76 if(!cbmap.erase(fd))
77 throw FDMultiplexerException("Tried to remove unlisted fd "+std::to_string(fd)+ " from multiplexer");
78
79 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"
80 throw FDMultiplexerException("Removing fd from port set: "+stringerror());
81 }
82
83 int PortsFDMultiplexer::run(struct timeval* now)
84 {
85 if(d_inrun) {
86 throw FDMultiplexerException("FDMultiplexer::run() is not reentrant!\n");
87 }
88
89 struct timespec timeout;
90 timeout.tv_sec=0; timeout.tv_nsec=500000000;
91 unsigned int numevents=1;
92 int ret= port_getn(d_portfd, d_pevents.get(), min(PORT_MAX_LIST, s_maxevents), &numevents, &timeout);
93
94 /* port_getn has an unusual API - (ret == -1, errno == ETIME) can
95 mean partial success; you must check (*numevents) in this case
96 and process anything in there, otherwise you'll never see any
97 events from that object again. We don't care about pure timeouts
98 (ret == -1, errno == ETIME, *numevents == 0) so we don't bother
99 with that case. */
100 if(ret == -1 && errno!=ETIME) {
101 if(errno!=EINTR)
102 throw FDMultiplexerException("completion port_getn returned error: "+stringerror());
103 // EINTR is not really an error
104 gettimeofday(now,0);
105 return 0;
106 }
107 gettimeofday(now,0);
108 if(!numevents) // nothing
109 return 0;
110
111 d_inrun=true;
112
113 for(unsigned int n=0; n < numevents; ++n) {
114 d_iter=d_readCallbacks.find(d_pevents[n].portev_object);
115
116 if(d_iter != d_readCallbacks.end()) {
117 d_iter->second.d_callback(d_iter->first, d_iter->second.d_parameter);
118 if(d_readCallbacks.count(d_pevents[n].portev_object) && port_associate(d_portfd, PORT_SOURCE_FD, d_pevents[n].portev_object,
119 POLLIN, 0) < 0)
120 throw FDMultiplexerException("Unable to add fd back to ports (read): "+stringerror());
121 continue; // so we don't find ourselves as writable again
122 }
123
124 d_iter=d_writeCallbacks.find(d_pevents[n].portev_object);
125
126 if(d_iter != d_writeCallbacks.end()) {
127 d_iter->second.d_callback(d_iter->first, d_iter->second.d_parameter);
128 if(d_writeCallbacks.count(d_pevents[n].portev_object) && port_associate(d_portfd, PORT_SOURCE_FD, d_pevents[n].portev_object,
129 POLLOUT, 0) < 0)
130 throw FDMultiplexerException("Unable to add fd back to ports (write): "+stringerror());
131 }
132
133 }
134
135 d_inrun=false;
136 return 0;
137 }
138
139 #if 0
140 void acceptData(int fd, boost::any& parameter)
141 {
142 cout<<"Have data on fd "<<fd<<endl;
143 Socket* sock=boost::any_cast<Socket*>(parameter);
144 string packet;
145 IPEndpoint rem;
146 sock->recvFrom(packet, rem);
147 cout<<"Received "<<packet.size()<<" bytes!\n";
148 }
149
150
151 int main()
152 {
153 Socket s(AF_INET, SOCK_DGRAM);
154
155 IPEndpoint loc("0.0.0.0", 2000);
156 s.bind(loc);
157
158 PortsFDMultiplexer sfm;
159
160 sfm.addReadFD(s.getHandle(), &acceptData, &s);
161
162 for(int n=0; n < 100 ; ++n) {
163 sfm.run();
164 }
165 sfm.removeReadFD(s.getHandle());
166 sfm.removeReadFD(s.getHandle());
167 }
168 #endif
169
170