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