119 lines
2.7 KiB
C
119 lines
2.7 KiB
C
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
#include "common/debug.h"
|
|
#include "common/queue.h"
|
|
#include "common/threading.h"
|
|
|
|
#include "boss.h"
|
|
#include "client.h"
|
|
|
|
/* The id of the listening socket. */
|
|
static socket_t m_listening_socket = -1;
|
|
|
|
/* Child count */
|
|
static int child_count = 0;
|
|
|
|
/* List of child threads. */
|
|
static pthread_t* m_children = NULL;
|
|
|
|
/* The queue of client sockets. */
|
|
static queue_t m_client_sockets;
|
|
|
|
int boss_initialize(port_t pnum, int thread_count)
|
|
{
|
|
int index = 0;
|
|
int result = 0;
|
|
|
|
#ifdef WIN32
|
|
/* Have to also initialize WinSock */
|
|
WSADATA uselessData;
|
|
result = WSAStartup(MAKEWORD(2, 2), &uselessData);
|
|
if (result)
|
|
{
|
|
fprintf(stderr, "[BOSS] Could not initialize WinSock.\n");
|
|
net_report_error();
|
|
return result;
|
|
}
|
|
#endif
|
|
|
|
child_count = thread_count;
|
|
|
|
/* Make a listening socket: */
|
|
m_listening_socket = net_listen_on_port(pnum);
|
|
if (IS_BAD_SOCKET(m_listening_socket))
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
/* Initialize the queue */
|
|
queue_initialize(&m_client_sockets);
|
|
|
|
/* Spawn children threads. */
|
|
m_children = (pthread_t*) calloc(thread_count, sizeof(pthread_t));
|
|
if (!m_children)
|
|
{
|
|
fprintf(stderr, "[BOSS] Could not allocate memory.\n");
|
|
net_report_error();
|
|
return 1;
|
|
}
|
|
|
|
for (index = 0; index < thread_count; index++)
|
|
{
|
|
result = pthread_create(m_children + index, NULL,
|
|
client_run, &m_client_sockets);
|
|
if (result)
|
|
{
|
|
fprintf(stderr, "[BOSS] Could not create child thread.\n");
|
|
net_report_error();
|
|
return result;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void* boss_run(void* param)
|
|
{
|
|
/* Loop infinitely accepting connections: */
|
|
while (1)
|
|
{
|
|
/* Accept connection */
|
|
socket_t client_socket = -1;
|
|
sockaddress_t caddr;
|
|
socklen_t sizeof_caddr = sizeof(sockaddress_t);
|
|
|
|
DEBUG_PRINTF(("[BOSS] Waiting for a client connection...\n"));
|
|
|
|
client_socket = accept(m_listening_socket,
|
|
(struct sockaddr*) &caddr, &sizeof_caddr);
|
|
if (IS_BAD_SOCKET(client_socket))
|
|
{
|
|
fprintf(stderr,
|
|
"[BOSS] Could not accept client on listening socket\n");
|
|
net_report_error();
|
|
continue;
|
|
}
|
|
|
|
DEBUG_PRINTF(("[BOSS] Got client on port %d.\n", ntohs(caddr.sin_port)));
|
|
|
|
/* Enqueue socket to be picked up by a client thread. */
|
|
queue_enqueue(&m_client_sockets, (void*) client_socket);
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
int boss_clean()
|
|
{
|
|
/* Kill children */
|
|
int index;
|
|
for (index = 0; index < child_count; index++)
|
|
{
|
|
pthread_kill(m_children[index], SIGINT);
|
|
}
|
|
|
|
DEBUG_PRINTF(("[BOSS] Shutting down...\n\n"));
|
|
return net_close_socket(m_listening_socket);
|
|
}
|