src/server/listen.c
void *hearersListener( void *arg ){
	struct serverinfo *si = ( struct serverinfo * )arg;
	struct connserverinfo *csi = NULL; // Malloced each time a connection arrives
	struct twitpoollist_node *tpln = NULL; // used for the twitpoollist_node of each hearer
	pthread_t threadid; // Used for the threads created to handle the connections
	int connsockfd = -1; // The socket from each connection arriving
	struct listenerinfo li = {
		.li_serverinfo = si
	};

	assert( si != NULL );

	// Setup the listener
	// Setup the cleanup
	// POSIX says that pthread_cleanup_push() and pthread_cleanup_pop() must appear as statements
	// and in pairs within the same lexical scope so pthread_cleanup_push() must be put here
 	// and not in setupHearersListener()
	pthread_cleanup_push( &cleanupHearersListener, &li );
	setupHearersListener( &li );

	// Wait for connections
	while ( 1 ){
		// Do not accept any more connections if we are full of hearers
		acquire_statistics( si );
		assert( si->si_stats.stats_hearersNum <= HEARERS_MAXCOUNT );		
		while ( si->si_stats.stats_hearersNum == HEARERS_MAXCOUNT ){
			while ( pthread_cond_wait( &si->si_stats_hearers_cond, &si->si_stats_lock ) ){ continue; }
		}
		assert( si->si_stats.stats_hearersNum < SAYERS_MAXCOUNT );
		release_statistics( si );

		errno = 0;
		if ( ( connsockfd = accept( li.li_sockfd, NULL, NULL ) ) == -1 ){
			error( "accept() failed in hearersListener() (%s)\n", strerror( errno ) );
			continue;
		}
		// A connection arrived. Create a new struct connserverinfo object
 		// for the new thread
		errno = 0;
		if ( ( csi = malloc( sizeof( *csi ) ) ) == NULL ){
			error( "malloc() failed in hearersListener() (%s)\n", strerror( errno ) );
			// must close the socket here
			safe_close( connsockfd );
			continue;
		}
		
		// Acquire ownership of the twitpool list
		acquire_twitpool_list( si );
		errno = 0;
		// Create a twitpool for that hearer
		if ( newtwitpool( &si->si_twitpool_list, &tpln ) == -1  ){
			error( "newtwitpool() failed in hearersListener() (%s)\n", strerror( errno ) );
			// do cleanup work
			// close the socket
			safe_close( connsockfd );
			// free structure
			free( csi );

			// CAUTION: do **not** forget to unlock the list here
			// Release ownership of the twitpool list
			release_twitpool_list( si );

			continue;
		}
		// Release ownership of the twitpool list
		release_twitpool_list( si );

		csi->csi_serverinfo = si;
		csi->csi_sockfd = connsockfd;
		csi->csi_tpln = tpln;

		// CAUTION: the statistics must be locked before the thread is created cause in case the connection gets closed
		// before the nums are increased here and the created thread decreases the nums then we have an error.
 		// So lock the statistics beforehand to avoid any race condition		
		acquire_statistics( si );
		// Create the new thread to handle the connection
		if ( ( errno = pthread_create( &threadid, &li.li_threadattr, &hearerConnectionHandler, csi ) ) ){
			error( "pthread_create() failed in hearersListener() (%s)\n", strerror( errno ) );
			// must close the socket here
			safe_close( connsockfd );
			// note that if the thread failed to be created we must free the memory for csi here
			// otherwise, the thread must free the memory itself
			free( csi );

			// must also remove the twitpool created for the hearer
			( void )removefromtwitpoollist( &si->si_twitpool_list, tpln );
		}
		else{
			// Update the statistics that a new hearer was connected
			increaseHearersNum( &si->si_stats );
			increaseThreadsNum( &si->si_stats );
		}
		release_statistics( si );
	}

	// Perform cleanup
	pthread_cleanup_pop( 1 );

	// Not Reached
	pthread_exit( NULL );
}
/**
 * hearersListener() runs on its own thread and is responsible for accepting connections from hearers. 
 * The port to which the hearersListener() function will listen for hearers is obtained from config.h (HEARERS_PORT).
 * The steps the hearersListener() function takes are:
 *	1) The socket that will listen for hearers at the port HEARERS_PORT is created.
 *	2) If successfull (the above step) the hearersListener() function notifies through the serverinfo structure
 *	passed as parameter that is prepared.
 *	3) It waits for a connection from a hearer and if a connection arrives: 
 *		1) Start a new thread that handles the connection with the hearer hearerConnectionHandler().
 *		2) Update the statistics structure (a new hearer arrived).
 */
hearersListener() runs on its own thread and is responsible for accepting connections from hearers.
The port to which the hearersListener() function will listen for hearers is obtained from config.h (HEARERS_PORT).
The steps the hearersListener() function takes are:
1) The socket that will listen for hearers at the port HEARERS_PORT is created.
2) If successfull (the above step) the hearersListener() function notifies through the serverinfo structure
passed as parameter that is prepared.
3) It waits for a connection from a hearer and if a connection arrives:
1) Start a new thread that handles the connection with the hearer hearerConnectionHandler().
2) Update the statistics structure (a new hearer arrived).
hearersListener () runs on its own thread and is responsible for accepting connections from hearers . The port to which the hearersListener () function will listen for hearers is obtained from config . h ( HEARERS_PORT ) . The steps the hearersListener () function takes are : 1 ) The socket that will listen for hearers at the port HEARERS_PORT is created . 2 ) If successfull ( the above step ) the hearersListener () function notifies through the serverinfo structure passed as parameter that is prepared . 3 ) It waits for a connection from a hearer and if a connection arrives : 1 ) Start a new thread that handles the connection with the hearer hearerConnectionHandler () . 2 ) Update the statistics structure ( a new hearer arrived ) .
void *hearersListener( void *arg ){
	struct serverinfo *si = ( struct serverinfo * )arg;
	struct connserverinfo *csi = NULL; 
	struct twitpoollist_node *tpln = NULL; 
	pthread_t threadid; 
	int connsockfd = -1; 
	struct listenerinfo li = {
		.li_serverinfo = si
	};
	assert( si != NULL );
	pthread_cleanup_push( &cleanupHearersListener, &li );
	setupHearersListener( &li );
	while ( 1 ){
		acquire_statistics( si );
		assert( si->si_stats.stats_hearersNum <= HEARERS_MAXCOUNT );		
		while ( si->si_stats.stats_hearersNum == HEARERS_MAXCOUNT ){
			while ( pthread_cond_wait( &si->si_stats_hearers_cond, &si->si_stats_lock ) ){ continue; }
		}
		assert( si->si_stats.stats_hearersNum < SAYERS_MAXCOUNT );
		release_statistics( si );
		errno = 0;
		if ( ( connsockfd = accept( li.li_sockfd, NULL, NULL ) ) == -1 ){
			error( "accept() failed in hearersListener() (%s)\n", strerror( errno ) );
			continue;
		}
		errno = 0;
		if ( ( csi = malloc( sizeof( *csi ) ) ) == NULL ){
			error( "malloc() failed in hearersListener() (%s)\n", strerror( errno ) );
			safe_close( connsockfd );
			continue;
		}
		acquire_twitpool_list( si );
		errno = 0;
		if ( newtwitpool( &si->si_twitpool_list, &tpln ) == -1  ){
			error( "newtwitpool() failed in hearersListener() (%s)\n", strerror( errno ) );
			safe_close( connsockfd );
			free( csi );
			release_twitpool_list( si );
			continue;
		}
		release_twitpool_list( si );
		csi->csi_serverinfo = si;
		csi->csi_sockfd = connsockfd;
		csi->csi_tpln = tpln;
		acquire_statistics( si );
		if ( ( errno = pthread_create( &threadid, &li.li_threadattr, &hearerConnectionHandler, csi ) ) ){
			error( "pthread_create() failed in hearersListener() (%s)\n", strerror( errno ) );
			safe_close( connsockfd );
			free( csi );
			( void )removefromtwitpoollist( &si->si_twitpool_list, tpln );
		}
		else{
			increaseHearersNum( &si->si_stats );
			increaseThreadsNum( &si->si_stats );
		}
		release_statistics( si );
	}
	pthread_cleanup_pop( 1 );
	pthread_exit( NULL );
}
void * hearersListener ( void * arg ) { struct serverinfo * si = ( struct serverinfo * ) arg ; struct connserverinfo * csi = NULL ; struct twitpoollist_node * tpln = NULL ; pthread_t threadid ; int connsockfd = -1 ; struct listenerinfo li = { . li_serverinfo = si } ; assert ( si != NULL ) ; pthread_cleanup_push ( & cleanupHearersListener , & li ) ; setupHearersListener ( & li ) ; while ( 1 ) { acquire_statistics ( si ) ; assert ( si -> si_stats . stats_hearersNum <= HEARERS_MAXCOUNT ) ; while ( si -> si_stats . stats_hearersNum == HEARERS_MAXCOUNT ) { while ( pthread_cond_wait ( & si -> si_stats_hearers_cond , & si -> si_stats_lock ) ) { continue ; } } assert ( si -> si_stats . stats_hearersNum < SAYERS_MAXCOUNT ) ; release_statistics ( si ) ; errno = 0 ; if ( ( connsockfd = accept ( li . li_sockfd , NULL , NULL ) ) == -1 ) { error ( " \n " , strerror ( errno ) ) ; continue ; } errno = 0 ; if ( ( csi = malloc ( sizeof ( * csi ) ) ) == NULL ) { error ( " \n " , strerror ( errno ) ) ; safe_close ( connsockfd ) ; continue ; } acquire_twitpool_list ( si ) ; errno = 0 ; if ( newtwitpool ( & si -> si_twitpool_list , & tpln ) == -1 ) { error ( " \n " , strerror ( errno ) ) ; safe_close ( connsockfd ) ; free ( csi ) ; release_twitpool_list ( si ) ; continue ; } release_twitpool_list ( si ) ; csi -> csi_serverinfo = si ; csi -> csi_sockfd = connsockfd ; csi -> csi_tpln = tpln ; acquire_statistics ( si ) ; if ( ( errno = pthread_create ( & threadid , & li . li_threadattr , & hearerConnectionHandler , csi ) ) ) { error ( " \n " , strerror ( errno ) ) ; safe_close ( connsockfd ) ; free ( csi ) ; ( void ) removefromtwitpoollist ( & si -> si_twitpool_list , tpln ) ; } else { increaseHearersNum ( & si -> si_stats ) ; increaseThreadsNum ( & si -> si_stats ) ; } release_statistics ( si ) ; } pthread_cleanup_pop ( 1 ) ; pthread_exit ( NULL ) ; }
hearersListener() runs on its own thread and is responsible for accepting connections from hearers.
hearersListener () runs on its own thread and is responsible for accepting connections from hearers .
// Malloced each time a connection arrives // used for the twitpoollist_node of each hearer // Used for the threads created to handle the connections // The socket from each connection arriving // Setup the listener // Setup the cleanup // POSIX says that pthread_cleanup_push() and pthread_cleanup_pop() must appear as statements // and in pairs within the same lexical scope so pthread_cleanup_push() must be put here // and not in setupHearersListener() // Wait for connections // Do not accept any more connections if we are full of hearers // A connection arrived. Create a new struct connserverinfo object // for the new thread // must close the socket here // Acquire ownership of the twitpool list // Create a twitpool for that hearer // do cleanup work // close the socket // free structure // CAUTION: do **not** forget to unlock the list here // Release ownership of the twitpool list // Release ownership of the twitpool list // CAUTION: the statistics must be locked before the thread is created cause in case the connection gets closed // before the nums are increased here and the created thread decreases the nums then we have an error. // So lock the statistics beforehand to avoid any race condition		 // Create the new thread to handle the connection // must close the socket here // note that if the thread failed to be created we must free the memory for csi here // otherwise, the thread must free the memory itself // must also remove the twitpool created for the hearer // Update the statistics that a new hearer was connected // Perform cleanup // Not Reached