2022-01-24 03:28:16 +00:00
# include "lerror.h"
# include "lmem.h"
# include "lpolllist.h"
typedef struct sLaika_hashMapElem {
SOCKET fd ;
struct sLaika_socket * sock ;
} tLaika_hashMapElem ;
int elem_compare ( const void * a , const void * b , void * udata ) {
const tLaika_hashMapElem * ua = a ;
const tLaika_hashMapElem * ub = b ;
return ua - > fd ! = ub - > fd ;
}
uint64_t elem_hash ( const void * item , uint64_t seed0 , uint64_t seed1 ) {
const tLaika_hashMapElem * u = item ;
return ( uint64_t ) ( u - > fd ) ;
}
void laikaP_initPList ( struct sLaika_pollList * pList ) {
laikaS_init ( ) ;
/* setup hashmap */
pList - > sockets = hashmap_new ( sizeof ( tLaika_hashMapElem ) , POLLSTARTCAP , 0 , 0 , elem_hash , elem_compare , NULL , NULL ) ;
pList - > revents = NULL ; /* laikaP_pollList() will allocate the buffer */
2022-02-14 05:55:30 +00:00
pList - > reventCap = POLLSTARTCAP / GROW_FACTOR ;
2022-01-24 03:28:16 +00:00
pList - > reventCount = 0 ;
2022-02-14 05:55:30 +00:00
pList - > outQueue = NULL ;
pList - > outCap = POLLSTARTCAP / GROW_FACTOR ;
pList - > outCount = 0 ;
2022-01-24 03:28:16 +00:00
# ifdef LAIKA_USE_EPOLL
/* setup our epoll */
memset ( & pList - > ev , 0 , sizeof ( struct epoll_event ) ) ;
if ( ( pList - > epollfd = epoll_create ( POLLSTARTCAP ) ) = = - 1 )
2022-01-25 03:46:29 +00:00
LAIKA_ERROR ( " epoll_create() failed! \n " ) ;
2022-01-24 03:28:16 +00:00
# else
pList - > fds = NULL ; /* laikaP_addSock will allocate the buffer */
pList - > fdCapacity = POLLSTARTCAP / GROW_FACTOR ; /* div by GROW_FACTOR since laikaM_growarray multiplies by GROW_FACTOR */
pList - > fdCount = 0 ;
# endif
}
void laikaP_cleanPList ( struct sLaika_pollList * pList ) {
laikaM_free ( pList - > revents ) ;
2022-02-14 05:55:30 +00:00
laikaM_free ( pList - > outQueue ) ;
2022-01-29 23:00:44 +00:00
hashmap_free ( pList - > sockets ) ;
2022-01-24 03:28:16 +00:00
# ifdef LAIKA_USE_EPOLL
close ( pList - > epollfd ) ;
# else
laikaM_free ( pList - > fds ) ;
# endif
laikaS_cleanUp ( ) ;
}
void laikaP_addSock ( struct sLaika_pollList * pList , struct sLaika_socket * sock ) {
/* add socket to hashmap */
hashmap_set ( pList - > sockets , & ( tLaika_hashMapElem ) { . fd = sock - > sock , . sock = sock } ) ;
# ifdef LAIKA_USE_EPOLL
pList - > ev . events = EPOLLIN ;
pList - > ev . data . ptr = ( void * ) sock ;
if ( epoll_ctl ( pList - > epollfd , EPOLL_CTL_ADD , sock - > sock , & pList - > ev ) = = - 1 )
2022-01-25 03:46:29 +00:00
LAIKA_ERROR ( " epoll_ctl [ADD] failed \n " ) ;
2022-01-24 03:28:16 +00:00
# else
/* allocate space in array & add PollFD */
2022-01-28 01:55:28 +00:00
laikaM_growarray ( PollFD , pList - > fds , 1 , pList - > fdCount , pList - > fdCapacity ) ;
2022-01-24 03:28:16 +00:00
pList - > fds [ pList - > fdCount + + ] = ( PollFD ) { sock - > sock , POLLIN } ;
# endif
}
void laikaP_rmvSock ( struct sLaika_pollList * pList , struct sLaika_socket * sock ) {
2022-02-14 06:22:36 +00:00
int i ;
2022-01-24 03:28:16 +00:00
/* remove socket from hashmap */
hashmap_delete ( pList - > sockets , & ( tLaika_hashMapElem ) { . fd = sock - > sock , . sock = sock } ) ;
2022-02-14 06:22:36 +00:00
/* make sure peer isn't in outQueue */
for ( i = 0 ; i < pList - > outCount ; i + + ) {
if ( ( void * ) pList - > outQueue [ i ] = = ( void * ) sock ) {
laikaM_rmvarray ( pList - > outQueue , pList - > outCount , i , 1 ) ;
}
}
2022-01-24 03:28:16 +00:00
# ifdef LAIKA_USE_EPOLL
/* epoll_event* isn't needed with EPOLL_CTL_DEL, however we still need to pass a NON-NULL pointer. [see: https://man7.org/linux/man-pages/man2/epoll_ctl.2.html#BUGS] */
if ( epoll_ctl ( pList - > epollfd , EPOLL_CTL_DEL , sock - > sock , & pList - > ev ) = = - 1 ) {
/* non-fatal error, socket probably just didn't exist, so ignore it. */
2022-01-25 03:46:29 +00:00
LAIKA_WARN ( " epoll_ctl [DEL] failed \n " ) ;
2022-01-24 03:28:16 +00:00
}
# else
int i ;
/* search fds for socket, remove it and shrink array */
for ( i = 0 ; i < pList - > fdCount ; i + + ) {
if ( pList - > fds [ i ] . fd = = sock - > sock ) {
/* remove from array */
2022-01-31 21:54:39 +00:00
laikaM_rmvarray ( pList - > fds , pList - > fdCount , i , 1 ) ;
2022-01-24 03:28:16 +00:00
break ;
}
}
# endif
}
void laikaP_addPollOut ( struct sLaika_pollList * pList , struct sLaika_socket * sock ) {
# ifdef LAIKA_USE_EPOLL
pList - > ev . events = EPOLLIN | EPOLLOUT ;
pList - > ev . data . ptr = ( void * ) sock ;
if ( epoll_ctl ( pList - > epollfd , EPOLL_CTL_MOD , sock - > sock , & pList - > ev ) = = - 1 ) {
/* non-fatal error, socket probably just didn't exist, so ignore it. */
2022-01-25 03:46:29 +00:00
LAIKA_WARN ( " epoll_ctl [MOD] failed \n " ) ;
2022-01-24 03:28:16 +00:00
}
# else
int i ;
/* search fds for socket, add POLLOUT flag */
for ( i = 0 ; i < pList - > fdCount ; i + + ) {
if ( pList - > fds [ i ] . fd = = sock - > sock ) {
pList - > fds [ i ] . events = POLLIN | POLLOUT ;
break ;
}
}
# endif
}
void laikaP_rmvPollOut ( struct sLaika_pollList * pList , struct sLaika_socket * sock ) {
# ifdef LAIKA_USE_EPOLL
pList - > ev . events = EPOLLIN ;
pList - > ev . data . ptr = ( void * ) sock ;
if ( epoll_ctl ( pList - > epollfd , EPOLL_CTL_MOD , sock - > sock , & pList - > ev ) = = - 1 ) {
/* non-fatal error, socket probably just didn't exist, so ignore it. */
2022-01-25 03:46:29 +00:00
LAIKA_WARN ( " epoll_ctl [MOD] failed \n " ) ;
2022-01-24 03:28:16 +00:00
}
# else
int i ;
/* search fds for socket, remove POLLOUT flag */
for ( i = 0 ; i < pList - > fdCount ; i + + ) {
if ( pList - > fds [ i ] . fd = = sock - > sock ) {
pList - > fds [ i ] . events = POLLIN ;
break ;
}
}
# endif
}
2022-02-14 05:55:30 +00:00
void laikaP_pushOutQueue ( struct sLaika_pollList * pList , struct sLaika_peer * peer ) {
int i ;
/* first, check that we don't have this peer in the queue already */
for ( i = 0 ; i < pList - > outCount ; i + + ) {
if ( pList - > outQueue [ i ] = = peer )
return ; /* found it :) */
}
laikaM_growarray ( struct sLaika_peer * , pList - > outQueue , 1 , pList - > outCount , pList - > outCap ) ;
pList - > outQueue [ pList - > outCount + + ] = peer ;
}
void laikaP_resetOutQueue ( struct sLaika_pollList * pList ) {
pList - > outCount = 0 ; /* ez lol */
}
2022-01-24 03:28:16 +00:00
struct sLaika_pollEvent * laikaP_poll ( struct sLaika_pollList * pList , int timeout , int * _nevents ) {
int nEvents , i ;
pList - > reventCount = 0 ; /* reset revent array */
# ifdef LAIKA_USE_EPOLL
/* fastpath: we store the sLaika_socket* pointer directly in the epoll_data_t, saving us a lookup into our socket hashmap
not to mention the various improvements epoll ( ) has over poll ( ) : D
*/
nEvents = epoll_wait ( pList - > epollfd , pList - > ep_events , MAX_EPOLL_EVENTS , timeout ) ;
if ( SOCKETERROR ( nEvents ) )
2022-01-25 03:46:29 +00:00
LAIKA_ERROR ( " epoll_wait() failed! \n " ) ;
2022-01-24 03:28:16 +00:00
for ( i = 0 ; i < nEvents ; i + + ) {
/* add event to revent array */
2022-02-14 05:55:30 +00:00
laikaM_growarray ( struct sLaika_pollEvent , pList - > revents , 1 , pList - > reventCount , pList - > reventCap ) ;
2022-01-24 03:28:16 +00:00
pList - > revents [ pList - > reventCount + + ] = ( struct sLaika_pollEvent ) {
. sock = pList - > ep_events [ i ] . data . ptr ,
. pollIn = pList - > ep_events [ i ] . events & EPOLLIN ,
. pollOut = pList - > ep_events [ i ] . events & EPOLLOUT
} ;
}
# else
nEvents = poll ( pList - > fds , pList - > fdCount , timeout ) ; /* poll returns -1 for error, or the number of events */
if ( SOCKETERROR ( nEvents ) )
2022-01-25 03:46:29 +00:00
LAIKA_ERROR ( " poll() failed! \n " ) ;
2022-01-24 03:28:16 +00:00
/* walk through the returned poll fds, if they have an event, add it to our revents array */
for ( i = 0 ; i < pList - > fdCount & & nEvents > 0 ; i + + ) {
PollFD pfd = pList - > fds [ i ] ;
if ( pList - > fds [ i ] . revents ! = 0 ) {
/* grab socket from hashmap */
2022-01-31 21:54:39 +00:00
tLaika_hashMapElem * elem = ( tLaika_hashMapElem * ) hashmap_get ( pList - > sockets , & ( tLaika_hashMapElem ) { . fd = ( SOCKET ) pfd . fd } ) ;
2022-01-24 03:28:16 +00:00
/* insert event into revents array */
2022-02-14 05:55:30 +00:00
laikaM_growarray ( struct sLaika_pollEvent , pList - > revents , 1 , pList - > reventCount , pList - > reventCap ) ;
2022-01-24 03:28:16 +00:00
pList - > revents [ pList - > reventCount + + ] = ( struct sLaika_pollEvent ) {
2022-01-31 21:54:39 +00:00
. sock = elem - > sock ,
2022-01-24 03:28:16 +00:00
. pollIn = pfd . revents & POLLIN ,
. pollOut = pfd . revents & POLLOUT
} ;
nEvents - - ;
}
}
# endif
2022-01-31 21:54:39 +00:00
* _nevents = pList - > reventCount ;
2022-01-24 03:28:16 +00:00
/* return revents array */
return pList - > revents ;
2022-02-10 22:56:40 +00:00
}