]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/portsmplexer.cc
fix enums in commented out code
[thirdparty/pdns.git] / pdns / portsmplexer.cc
1 #if defined(__sun__) && defined(__svr4__)
2 #include <port.h>
3 #include <sys/port_impl.h>
4 #endif
5 #include <unistd.h>
6 #include "mplexer.hh"
7 #include "sstuff.hh"
8 #include <iostream>
9
10 #include "misc.hh"
11 #include <boost/lexical_cast.hpp>
12 #include "syncres.hh"
13
14 #include "namespaces.hh"
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);
27
28 virtual void addFD(callbackmap_t& cbmap, int fd, callbackfunc_t toDo, const boost::any& parameter);
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)
63 {
64 accountingAddFD(cbmap, fd, toDo, parameter);
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 "+lexical_cast<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)
82 {
83 if(d_inrun) {
84 throw FDMultiplexerException("FDMultiplexer::run() is not reentrant!\n");
85 }
86
87 struct timespec timeout;
88 timeout.tv_sec=0; timeout.tv_nsec=500000000;
89 unsigned int numevents=1;
90 int ret= port_getn(d_portfd, d_pevents.get(), min(PORT_MAX_LIST, s_maxevents), &numevents, &timeout);
91
92 /* port_getn has an unusual API - (ret == -1, errno == ETIME) can
93 mean partial success; you must check (*numevents) in this case
94 and process anything in there, otherwise you'll never see any
95 events from that object again. We don't care about pure timeouts
96 (ret == -1, errno == ETIME, *numevents == 0) so we don't bother
97 with that case. */
98 if(ret == -1 && errno!=ETIME) {
99 if(errno!=EINTR)
100 throw FDMultiplexerException("completion port_getn returned error: "+stringerror());
101 // EINTR is not really an error
102 gettimeofday(now,0);
103 return 0;
104 }
105 gettimeofday(now,0);
106 if(!numevents) // nothing
107 return 0;
108
109 d_inrun=true;
110
111 for(unsigned int n=0; n < numevents; ++n) {
112 d_iter=d_readCallbacks.find(d_pevents[n].portev_object);
113
114 if(d_iter != d_readCallbacks.end()) {
115 d_iter->second.d_callback(d_iter->first, d_iter->second.d_parameter);
116 if(d_readCallbacks.count(d_pevents[n].portev_object) && port_associate(d_portfd, PORT_SOURCE_FD, d_pevents[n].portev_object,
117 POLLIN, 0) < 0)
118 throw FDMultiplexerException("Unable to add fd back to ports (read): "+stringerror());
119 continue; // so we don't find ourselves as writable again
120 }
121
122 d_iter=d_writeCallbacks.find(d_pevents[n].portev_object);
123
124 if(d_iter != d_writeCallbacks.end()) {
125 d_iter->second.d_callback(d_iter->first, d_iter->second.d_parameter);
126 if(d_writeCallbacks.count(d_pevents[n].portev_object) && port_associate(d_portfd, PORT_SOURCE_FD, d_pevents[n].portev_object,
127 POLLOUT, 0) < 0)
128 throw FDMultiplexerException("Unable to add fd back to ports (write): "+stringerror());
129 }
130
131 }
132
133 d_inrun=false;
134 return 0;
135 }
136
137 #if 0
138 void acceptData(int fd, boost::any& parameter)
139 {
140 cout<<"Have data on fd "<<fd<<endl;
141 Socket* sock=boost::any_cast<Socket*>(parameter);
142 string packet;
143 IPEndpoint rem;
144 sock->recvFrom(packet, rem);
145 cout<<"Received "<<packet.size()<<" bytes!\n";
146 }
147
148
149 int main()
150 {
151 Socket s(AF_INET, SOCK_DGRAM);
152
153 IPEndpoint loc("0.0.0.0", 2000);
154 s.bind(loc);
155
156 PortsFDMultiplexer sfm;
157
158 sfm.addReadFD(s.getHandle(), &acceptData, &s);
159
160 for(int n=0; n < 100 ; ++n) {
161 sfm.run();
162 }
163 sfm.removeReadFD(s.getHandle());
164 sfm.removeReadFD(s.getHandle());
165 }
166 #endif
167
168