]>
git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/portsmplexer.cc
1 #if defined(__sun__) && defined(__svr4__)
6 #include <sys/port_impl.h>
14 #include <boost/lexical_cast.hpp>
17 #include "namespaces.hh"
18 #include "namespaces.hh"
20 class PortsFDMultiplexer
: public FDMultiplexer
24 virtual ~ PortsFDMultiplexer ()
29 virtual int run ( struct timeval
* tv
);
31 virtual void addFD ( callbackmap_t
& cbmap
, int fd
, callbackfunc_t toDo
, const boost :: any
& parameter
);
32 virtual void removeFD ( callbackmap_t
& cbmap
, int fd
);
35 return "solaris completion ports" ;
39 boost :: shared_array
< port_event_t
> d_pevents
;
40 static int s_maxevents
; // not a hard maximum
44 static FDMultiplexer
* makePorts ()
46 return new PortsFDMultiplexer ();
49 static struct PortsRegisterOurselves
51 PortsRegisterOurselves () {
52 FDMultiplexer :: getMultiplexerMap (). insert ( make_pair ( 0 , & makePorts
)); // priority 0!
57 int PortsFDMultiplexer :: s_maxevents
= 1024 ;
58 PortsFDMultiplexer :: PortsFDMultiplexer () : d_pevents ( new port_event_t
[ s_maxevents
])
60 d_portfd
= port_create (); // not hard max
62 throw FDMultiplexerException ( "Setting up port: " + stringerror ());
65 void PortsFDMultiplexer :: addFD ( callbackmap_t
& cbmap
, int fd
, callbackfunc_t toDo
, const boost :: any
& parameter
)
67 accountingAddFD ( cbmap
, fd
, toDo
, parameter
);
69 if ( port_associate ( d_portfd
, PORT_SOURCE_FD
, fd
, (& cbmap
== & d_readCallbacks
) ? POLLIN
: POLLOUT
, 0 ) < 0 ) {
71 throw FDMultiplexerException ( "Adding fd to port set: " + stringerror ());
75 void PortsFDMultiplexer :: removeFD ( callbackmap_t
& cbmap
, int fd
)
78 throw FDMultiplexerException ( "Tried to remove unlisted fd " + lexical_cast
< string
>( fd
)+ " from multiplexer" );
80 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"
81 throw FDMultiplexerException ( "Removing fd from port set: " + stringerror ());
84 int PortsFDMultiplexer :: run ( struct timeval
* now
)
87 throw FDMultiplexerException ( "FDMultiplexer::run() is not reentrant! \n " );
90 struct timespec timeout
;
91 timeout
. tv_sec
= 0 ; timeout
. tv_nsec
= 500000000 ;
92 unsigned int numevents
= 1 ;
93 int ret
= port_getn ( d_portfd
, d_pevents
. get (), min ( PORT_MAX_LIST
, s_maxevents
), & numevents
, & timeout
);
95 /* port_getn has an unusual API - (ret == -1, errno == ETIME) can
96 mean partial success; you must check (*numevents) in this case
97 and process anything in there, otherwise you'll never see any
98 events from that object again. We don't care about pure timeouts
99 (ret == -1, errno == ETIME, *numevents == 0) so we don't bother
101 if ( ret
== - 1 && errno
!= ETIME
) {
103 throw FDMultiplexerException ( "completion port_getn returned error: " + stringerror ());
104 // EINTR is not really an error
109 if (! numevents
) // nothing
114 for ( unsigned int n
= 0 ; n
< numevents
; ++ n
) {
115 d_iter
= d_readCallbacks
. find ( d_pevents
[ n
]. portev_object
);
117 if ( d_iter
!= d_readCallbacks
. end ()) {
118 d_iter
-> second
. d_callback ( d_iter
-> first
, d_iter
-> second
. d_parameter
);
119 if ( d_readCallbacks
. count ( d_pevents
[ n
]. portev_object
) && port_associate ( d_portfd
, PORT_SOURCE_FD
, d_pevents
[ n
]. portev_object
,
121 throw FDMultiplexerException ( "Unable to add fd back to ports (read): " + stringerror ());
122 continue ; // so we don't find ourselves as writable again
125 d_iter
= d_writeCallbacks
. find ( d_pevents
[ n
]. portev_object
);
127 if ( d_iter
!= d_writeCallbacks
. end ()) {
128 d_iter
-> second
. d_callback ( d_iter
-> first
, d_iter
-> second
. d_parameter
);
129 if ( d_writeCallbacks
. count ( d_pevents
[ n
]. portev_object
) && port_associate ( d_portfd
, PORT_SOURCE_FD
, d_pevents
[ n
]. portev_object
,
131 throw FDMultiplexerException ( "Unable to add fd back to ports (write): " + stringerror ());
141 void acceptData ( int fd
, boost :: any
& parameter
)
143 cout
<< "Have data on fd " << fd
<< endl
;
144 Socket
* sock
= boost :: any_cast
< Socket
*>( parameter
);
147 sock
-> recvFrom ( packet
, rem
);
148 cout
<< "Received " << packet
. size ()<< " bytes! \n " ;
154 Socket
s ( AF_INET
, SOCK_DGRAM
);
156 IPEndpoint
loc ( "0.0.0.0" , 2000 );
159 PortsFDMultiplexer sfm
;
161 sfm
. addReadFD ( s
. getHandle (), & acceptData
, & s
);
163 for ( int n
= 0 ; n
< 100 ; ++ n
) {
166 sfm
. removeReadFD ( s
. getHandle ());
167 sfm
. removeReadFD ( s
. getHandle ());