]>
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
)
150 InRun
guard ( d_inrun
);
152 struct timespec timeoutspec
;
153 timeoutspec
. tv_sec
= timeout
/ 1000 ;
154 timeoutspec
. tv_nsec
= ( timeout
% 1000 ) * 1000000 ;
155 unsigned int numevents
= 1 ;
156 int ret
= port_getn ( d_portfd
, d_pevents
. data (), min ( PORT_MAX_LIST
, static_cast < int >( d_pevents
. size ())), & numevents
, timeout
!= - 1 ? & timeoutspec
: nullptr );
158 /* port_getn has an unusual API - (ret == -1, errno == ETIME) can
159 mean partial success; you must check (*numevents) in this case
160 and process anything in there, otherwise you'll never see any
161 events from that object again. We don't care about pure timeouts
162 (ret == -1, errno == ETIME, *numevents == 0) so we don't bother
164 if ( ret
== - 1 && errno
!= ETIME
) {
165 if ( errno
!= EINTR
) {
166 throw FDMultiplexerException ( "completion port_getn returned error: " + stringerror ());
168 // EINTR is not really an error
169 gettimeofday ( now
, nullptr );
172 gettimeofday ( now
, nullptr );
179 for ( unsigned int n
= 0 ; n
< numevents
; ++ n
) {
180 if ( d_pevents
[ n
]. portev_events
& POLLIN
|| d_pevents
[ n
]. portev_events
& POLLERR
|| d_pevents
[ n
]. portev_events
& POLLHUP
) {
181 const auto & iter
= d_readCallbacks
. find ( d_pevents
[ n
]. portev_object
);
182 if ( iter
!= d_readCallbacks
. end ()) {
183 iter
-> d_callback ( iter
-> d_fd
, iter
-> d_parameter
);
185 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 ) {
186 throw FDMultiplexerException ( "Unable to add fd back to ports (read): " + stringerror ());
190 if ( d_pevents
[ n
]. portev_events
& POLLOUT
|| d_pevents
[ n
]. portev_events
& POLLERR
) {
191 const auto & iter
= d_writeCallbacks
. find ( d_pevents
[ n
]. portev_object
);
192 if ( iter
!= d_writeCallbacks
. end ()) {
193 iter
-> d_callback ( iter
-> d_fd
, iter
-> d_parameter
);
195 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 ) {
196 throw FDMultiplexerException ( "Unable to add fd back to ports (write): " + stringerror ());
206 void acceptData ( int fd
, boost :: any
& parameter
)
208 cout
<< "Have data on fd " << fd
<< endl
;
209 Socket
* sock
= boost :: any_cast
< Socket
*>( parameter
);
212 sock
-> recvFrom ( packet
, rem
);
213 cout
<< "Received " << packet
. size ()<< " bytes! \n " ;
219 Socket
s ( AF_INET
, SOCK_DGRAM
);
221 IPEndpoint
loc ( "0.0.0.0" , 2000 );
224 PortsFDMultiplexer sfm
;
226 sfm
. addReadFD ( s
. getHandle (), & acceptData
, & s
);
228 for ( int n
= 0 ; n
< 100 ; ++ n
) {
231 sfm
. removeReadFD ( s
. getHandle ());
232 sfm
. removeReadFD ( s
. getHandle ());