src/server/listen.c
void *sayersListener( void *arg ){
	struct serverinfo *si = ( struct serverinfo * )arg;
	struct connserverinfo *csi = NULL; // Malloced each time a connection arrives
	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 setupSayersListener()
	pthread_cleanup_push( &cleanupSayersListener, &li );
	setupSayersListener( &li );
	
	// Wait for connections
	while ( 1 ){
		// Do not accept any more connections if we are full of sayers
		acquire_statistics( si );
		assert( si->si_stats.stats_sayersNum <= SAYERS_MAXCOUNT );		
		while ( si->si_stats.stats_sayersNum == SAYERS_MAXCOUNT ){
			while ( pthread_cond_wait( &si->si_stats_sayers_cond, &si->si_stats_lock ) ){ continue; }
		}
		assert( si->si_stats.stats_sayersNum < SAYERS_MAXCOUNT );
		release_statistics( si );

		errno = 0;
		if ( ( connsockfd = accept( li.li_sockfd, NULL, NULL ) ) == -1 ){
			error( "accept() failed in sayersListener() (%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 sayersListener() (%s)\n", strerror( errno ) );
			// must close the socket here
			safe_close( connsockfd );
			continue;
		}
		csi->csi_serverinfo = si;
		csi->csi_sockfd = connsockfd;

		// 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, &sayerConnectionHandler, csi ) ) ){
			error( "pthread_create() failed in sayersListener() (%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 );
		}
		else{
			// Update the statistics that a new sayer was connected
			increaseSayersNum( &si->si_stats );
			increaseThreadsNum( &si->si_stats );
		}
		release_statistics( si );
	}

	// Perform cleanup
	pthread_cleanup_pop( 1 );

	// Not Reached
	pthread_exit( NULL );
}
/**
 * sayersListener() runs on its own thread and is responsible for accepting connections from sayers. 
 * The port to which the sayersListener() function will listen for sayers is obtained from config.h (SAYERS_PORT).
 * The steps the sayersListener() function takes are:
 *	1) The socket that will listen for sayers at the port SAYERS_PORT is created.
 *	2) If successfull (the above step) the sayersListener() function notifies through the serverinfo structure
 *	passed as parameter that is prepared.
 *	3) It waits for a connection from a sayer and if a connection arrives: 
 *		1) Start a new thread that handles the connection with the sayer sayerConnectionHandler().
 *		2) Update the statistics structure (a new sayer arrived).
 */
sayersListener() runs on its own thread and is responsible for accepting connections from sayers.
The port to which the sayersListener() function will listen for sayers is obtained from config.h (SAYERS_PORT).
The steps the sayersListener() function takes are:
1) The socket that will listen for sayers at the port SAYERS_PORT is created.
2) If successfull (the above step) the sayersListener() function notifies through the serverinfo structure
passed as parameter that is prepared.
3) It waits for a connection from a sayer and if a connection arrives:
1) Start a new thread that handles the connection with the sayer sayerConnectionHandler().
2) Update the statistics structure (a new sayer arrived).
sayersListener () runs on its own thread and is responsible for accepting connections from sayers . The port to which the sayersListener () function will listen for sayers is obtained from config . h ( SAYERS_PORT ) . The steps the sayersListener () function takes are : 1 ) The socket that will listen for sayers at the port SAYERS_PORT is created . 2 ) If successfull ( the above step ) the sayersListener () function notifies through the serverinfo structure passed as parameter that is prepared . 3 ) It waits for a connection from a sayer and if a connection arrives : 1 ) Start a new thread that handles the connection with the sayer sayerConnectionHandler () . 2 ) Update the statistics structure ( a new sayer arrived ) .
void *sayersListener( void *arg ){
	struct serverinfo *si = ( struct serverinfo * )arg;
	struct connserverinfo *csi = NULL; 
	pthread_t threadid; 
	int connsockfd = -1; 
	struct listenerinfo li = {
		.li_serverinfo = si
	};
	assert( si != NULL );
	pthread_cleanup_push( &cleanupSayersListener, &li );
	setupSayersListener( &li );
	while ( 1 ){
		acquire_statistics( si );
		assert( si->si_stats.stats_sayersNum <= SAYERS_MAXCOUNT );		
		while ( si->si_stats.stats_sayersNum == SAYERS_MAXCOUNT ){
			while ( pthread_cond_wait( &si->si_stats_sayers_cond, &si->si_stats_lock ) ){ continue; }
		}
		assert( si->si_stats.stats_sayersNum < SAYERS_MAXCOUNT );
		release_statistics( si );
		errno = 0;
		if ( ( connsockfd = accept( li.li_sockfd, NULL, NULL ) ) == -1 ){
			error( "accept() failed in sayersListener() (%s)\n", strerror( errno ) );
			continue;
		}
		errno = 0;
		if ( ( csi = malloc( sizeof( *csi ) ) ) == NULL ){
			error( "malloc() failed in sayersListener() (%s)\n", strerror( errno ) );
			safe_close( connsockfd );
			continue;
		}
		csi->csi_serverinfo = si;
		csi->csi_sockfd = connsockfd;
		acquire_statistics( si );
		if ( ( errno = pthread_create( &threadid, &li.li_threadattr, &sayerConnectionHandler, csi ) ) ){
			error( "pthread_create() failed in sayersListener() (%s)\n", strerror( errno ) );
			safe_close( connsockfd );
			free( csi );
		}
		else{
			increaseSayersNum( &si->si_stats );
			increaseThreadsNum( &si->si_stats );
		}
		release_statistics( si );
	}
	pthread_cleanup_pop( 1 );
	pthread_exit( NULL );
}
void * sayersListener ( void * arg ) { struct serverinfo * si = ( struct serverinfo * ) arg ; struct connserverinfo * csi = NULL ; pthread_t threadid ; int connsockfd = -1 ; struct listenerinfo li = { . li_serverinfo = si } ; assert ( si != NULL ) ; pthread_cleanup_push ( & cleanupSayersListener , & li ) ; setupSayersListener ( & li ) ; while ( 1 ) { acquire_statistics ( si ) ; assert ( si -> si_stats . stats_sayersNum <= SAYERS_MAXCOUNT ) ; while ( si -> si_stats . stats_sayersNum == SAYERS_MAXCOUNT ) { while ( pthread_cond_wait ( & si -> si_stats_sayers_cond , & si -> si_stats_lock ) ) { continue ; } } assert ( si -> si_stats . stats_sayersNum < 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 ; } csi -> csi_serverinfo = si ; csi -> csi_sockfd = connsockfd ; acquire_statistics ( si ) ; if ( ( errno = pthread_create ( & threadid , & li . li_threadattr , & sayerConnectionHandler , csi ) ) ) { error ( " \n " , strerror ( errno ) ) ; safe_close ( connsockfd ) ; free ( csi ) ; } else { increaseSayersNum ( & si -> si_stats ) ; increaseThreadsNum ( & si -> si_stats ) ; } release_statistics ( si ) ; } pthread_cleanup_pop ( 1 ) ; pthread_exit ( NULL ) ; }
sayersListener() runs on its own thread and is responsible for accepting connections from sayers.
sayersListener () runs on its own thread and is responsible for accepting connections from sayers .
// Malloced each time a connection arrives // 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 setupSayersListener() // Wait for connections // Do not accept any more connections if we are full of sayers // A connection arrived. Create a new struct connserverinfo object // for the new thread // must close the socket here // 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 // Update the statistics that a new sayer was connected // Perform cleanup // Not Reached