]>
git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/portsmplexer.cc
6 #include <boost/lexical_cast.hpp>
9 #if defined(__sun__) && defined(__svr4__)
11 #include <sys/port_impl.h>
14 #include "namespaces.hh"
17 class PortsFDMultiplexer
: public FDMultiplexer
21 virtual ~ PortsFDMultiplexer ()
26 virtual int run ( struct timeval
* tv
);
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
);
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
)
64 accountingAddFD ( cbmap
, fd
, toDo
, parameter
);
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 " + lexical_cast
< 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
)
84 throw FDMultiplexerException ( "FDMultiplexer::run() is not reentrant! \n " );
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
);
94 /* port_getn has an unusual API - (ret == -1, errno == ETIME) can
95 mean partial success; you must check (*numevents) in this case
96 and process anything in there, otherwise you'll never see any
97 events from that object again. We don't care about pure timeouts
98 (ret == -1, errno == ETIME, *numevents == 0) so we don't bother
100 if ( ret
< 0 && errno
!= ETIME
) {
102 throw FDMultiplexerException ( "completion port_getn returned error: " + stringerror ());
103 // 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
-> second
. d_callback ( d_iter
-> first
, d_iter
-> second
. 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
-> second
. d_callback ( d_iter
-> first
, d_iter
-> second
. 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 ( InterNetwork
, Datagram
);
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 ());