]>
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
21 virtual ~ PortsFDMultiplexer ()
26 virtual int run ( struct timeval
* tv
, int timeout
= 500 );
28 virtual void addFD ( callbackmap_t
& cbmap
, int fd
, callbackfunc_t toDo
, const boost :: any
& parameter
, const struct timeval
* ttd
= nullptr );
29 virtual void removeFD ( callbackmap_t
& cbmap
, int fd
);
32 return "solaris completion ports" ;
36 boost :: shared_array
< port_event_t
> d_pevents
;
37 static int s_maxevents
; // not a hard maximum
41 static FDMultiplexer
* makePorts ()
43 return new PortsFDMultiplexer ();
46 static struct PortsRegisterOurselves
48 PortsRegisterOurselves () {
49 FDMultiplexer :: getMultiplexerMap (). insert ( make_pair ( 0 , & makePorts
)); // priority 0!
54 int PortsFDMultiplexer :: s_maxevents
= 1024 ;
55 PortsFDMultiplexer :: PortsFDMultiplexer () : d_pevents ( new port_event_t
[ s_maxevents
])
57 d_portfd
= port_create (); // not hard max
59 throw FDMultiplexerException ( "Setting up port: " + stringerror ());
62 void PortsFDMultiplexer :: addFD ( callbackmap_t
& cbmap
, int fd
, callbackfunc_t toDo
, const boost :: any
& parameter
, const struct timeval
* ttd
)
64 accountingAddFD ( cbmap
, fd
, toDo
, parameter
, ttd
);
66 if ( port_associate ( d_portfd
, PORT_SOURCE_FD
, fd
, (& cbmap
== & d_readCallbacks
) ? POLLIN
: POLLOUT
, 0 ) < 0 ) {
68 throw FDMultiplexerException ( "Adding fd to port set: " + stringerror ());
72 void PortsFDMultiplexer :: removeFD ( callbackmap_t
& cbmap
, int fd
)
75 throw FDMultiplexerException ( "Tried to remove unlisted fd " + std :: to_string ( fd
)+ " from multiplexer" );
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 ());
81 int PortsFDMultiplexer :: run ( struct timeval
* now
, int timeout
)
84 throw FDMultiplexerException ( "FDMultiplexer::run() is not reentrant! \n " );
87 struct timespec timeoutspec
;
88 timeoutspec
. tv_sec
= time
/ 1000 ;
89 timeoutspec
. tv_nsec
= ( time
% 1000 ) * 1000000 ;
90 unsigned int numevents
= 1 ;
91 int ret
= port_getn ( d_portfd
, d_pevents
. get (), min ( PORT_MAX_LIST
, s_maxevents
), & numevents
, & timeoutspec
);
93 /* port_getn has an unusual API - (ret == -1, errno == ETIME) can
94 mean partial success; you must check (*numevents) in this case
95 and process anything in there, otherwise you'll never see any
96 events from that object again. We don't care about pure timeouts
97 (ret == -1, errno == ETIME, *numevents == 0) so we don't bother
99 if ( ret
== - 1 && errno
!= ETIME
) {
101 throw FDMultiplexerException ( "completion port_getn returned error: " + stringerror ());
102 // EINTR is not really an error
107 if (! numevents
) // nothing
112 for ( unsigned int n
= 0 ; n
< numevents
; ++ n
) {
113 d_iter
= d_readCallbacks
. find ( d_pevents
[ n
]. portev_object
);
115 if ( d_iter
!= d_readCallbacks
. end ()) {
116 d_iter
-> d_callback ( d_iter
-> d_fd
, d_iter
-> d_parameter
);
117 if ( d_readCallbacks
. count ( d_pevents
[ n
]. portev_object
) && port_associate ( d_portfd
, PORT_SOURCE_FD
, d_pevents
[ n
]. portev_object
,
119 throw FDMultiplexerException ( "Unable to add fd back to ports (read): " + stringerror ());
120 continue ; // so we don't find ourselves as writable again
123 d_iter
= d_writeCallbacks
. find ( d_pevents
[ n
]. portev_object
);
125 if ( d_iter
!= d_writeCallbacks
. end ()) {
126 d_iter
-> d_callback ( d_iter
-> d_fd
, d_iter
-> d_parameter
);
127 if ( d_writeCallbacks
. count ( d_pevents
[ n
]. portev_object
) && port_associate ( d_portfd
, PORT_SOURCE_FD
, d_pevents
[ n
]. portev_object
,
129 throw FDMultiplexerException ( "Unable to add fd back to ports (write): " + stringerror ());
139 void acceptData ( int fd
, boost :: any
& parameter
)
141 cout
<< "Have data on fd " << fd
<< endl
;
142 Socket
* sock
= boost :: any_cast
< Socket
*>( parameter
);
145 sock
-> recvFrom ( packet
, rem
);
146 cout
<< "Received " << packet
. size ()<< " bytes! \n " ;
152 Socket
s ( AF_INET
, SOCK_DGRAM
);
154 IPEndpoint
loc ( "0.0.0.0" , 2000 );
157 PortsFDMultiplexer sfm
;
159 sfm
. addReadFD ( s
. getHandle (), & acceptData
, & s
);
161 for ( int n
= 0 ; n
< 100 ; ++ n
) {
164 sfm
. removeReadFD ( s
. getHandle ());
165 sfm
. removeReadFD ( s
. getHandle ());