Add support for Win32 and Winsock to main.c and sock.c code

This commit is contained in:
blt
2003-08-10 02:29:32 +00:00
parent 67cae9e447
commit b03a3522d9
3 changed files with 308 additions and 69 deletions
+237 -61
View File
@@ -6,33 +6,36 @@
* COPYING file distributed with this package.
*
* Copyright (c) 1999, William Ferrell, Scott Scriven
*
* 2003, Benjamin Tse (blt@ieee.org) - Winsock port
*
* LCDproc sockets code...
*
* This is messy, and needs to be finished.
*
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <unistd.h>
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#ifdef WINSOCK2
#include <winsock2.h>
#else
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/time.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#endif /* WINSOCK */
#include <sys/time.h>
#include <sys/types.h>
#include <fcntl.h>
#include <string.h>
#include "shared/sockets.h"
#include "main.h"
#include "sock.h"
#include "client.h"
#include "clients.h"
@@ -41,26 +44,97 @@
#include "screenlist.h"
fd_set active_fd_set, read_fd_set;
int listening_fd;
/****************************************************************************/
static fd_set active_fd_set, read_fd_set;
static int listening_fd;
/* For efficiency we maintain a list of open sockets. Nodes in this list
* are obtained from a pre-allocated pool - this removes heap operations
* from the polling loop. A list of open sockets is also required under WINSOCK
* as sockets can be arbitrary values instead of low value integers. */
static LinkedList* openSocketList = NULL;
static LinkedList* freeClientSocketList = NULL;
struct ClientSocketMap
{
int socket;
Client* client;
};
/* The memory referenced from clientSocketPoolList is obtained from the
* clientSocketPool array. */
struct ClientSocketMap* freeClientSocketPool;
/* Length of longest transmission allowed at once...*/
#define MAXMSG 8192
int sock_read_from_client (int filedes);
/**** Internal function declarations ****************************************/
int sock_read_from_client(struct ClientSocketMap* clientSocketMap);
/****************************************************************************/
int
sock_init ()
sock_init(char* bind_addr, int bind_port)
{
int i;
#ifdef WINSOCK2
/* Initialize the Winsock dll */
WSADATA wsaData;
int startup = WSAStartup( MAKEWORD(2, 2), &wsaData );
if (startup != 0)
{
report(RPT_ERR, "%s: Could not start Winsock library - %s",
__FUNCTION__, sock_geterror());
}
/* REVISIT: call WSACleanup(); */
#endif
debug (RPT_DEBUG, "%s( bind_addr=\"%s\", port=%d )", __FUNCTION__, bind_addr, bind_port);
/* Create the socket and set it up to accept connections. */
listening_fd = sock_create_inet_socket (bind_addr, bind_port);
if (listening_fd < 0) {
report (RPT_ERR, "%s: Error creating socket", __FUNCTION__);
report (RPT_ERR, "%s: Error creating socket - %s",
__FUNCTION__, sock_geterror());
return -1;
}
/* Create the socket -> Client mapping pool */
/* How large can FD_SETSIZE be? Even if it is ~2000 this only uses a
few kilobytes of memory. Let's trade size for speed! */
freeClientSocketPool = (struct ClientSocketMap*)
malloc(sizeof(struct ClientSocketMap) * FD_SETSIZE);
if (!freeClientSocketPool)
{
report(RPT_ERR, "%s: Error allocating memory for client sockets.",
__FUNCTION__);
return -1;
}
freeClientSocketList = LL_new();
for (i = 0; i < FD_SETSIZE; ++i)
{
LL_AddNode(freeClientSocketList, (void*) &freeClientSocketPool[i]);
}
/* Create and initialize the open socket list with the server socket */
openSocketList = LL_new();
if (!openSocketList)
{
report(RPT_ERR, "%s: Error allocating memory for the open socket "
"list.", __FUNCTION__);
return -1;
} else {
struct ClientSocketMap* entry;
/* LL_DeleteNode removes an entry from the list and returns it */
entry = (struct ClientSocketMap*) LL_Pop(freeClientSocketList);
entry->socket = listening_fd;
entry->client = NULL;
LL_AddNode(openSocketList, (void*) entry);
}
return 0;
}
@@ -84,12 +158,46 @@ This code gets the send and receive buffer sizes.
int
sock_shutdown ()
{
int retVal = 0;
debug( RPT_DEBUG, "%s()", __FUNCTION__ );
/*struct ClientSocketMap* clientIt;*/
/* delete all clients */
/* This should be done by calling clients_shutdown */
/*
LL_Rewind(openSocketList);
for (clientIt = (struct ClientSocketMap*) LL_Get(openSocketList);
clientIt;
clientIt = LL_GetNext(openSocketList))
{
if (clientIt->client)
{
/* destroying a client also closes its socket */
/* client_destroy(clientIt->client);
}
}
LL_Destroy(openSocketList);
*/
close( listening_fd );
LL_Destroy(freeClientSocketList);
free(freeClientSocketPool);
#ifdef WINSOCK2
if (WSACleanup() != 0)
{
report(RPT_ERR, "%s: Error closing Winsock library - %s",
__FUNCTION__, sock_geterror());
retVal = -1;
}
#endif
return retVal;
}
/****************************************************************************/
/* Creates a socket in internet space */
int
sock_create_inet_socket (char * addr, unsigned int port)
@@ -101,13 +209,20 @@ sock_create_inet_socket (char * addr, unsigned int port)
/* Create the socket. */
sock = socket (PF_INET, SOCK_STREAM, 0);
if (sock < 0) {
report(RPT_ERR, "%s: Could not create socket", __FUNCTION__);
#ifdef WINSOCK2
if (sock == INVALID_SOCKET)
#else
if (sock < 0)
#endif
{
report(RPT_ERR, "%s: Could not create socket - %s",
__FUNCTION__, sock_geterror());
return -1;
}
/* Set the socket so we can re-use it*/
if(setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&sockopt,sizeof(sockopt)) < 0) {
report(RPT_ERR, "%s: Error setting socket option SO_REUSEADDR", __FUNCTION__);
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void*)&sockopt, sizeof(sockopt)) < 0) {
report(RPT_ERR, "%s: Error setting socket option SO_REUSEADDR - %s",
__FUNCTION__, sock_geterror());
return -1;
}
@@ -115,17 +230,26 @@ sock_create_inet_socket (char * addr, unsigned int port)
memset (&name, 0, sizeof (name));
name.sin_family = AF_INET;
name.sin_port = htons (port);
#ifndef WINSOCK2
/* REVISIT: can probably use the same code as under winsock */
inet_aton(addr, &name.sin_addr);
#else
name.sin_addr.S_un.S_addr = inet_addr(addr);
#endif
if (bind (sock, (struct sockaddr *) &name, sizeof (name)) < 0) {
report(RPT_ERR, "Could not bind to port %d", port);
if (bind(sock, (struct sockaddr *) &name, sizeof (name)) < 0)
{
report(RPT_ERR, "%s: Could not bind to port %d at address %s - %s",
__FUNCTION__, port, addr, sock_geterror());
return -1;
} else {
report(RPT_NOTICE, "Listening for queries on %s:%d", addr, port);
}
if (listen (sock, 1) < 0) {
report(RPT_ERR, "%s: error in attempting to listen to port", __FUNCTION__);
report(RPT_ERR, "%s: error in attempting to listen to port "
"%d at %s - %s",
__FUNCTION__, port, addr, sock_geterror());
return -1;
}
@@ -141,12 +265,10 @@ sock_create_inet_socket (char * addr, unsigned int port)
int
sock_poll_clients ()
{
int i;
int err;
struct sockaddr_in clientname;
size_t size;
struct timeval t;
Client * c;
struct ClientSocketMap* clientSocket;
debug (RPT_DEBUG, "%s()", __FUNCTION__);
@@ -157,35 +279,73 @@ sock_poll_clients ()
read_fd_set = active_fd_set;
if (select (FD_SETSIZE, &read_fd_set, NULL, NULL, &t) < 0) {
report (RPT_ERR, "%s: Select error", __FUNCTION__);
report(RPT_ERR, "%s: Select error - %s",
__FUNCTION__, sock_geterror());
return -1;
}
/* Service all the sockets with input pending. */
for (i = 0; i < FD_SETSIZE; ++i) {
if (FD_ISSET (i, &read_fd_set)) {
if (i == listening_fd) {
LL_Rewind(openSocketList);
for (clientSocket = (struct ClientSocketMap*) LL_Get(openSocketList);
clientSocket;
clientSocket = LL_GetNext(openSocketList))
{
if (FD_ISSET(clientSocket->socket, &read_fd_set))
{
if (clientSocket->socket == listening_fd)
{
/* Connection request on original socket. */
Client* c;
int new_sock;
size = sizeof (clientname);
size_t size = sizeof(clientname);
new_sock = accept (listening_fd, (struct sockaddr *) &clientname, &size);
if (new_sock < 0) {
report (RPT_ERR, "%s: Accept error", __FUNCTION__);
#ifdef WINSOCK2
if (new_sock == INVALID_SOCKET)
#else
if (new_sock < 0)
#endif
{
report(RPT_ERR, "%s: Accept error - %s",
__FUNCTION__, sock_geterror());
return -1;
}
report (RPT_NOTICE, "Connect from host %s:%hd on socket %i",
inet_ntoa (clientname.sin_addr), ntohs (clientname.sin_port), new_sock);
FD_SET (new_sock, &active_fd_set);
fcntl (new_sock, F_SETFL, O_NONBLOCK);
#ifdef WINSOCK2
{
unsigned long tmp;
ioctlsocket(new_sock, FIONBIO, &tmp);
}
#else
fcntl(new_sock, F_SETFL, O_NONBLOCK);
#endif
/* Create new client */
if ((c = client_create (new_sock)) == NULL) {
report( RPT_ERR, "%s: Error creating client on socket %i", __FUNCTION__, i);
report( RPT_ERR, "%s: Error creating client on socket %i - %s",
__FUNCTION__, clientSocket->socket, sock_geterror());
return -1;
}
} else {
/* add new_sock */
struct ClientSocketMap* newClientSocket;
newClientSocket = (struct ClientSocketMap*) LL_Pop(freeClientSocketList);
if (newClientSocket)
{
newClientSocket->socket = new_sock;
newClientSocket->client = c;
LL_InsertNode(openSocketList, (void*) newClientSocket);
/* advance past the new node - check it on the next pass */
LL_Next(openSocketList);
} else {
report(RPT_ERR, "%s: Error - free client socket list exhausted - %d clients.",
__FUNCTION__, FD_SETSIZE);
return -1;
}
}
if (clients_add_client (c) != 0) {
report( RPT_ERR, "%s: Could not add client on socket %i", __FUNCTION__, i);
report( RPT_ERR, "%s: Could not add client on socket %i", __FUNCTION__, clientSocket->socket);
return -1;
}
} else {
@@ -193,21 +353,30 @@ sock_poll_clients ()
err = 0;
do {
debug (RPT_DEBUG, "%s: reading...", __FUNCTION__);
err = sock_read_from_client (i);
err = sock_read_from_client(clientSocket);
debug (RPT_DEBUG, "%s: ...done", __FUNCTION__);
if (err < 0) {
/* Client disconnected, destroy client data */
c = clients_find_client_by_sock (i);
if (c) {
/*sock_send_string(i, "bye\n");*/
report (RPT_NOTICE, "Client on socket %i disconnected", i);
client_destroy (c);
clients_remove_client (c);
close (i);
FD_CLR (i, &active_fd_set);
} else {
report (RPT_ERR, "%s: Can't find client of socket %i", __FUNCTION__, i);
}
if (err < 0)
{
/* Client disconnected, destroy client data */
/* c = clients_find_client_by_sock(); - Deprecated by clientsocketmap*/
if (clientSocket->client)
{
struct ClientSocketMap* entry;
/*sock_send_string(i, "bye\n");*/
report (RPT_NOTICE, "Client on socket %i disconnected",
clientSocket->socket);
client_destroy(clientSocket->client);
clients_remove_client(clientSocket->client);
FD_CLR(clientSocket->socket, &active_fd_set);
close(clientSocket->socket);
entry = (struct ClientSocketMap*) LL_DeleteNode(openSocketList);
LL_Push(freeClientSocketList, (void*) entry);
} else {
report (RPT_ERR, "%s: Can't find client of socket %i",
__FUNCTION__, clientSocket->socket);
}
}
} while (err > 0);
}
@@ -217,25 +386,29 @@ sock_poll_clients ()
}
int
sock_read_from_client (int filedes)
sock_read_from_client(struct ClientSocketMap* clientSocketMap)
{
char buffer[MAXMSG];
int nbytes, i;
Client * c;
debug (RPT_DEBUG, "%s()", __FUNCTION__);
errno = 0;
if ((nbytes = sock_recv (filedes, buffer, MAXMSG)) < 0) {
nbytes = sock_recv(clientSocketMap->socket, buffer, MAXMSG);
if (nbytes < 0)
{
if (errno != EAGAIN)
report (RPT_DEBUG, "%s: Error on socket %d: %s", __FUNCTION__, filedes, strerror(errno));
report(RPT_DEBUG, "%s: Error on socket %d - %s",
__FUNCTION__, clientSocketMap->socket, sock_geterror());
return 0;
} else if (nbytes == 0) /* EOF*/
{
return -1;
else if (nbytes > (MAXMSG - (MAXMSG / 8))) /* Very noisy client...*/
} else if (nbytes > (MAXMSG - (MAXMSG / 8))) /* Very noisy client...*/
{
sock_send_string (filedes, "huh? Too much data received... quiet down!\n");
report (RPT_WARNING, "%s: Too much data received on socket %d", __FUNCTION__, filedes);
sock_send_string(clientSocketMap->socket, "huh? Too much data received... quiet down!\n");
report(RPT_WARNING, "%s: Too much data received on socket %d",
__FUNCTION__, clientSocketMap->socket);
return -1;
} else /* Data Read*/
{
@@ -245,13 +418,16 @@ sock_read_from_client (int filedes)
if (buffer[i] == 0)
buffer[i] = '\n';
/* Enqueue a "client message" here...*/
c = clients_find_client_by_sock (filedes);
if (c) {
client_add_message (c, buffer);
} else
report (RPT_DEBUG, "%s: Can't find client %d", __FUNCTION__, filedes);
/* c = clients_find_client_by_sock (filedes); - Deprecated by clientsocketmap*/
if (clientSocketMap->client) {
client_add_message(clientSocketMap->client, buffer);
} else {
report(RPT_DEBUG, "%s: Can't find client %d",
__FUNCTION__, clientSocketMap->socket);
}
report (RPT_DEBUG, "%s: got message from client %d: \"%s\"", __FUNCTION__, filedes, buffer);
report(RPT_DEBUG, "%s: got message from client %d: \"%s\"",
__FUNCTION__, clientSocketMap->socket, buffer);
return nbytes;
}
return nbytes;