]>
git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/portsmplexer.cc
1 #if defined(__sun__) && defined(__svr4__)
6 #include <sys/port_impl.h>
15 #include "namespaces.hh"
17 class PortsFDMultiplexer
: public FDMultiplexer
20 PortsFDMultiplexer ( unsigned int maxEventsHint
);
26 int run ( struct timeval
* tv
, int timeout
= 500 ) override
;
27 void getAvailableFDs ( std :: vector
< int >& fds
, int timeout
) override
;
29 void addFD ( int fd
, FDMultiplexer :: EventKind kind
) override
;
30 void removeFD ( int fd
, FDMultiplexer :: EventKind kind
) override
;
32 string
getName () const override
34 return "solaris completion ports" ;
39 std :: vector
< port_event_t
> d_pevents
;
42 static FDMultiplexer
* makePorts ( unsigned int maxEventsHint
)
44 return new PortsFDMultiplexer ( maxEventsHint
);
47 static struct PortsRegisterOurselves
49 PortsRegisterOurselves ()
51 FDMultiplexer :: getMultiplexerMap (). emplace ( 0 , & makePorts
); // priority 0!
55 PortsFDMultiplexer :: PortsFDMultiplexer ( unsigned int maxEventsHint
) :
56 d_pevents ( maxEventsHint
)
58 d_portfd
= port_create (); // not hard max
60 throw FDMultiplexerException ( "Setting up port: " + stringerror ());
64 static int convertEventKind ( FDMultiplexer :: EventKind kind
)
67 case FDMultiplexer :: EventKind :: Read
:
69 case FDMultiplexer :: EventKind :: Write
:
71 case FDMultiplexer :: EventKind :: Both
:
72 return POLLIN
| POLLOUT
;
74 throw std :: runtime_error ( "Unhandled event kind in the ports multiplexer" );
77 void PortsFDMultiplexer :: addFD ( int fd
, FDMultiplexer :: EventKind kind
)
79 if ( port_associate ( d_portfd
, PORT_SOURCE_FD
, fd
, convertEventKind ( kind
), 0 ) < 0 ) {
80 throw FDMultiplexerException ( "Adding fd to port set: " + stringerror ());
84 void PortsFDMultiplexer :: removeFD ( int fd
, FDMultiplexer :: EventKind
)
86 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"
87 throw FDMultiplexerException ( "Removing fd from port set: " + stringerror ());
91 void PortsFDMultiplexer :: getAvailableFDs ( std :: vector
< int >& fds
, int timeout
)
93 struct timespec timeoutspec
;
94 timeoutspec
. tv_sec
= timeout
/ 1000 ;
95 timeoutspec
. tv_nsec
= ( timeout
% 1000 ) * 1000000 ;
96 unsigned int numevents
= 1 ;
97 int ret
= port_getn ( d_portfd
, d_pevents
. data (), min ( PORT_MAX_LIST
, static_cast < int >( d_pevents
. size ())), & numevents
, timeout
!= - 1 ? & timeoutspec
: nullptr );
99 /* port_getn has an unusual API - (ret == -1, errno == ETIME) can
100 mean partial success; you must check (*numevents) in this case
101 and process anything in there, otherwise you'll never see any
102 events from that object again. We don't care about pure timeouts
103 (ret == -1, errno == ETIME, *numevents == 0) so we don't bother
105 if ( ret
== - 1 && errno
!= ETIME
) {
106 if ( errno
!= EINTR
) {
107 throw FDMultiplexerException ( "completion port_getn returned error: " + stringerror ());
110 // EINTR is not really an error
114 if ( numevents
== 0 ) {
119 fds
. reserve ( numevents
);
121 for ( unsigned int n
= 0 ; n
< numevents
; ++ n
) {
122 const auto fd
= d_pevents
[ n
]. portev_object
;
124 /* we need to re-associate the FD */
125 if (( d_pevents
[ n
]. portev_events
& POLLIN
|| d_pevents
[ n
]. portev_events
& POLLERR
|| d_pevents
[ n
]. portev_events
& POLLHUP
)) {
126 if ( d_readCallbacks
. count ( fd
)) {
127 if ( port_associate ( d_portfd
, PORT_SOURCE_FD
, fd
, d_writeCallbacks
. count ( fd
) > 0 ? POLLIN
| POLLOUT
: POLLIN
, 0 ) < 0 ) {
128 throw FDMultiplexerException ( "Unable to add fd back to ports (read): " + stringerror ());
132 else if (( d_pevents
[ n
]. portev_events
& POLLOUT
|| d_pevents
[ n
]. portev_events
& POLLERR
)) {
133 if ( d_writeCallbacks
. count ( fd
)) {
134 if ( port_associate ( d_portfd
, PORT_SOURCE_FD
, fd
, d_readCallbacks
. count ( fd
) > 0 ? POLLIN
| POLLOUT
: POLLOUT
, 0 ) < 0 ) {
135 throw FDMultiplexerException ( "Unable to add fd back to ports (write): " + stringerror ());
140 /* not registered, this is unexpected */
148 int PortsFDMultiplexer :: run ( struct timeval
* now
, int timeout
)
151 throw FDMultiplexerException ( "FDMultiplexer::run() is not reentrant! \n " );
154 struct timespec timeoutspec
;
155 timeoutspec
. tv_sec
= timeout
/ 1000 ;
156 timeoutspec
. tv_nsec
= ( timeout
% 1000 ) * 1000000 ;
157 unsigned int numevents
= 1 ;
158 int ret
= port_getn ( d_portfd
, d_pevents
. data (), min ( PORT_MAX_LIST
, static_cast < int >( d_pevents
. size ())), & numevents
, timeout
!= - 1 ? & timeoutspec
: nullptr );
160 /* port_getn has an unusual API - (ret == -1, errno == ETIME) can
161 mean partial success; you must check (*numevents) in this case
162 and process anything in there, otherwise you'll never see any
163 events from that object again. We don't care about pure timeouts
164 (ret == -1, errno == ETIME, *numevents == 0) so we don't bother
166 if ( ret
== - 1 && errno
!= ETIME
) {
167 if ( errno
!= EINTR
) {
168 throw FDMultiplexerException ( "completion port_getn returned error: " + stringerror ());
170 // EINTR is not really an error
171 gettimeofday ( now
, nullptr );
174 gettimeofday ( now
, nullptr );
182 for ( unsigned int n
= 0 ; n
< numevents
; ++ n
) {
183 if ( d_pevents
[ n
]. portev_events
& POLLIN
|| d_pevents
[ n
]. portev_events
& POLLERR
|| d_pevents
[ n
]. portev_events
& POLLHUP
) {
184 const auto & iter
= d_readCallbacks
. find ( d_pevents
[ n
]. portev_object
);
185 if ( iter
!= d_readCallbacks
. end ()) {
186 iter
-> d_callback ( iter
-> d_fd
, iter
-> d_parameter
);
188 if ( d_readCallbacks
. count ( d_pevents
[ n
]. portev_object
) && port_associate ( d_portfd
, PORT_SOURCE_FD
, d_pevents
[ n
]. portev_object
, d_writeCallbacks
. count ( d_pevents
[ n
]. portev_object
) ? POLLIN
| POLLOUT
: POLLIN
, 0 ) < 0 ) {
189 throw FDMultiplexerException ( "Unable to add fd back to ports (read): " + stringerror ());
193 if ( d_pevents
[ n
]. portev_events
& POLLOUT
|| d_pevents
[ n
]. portev_events
& POLLERR
) {
194 const auto & iter
= d_writeCallbacks
. find ( d_pevents
[ n
]. portev_object
);
195 if ( iter
!= d_writeCallbacks
. end ()) {
196 iter
-> d_callback ( iter
-> d_fd
, iter
-> d_parameter
);
198 if ( d_writeCallbacks
. count ( d_pevents
[ n
]. portev_object
) && port_associate ( d_portfd
, PORT_SOURCE_FD
, d_pevents
[ n
]. portev_object
, d_readCallbacks
. count ( d_pevents
[ n
]. portev_object
) ? POLLIN
| POLLOUT
: POLLOUT
, 0 ) < 0 ) {
199 throw FDMultiplexerException ( "Unable to add fd back to ports (write): " + stringerror ());
210 void acceptData ( int fd
, boost :: any
& parameter
)
212 cout
<< "Have data on fd " << fd
<< endl
;
213 Socket
* sock
= boost :: any_cast
< Socket
*>( parameter
);
216 sock
-> recvFrom ( packet
, rem
);
217 cout
<< "Received " << packet
. size ()<< " bytes! \n " ;
223 Socket
s ( AF_INET
, SOCK_DGRAM
);
225 IPEndpoint
loc ( "0.0.0.0" , 2000 );
228 PortsFDMultiplexer sfm
;
230 sfm
. addReadFD ( s
. getHandle (), & acceptData
, & s
);
232 for ( int n
= 0 ; n
< 100 ; ++ n
) {
235 sfm
. removeReadFD ( s
. getHandle ());
236 sfm
. removeReadFD ( s
. getHandle ());