summaryrefslogtreecommitdiff
path: root/src/z-sock.c
diff options
context:
space:
mode:
authorBardur Arantsson <bardur@scientician.net>2010-01-08 20:28:34 +0100
committerBardur Arantsson <bardur@scientician.net>2010-01-08 23:46:06 +0100
commit6aa48afdd57d03314fdf4be6c9da911c32277c84 (patch)
tree2dc401f9aae2dc6736d2fc3811c8f8099d3eabe6 /src/z-sock.c
Import tome-2.3.5.
Diffstat (limited to 'src/z-sock.c')
-rw-r--r--src/z-sock.c787
1 files changed, 787 insertions, 0 deletions
diff --git a/src/z-sock.c b/src/z-sock.c
new file mode 100644
index 00000000..fcc6cd1c
--- /dev/null
+++ b/src/z-sock.c
@@ -0,0 +1,787 @@
+/* File: z-term.c */
+
+/*
+ * Copyright (c) 1997 Ben Harrison
+ *
+ * This software may be copied and distributed for educational, research,
+ * and not for profit purposes provided that this copyright and statement
+ * are included in all such copies.
+ */
+
+/* Purpose: a generic, IP connection package */
+
+#include "angband.h"
+#include "z-term.h"
+#include "z-virt.h"
+
+
+/*
+ * System independant functions
+ */
+
+/* Call all the callbacks */
+void zsock_handle_callbacks()
+{
+ timer_callback_list *c = zsock.__timer_callbacks;
+
+ while (c != NULL)
+ {
+ c->callback();
+ c = c->next;
+ }
+}
+
+/* Add a callback in the list */
+void zsock_add_timer_callback(timer_callback callback)
+{
+ timer_callback_list *c;
+
+ /* Create it */
+ MAKE(c, timer_callback_list);
+ c->callback = callback;
+
+ /* Add it into the lsit */
+ c->next = zsock.__timer_callbacks;
+ zsock.__timer_callbacks = c;
+
+ /* Increase the timer count */
+ zsock.__timers++;
+}
+
+/* Remove a callback in the list */
+void zsock_remove_timer_callback(timer_callback callback)
+{
+ timer_callback_list *c = zsock.__timer_callbacks, *old = NULL;
+
+ /* Find it */
+ while ((c != NULL) && (c->callback != callback))
+ {
+ old = c;
+ c = c->next;
+ }
+
+ if (c->callback == callback)
+ {
+ /* Skip it */
+ if (old == NULL)
+ zsock.__timer_callbacks = c->next;
+ else
+ old->next = c->next;
+
+ /* Delete it */
+ FREE(c, timer_callback_list);
+
+ /* Increase the timer count */
+ zsock.__timers--;
+ }
+ else
+ {
+ cmsg_print(TERM_VIOLET, "WARNING: tried to remove a non existing timer callback!");
+ }
+}
+
+/* Creates a connection struct */
+ip_connection *zsock_new_connection()
+{
+ ip_connection *c;
+
+ MAKE(c, ip_connection);
+ return c;
+}
+void zsock_free_connection(ip_connection *c)
+{
+ FREE(c, ip_connection);
+}
+
+
+/* Set the dying connection callback */
+void zsock_set_lose_connection(ip_connection *conn, lose_connection_hook hook)
+{
+ conn->lost_conn = hook;
+}
+
+/* Send data on the connection -- easy to use */
+bool zsock_write_simple(ip_connection *conn, cptr str)
+{
+ int len = 0;
+
+ return zsock.write(conn, str, &len);
+}
+
+/* Read data on the connection -- easy to use */
+bool zsock_read_simple(ip_connection *conn, char *str, int len)
+{
+ int rlen = len;
+
+ return zsock.read(conn, str, &rlen, FALSE);
+}
+
+/*
+ ******************************* Here comes the Windows socket part ********************************
+ */
+#ifdef USE_WINSOCK
+#include <windows.h>
+#include <winsock2.h>
+
+/* Needed for timers -- pfft */
+extern HWND get_main_hwnd();
+
+#define ZSOCK_TIMER_ID 1
+
+VOID CALLBACK zsock_timer_callback_win(HWND hwnd, UINT message, UINT idTimer, DWORD dwTime)
+{
+ zsock_handle_callbacks();
+}
+
+bool zsock_add_timer_win(timer_callback callback)
+{
+ zsock_add_timer_callback(callback);
+
+ /* Is it the first callback ? then we must create the timer */
+ if (zsock.__timers == 1)
+ {
+ SetTimer(get_main_hwnd(), ZSOCK_TIMER_ID, ZSOCK_TIMER_DELAY, zsock_timer_callback_win);
+ }
+ return TRUE;
+}
+
+bool zsock_remove_timer_win(timer_callback callback)
+{
+ zsock_remove_timer_callback(callback);
+
+ /* No more callbacks ? no need for the timer then */
+ if (!zsock.__timers)
+ {
+ KillTimer(get_main_hwnd(), ZSOCK_TIMER_ID);
+ }
+ return TRUE;
+}
+
+
+bool zsock_setup_win(ip_connection *conn, cptr conn_ip, int port, byte conn_type, bool server)
+{
+ /* Already setup! */
+ if (conn->setup) return FALSE;
+
+ MAKE(conn->socket, SOCKET);
+
+ if (!server)
+ {
+ struct hostent *host;
+
+ host = gethostbyname(conn_ip);
+ conn->conn_ip = ((struct in_addr *)(host->h_addr))->s_addr;
+ }
+ else
+ conn->conn_ip = 0;
+
+ conn->conn_type = conn_type;
+ conn->conn_port = htons(port);
+
+ conn->setup = TRUE;
+ conn->server = server;
+
+ conn->lost_conn = NULL;
+
+ return TRUE;
+}
+
+bool zsock_unsetup_win(ip_connection *conn)
+{
+ /* Already unsetup */
+ if (!conn->setup) return FALSE;
+
+ FREE(conn->socket, SOCKET);
+
+ return TRUE;
+}
+
+bool zsock_open_win(ip_connection *conn)
+{
+ struct sockaddr_in sin;
+
+ /* Already connected */
+ if (conn->connected) return FALSE;
+
+ *((SOCKET*)conn->socket) = socket(AF_INET, SOCK_STREAM, 0);
+
+ memset(&sin, 0, sizeof(sin));
+ sin.sin_family = AF_INET;
+ sin.sin_addr.s_addr = conn->conn_ip;
+ sin.sin_port = conn->conn_port;
+
+ if (conn->server)
+ {
+ if (SOCKET_ERROR == bind(*((SOCKET*)conn->socket), &sin, sizeof(sin)))
+ return FALSE;
+
+ if (SOCKET_ERROR == listen(*((SOCKET*)conn->socket), 10)) return FALSE;
+ }
+ else
+ {
+ if (connect(*((SOCKET*)conn->socket), &sin, sizeof sin) == SOCKET_ERROR)
+ {
+ /* could not connect to server */
+ return (FALSE);
+ }
+ }
+
+ conn->connected = TRUE;
+ return TRUE;
+}
+
+bool zsock_can_read_win(ip_connection *conn)
+{
+ struct timeval t;
+ fd_set rd;
+ SOCKET *c = conn->socket;
+
+ if (!conn->connected) return FALSE;
+
+ FD_ZERO(&rd);
+ FD_SET(*c, &rd);
+ t.tv_sec = 0;
+ t.tv_usec = 0;
+ select(*c + 1, &rd, NULL, NULL, &t);
+ if (FD_ISSET(*c, &rd)) return TRUE;
+ else return (FALSE);
+}
+
+bool zsock_wait_win(ip_connection *conn, int seconds)
+{
+ struct timeval t;
+ fd_set rd;
+ SOCKET *c = conn->socket;
+
+ if (!conn->connected) return FALSE;
+
+ t.tv_sec = seconds;
+ t.tv_usec = 0;
+
+ FD_ZERO(&rd);
+ FD_SET(*c, &rd);
+ select(*c + 1, &rd, NULL, NULL, &t);
+ if (FD_ISSET(*c, &rd)) return TRUE;
+ else return (FALSE);
+}
+
+bool zsock_close_win(ip_connection *conn)
+{
+ SOCKET *c = conn->socket;
+
+ /* Already disconnected */
+ if (!conn->connected) return FALSE;
+
+ closesocket(*c);
+ conn->connected = FALSE;
+ return TRUE;
+}
+
+bool zsock_write_win(ip_connection *conn, cptr str, int *size)
+{
+ SOCKET *c = conn->socket;
+
+ if (!conn->connected) return FALSE;
+
+ if ((*size = send(*c, str, (!*size) ? strlen(str) : *size, 0)) <= 0)
+ {
+ /* Oups connection died! */
+ if (conn->lost_conn) conn->lost_conn(conn);
+ zsock.close(conn);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+bool zsock_read_win(ip_connection *conn, char *str, int *len, bool raw)
+{
+ char c;
+ int l = 0;
+ SOCKET *cc = conn->socket;
+
+ if (!conn->connected) return FALSE;
+
+ if (!raw)
+ {
+ /* This *IS* fucking slow */
+ while ((l < *len) && zsock_can_read_win(conn))
+ {
+ if (recv(*cc, &c, 1, 0) <= 0)
+ {
+ /* Oups connection died! */
+ if (conn->lost_conn) conn->lost_conn(conn);
+ zsock.close(conn);
+ return FALSE;
+ }
+ if (c == '\r') continue;
+ if (c == '\n') break;
+ str[l++] = c;
+ }
+ str[l] = '\0';
+ *len = l;
+ return TRUE;
+ }
+ else
+ {
+ if ((*len = recv(*cc, str, *len, 0)) <= 0)
+ {
+ /* Oups connection died! */
+ if (conn->lost_conn) conn->lost_conn(conn);
+ zsock.close(conn);
+ return FALSE;
+ }
+ return TRUE;
+ }
+}
+
+bool zsock_accept_win(ip_connection *conn, ip_connection *child)
+{
+ SOCKET *s = conn->socket;
+ SOCKET sock;
+ struct sockaddr_in sin;
+ int len;
+
+ if (!conn->server) return FALSE;
+ if (!conn->connected) return FALSE;
+
+ len = sizeof(sin);
+ sock = accept(*s, (struct sockaddr*) & sin, &len);
+
+ if (sock == SOCKET_ERROR) return FALSE;
+
+ /* Initialize the connection with a fake destination */
+ zsock.setup(child, "127.0.0.1", 0, ZSOCK_TYPE_TCP, FALSE);
+
+ /* Set the correct socket */
+ *((SOCKET*)child->socket) = sock;
+ child->connected = TRUE;
+
+ return TRUE;
+}
+
+bool init_socks_win()
+{
+ WSADATA wsaData;
+ WORD version;
+ int error;
+
+ version = MAKEWORD( 2, 0 );
+
+ error = WSAStartup( version, &wsaData );
+
+ /* check for error */
+ if ( error != 0 )
+ {
+ /* error occured */
+ return FALSE;
+ }
+
+ /* check for correct version */
+ if ( LOBYTE( wsaData.wVersion ) != 2 ||
+ HIBYTE( wsaData.wVersion ) != 0 )
+ {
+ /* incorrect WinSock version */
+ WSACleanup();
+ return FALSE;
+ }
+
+ return TRUE;
+}
+#endif
+
+/*
+ ****************************** And there is the unix sockets **************************
+ */
+#ifdef USE_UNIXSOCK
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <signal.h>
+
+void handle_timer(int sig)
+{
+ zsock_handle_callbacks();
+}
+
+static struct sigaction handle_old_alarm;
+bool zsock_add_timer_unix(timer_callback callback)
+{
+ zsock_add_timer_callback(callback);
+
+ /* Is it the first callback ? then we must create the timer */
+ if (zsock.__timers == 1)
+ {
+ struct sigaction new_sig;
+
+ /* Register the timer */
+ new_sig.sa_handler = handle_timer;
+ new_sig.sa_flags = 0;
+ sigaction(SIGALRM, &new_sig, &handle_old_alarm);
+
+ ualarm(ZSOCK_TIMER_DELAY * 1000, ZSOCK_TIMER_DELAY * 1000);
+ }
+ return TRUE;
+}
+
+bool zsock_remove_timer_unix(timer_callback callback)
+{
+ zsock_remove_timer_callback(callback);
+
+ /* No more callbacks ? no need for the timer then */
+ if (!zsock.__timers)
+ {
+ alarm(0);
+ sigaction(SIGALRM, &handle_old_alarm, NULL);
+ }
+ return TRUE;
+}
+
+bool zsock_setup_unix(ip_connection *conn, cptr conn_ip, int port, byte conn_type, bool server)
+{
+ /* Already setup! */
+ if (conn->setup) return FALSE;
+
+ MAKE(conn->socket, int);
+
+ if (!server)
+ {
+ struct hostent *host;
+
+ host = gethostbyname(conn_ip);
+ conn->conn_ip = ((struct in_addr *)(host->h_addr))->s_addr;
+ }
+ else
+ conn->conn_ip = 0;
+
+ conn->conn_type = conn_type;
+ conn->conn_port = htons(port);
+
+ conn->setup = TRUE;
+ conn->server = server;
+
+ conn->lost_conn = NULL;
+
+ return TRUE;
+}
+
+bool zsock_unsetup_unix(ip_connection *conn)
+{
+ /* Already unsetup */
+ if (!conn->setup) return FALSE;
+
+ FREE(conn->socket, int);
+
+ return TRUE;
+}
+
+bool zsock_open_unix(ip_connection *conn)
+{
+ struct sockaddr_in sin;
+
+ /* Already connected */
+ if (conn->connected) return FALSE;
+
+ *((int*)conn->socket) = socket(AF_INET, SOCK_STREAM, 0);
+
+ memset(&sin, 0, sizeof(sin));
+ sin.sin_family = AF_INET;
+ sin.sin_addr.s_addr = conn->conn_ip;
+ sin.sin_port = conn->conn_port;
+
+ if (conn->server)
+ {
+ int option = 1;
+
+ /* Set this so we don't wait forever on startups */
+ if ( -1 == setsockopt(*((int*)conn->socket), SOL_SOCKET, SO_REUSEADDR , (void*)&option, sizeof(int))) return FALSE;
+
+ if ( -1 == bind(*((int*)conn->socket), (struct sockaddr*)&sin, sizeof(sin)))
+ return FALSE;
+
+ if ( -1 == listen(*((int*)conn->socket), 10)) return FALSE;
+ }
+ else
+ {
+ if (connect(*((int*)conn->socket), (struct sockaddr*)&sin, sizeof sin) == -1)
+ {
+ /* could not connect to server */
+ return (FALSE);
+ }
+ }
+
+ conn->connected = TRUE;
+ return TRUE;
+}
+
+bool zsock_can_read_unix(ip_connection *conn)
+{
+ struct timeval t;
+ fd_set rd;
+ int *c = conn->socket;
+
+ if (!conn->connected) return FALSE;
+
+ FD_ZERO(&rd);
+ FD_SET(*c, &rd);
+ t.tv_sec = 0;
+ t.tv_usec = 0;
+ select(*c + 1, &rd, NULL, NULL, &t);
+ if (FD_ISSET(*c, &rd)) return TRUE;
+ else return (FALSE);
+}
+
+bool zsock_wait_unix(ip_connection *conn, int seconds)
+{
+ struct timeval t;
+ fd_set rd;
+ int *c = conn->socket;
+
+ if (!conn->connected) return FALSE;
+
+ t.tv_sec = seconds;
+ t.tv_usec = 0;
+
+ FD_ZERO(&rd);
+ FD_SET(*c, &rd);
+ select(*c + 1, &rd, NULL, NULL, &t);
+ if (FD_ISSET(*c, &rd)) return TRUE;
+ else return (FALSE);
+}
+
+bool zsock_close_unix(ip_connection *conn)
+{
+ int *c = conn->socket;
+
+ /* Already disconnected */
+ if (!conn->connected) return FALSE;
+
+ close(*c);
+ conn->connected = FALSE;
+ return TRUE;
+}
+
+bool zsock_write_unix(ip_connection *conn, cptr str, int *size)
+{
+ int *c = conn->socket;
+
+ if (conn->server) return FALSE;
+ if (!conn->connected) return FALSE;
+
+ if ((*size = send(*c, str, (!*size) ? (s32b)strlen(str) : *size, 0)) <= 0)
+ {
+ /* Oups connection died! */
+ if (conn->lost_conn) conn->lost_conn(conn);
+ zsock.close(conn);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+bool zsock_read_unix(ip_connection *conn, char *str, int *len, bool raw)
+{
+ char c;
+ int l = 0;
+ int *cc = conn->socket;
+
+ if (conn->server) return FALSE;
+ if (!conn->connected) return FALSE;
+
+ if (!raw)
+ {
+ /* This *IS* fucking slow */
+ while ((l < *len) && zsock_can_read_unix(conn))
+ {
+ if (recv(*cc, &c, 1, 0) <= 0)
+ {
+ /* Oups connection died! */
+ if (conn->lost_conn) conn->lost_conn(conn);
+ zsock.close(conn);
+ return FALSE;
+ }
+ if (c == '\r') continue;
+ if (c == '\n') break;
+ str[l++] = c;
+ }
+ str[l] = '\0';
+ *len = l;
+ return TRUE;
+ }
+ else
+ {
+ if ((*len = recv(*cc, str, *len, 0)) <= 0)
+ {
+ /* Oups connection died! */
+ if (conn->lost_conn) conn->lost_conn(conn);
+ zsock.close(conn);
+ return FALSE;
+ }
+ return TRUE;
+ }
+}
+
+bool zsock_accept_unix(ip_connection *conn, ip_connection *child)
+{
+ int *s = conn->socket;
+ int sock;
+ struct sockaddr_in sin;
+ unsigned int len;
+
+ if (!conn->server) return FALSE;
+ if (!conn->connected) return FALSE;
+
+ len = sizeof(sin);
+ sock = accept(*s, (struct sockaddr*) & sin, &len);
+
+ if (sock == -1) return FALSE;
+
+ /* Initialize the connection with a fake destination */
+ zsock.setup(child, "127.0.0.1", 0, ZSOCK_TYPE_TCP, FALSE);
+
+ /* Set the correct socket */
+ *((int*)child->socket) = sock;
+ child->connected = TRUE;
+
+ return TRUE;
+}
+
+#endif
+
+/* The zsock hook list */
+zsock_hooks zsock;
+
+/*
+ * Dummy hooks for systems without socks
+ */
+bool zsock_setup_dummy(ip_connection *conn, cptr conn_ip, int port, byte conn_type, bool server)
+{
+ return FALSE;
+}
+
+bool zsock_unsetup_dummy(ip_connection *conn)
+{
+ return FALSE;
+}
+
+bool zsock_open_dummy(ip_connection *conn)
+{
+ return FALSE;
+}
+
+bool zsock_can_read_dummy(ip_connection *conn)
+{
+ return (FALSE);
+}
+
+bool zsock_wait_dummy(ip_connection *conn, int seconds)
+{
+ return (FALSE);
+}
+
+bool zsock_close_dummy(ip_connection *conn)
+{
+ return FALSE;
+}
+
+bool zsock_write_dummy(ip_connection *conn, cptr str, int *size)
+{
+ return FALSE;
+}
+
+bool zsock_read_dummy(ip_connection *conn, char *str, int *len, bool raw)
+{
+ return FALSE;
+}
+
+bool zsock_accept_dummy(ip_connection *conn, ip_connection *child)
+{
+ return FALSE;
+}
+
+bool zsock_add_timer_dummy(timer_callback callback)
+{
+ return TRUE;
+}
+
+bool zsock_remove_timer_dummy(timer_callback callback)
+{
+ return TRUE;
+}
+
+void dummy_socks()
+{
+ zsock.setup = zsock_setup_dummy;
+ zsock.unsetup = zsock_unsetup_dummy;
+ zsock.open = zsock_open_dummy;
+ zsock.close = zsock_close_dummy;
+ zsock.write = zsock_write_dummy;
+ zsock.read = zsock_read_dummy;
+ zsock.accept = zsock_accept_dummy;
+ zsock.can_read = zsock_can_read_dummy;
+ zsock.wait = zsock_wait_dummy;
+ zsock.add_timer = zsock_add_timer_dummy;
+ zsock.remove_timer = zsock_remove_timer_dummy;
+}
+
+/*
+ * Initialize the hooks
+ */
+static bool init_once = TRUE;
+bool zsock_init()
+{
+ /* Sadly on some platforms we will be called 2 times ... */
+ if (init_once)
+ {
+ /* Set the timers */
+ zsock.__timers = 0;
+ zsock.__timer_callbacks = NULL;
+ init_once = FALSE;
+ }
+
+ /* Set the few system independants functions */
+ zsock.new_connection = zsock_new_connection;
+ zsock.free_connection = zsock_free_connection;
+ zsock.set_lose_connection = zsock_set_lose_connection;
+ zsock.write_simple = zsock_write_simple;
+ zsock.read_simple = zsock_read_simple;
+
+#ifdef USE_WINSOCK
+ if (init_socks_win())
+ {
+ zsock.setup = zsock_setup_win;
+ zsock.unsetup = zsock_unsetup_win;
+ zsock.open = zsock_open_win;
+ zsock.close = zsock_close_win;
+ zsock.write = zsock_write_win;
+ zsock.read = zsock_read_win;
+ zsock.accept = zsock_accept_win;
+ zsock.can_read = zsock_can_read_win;
+ zsock.wait = zsock_wait_win;
+ zsock.add_timer = zsock_add_timer_win;
+ zsock.remove_timer = zsock_remove_timer_win;
+ return TRUE;
+ }
+ else
+ {
+ dummy_socks();
+ return TRUE;
+ }
+#elif defined(USE_UNIXSOCK)
+zsock.setup = zsock_setup_unix;
+ zsock.unsetup = zsock_unsetup_unix;
+ zsock.open = zsock_open_unix;
+ zsock.close = zsock_close_unix;
+ zsock.write = zsock_write_unix;
+ zsock.read = zsock_read_unix;
+ zsock.accept = zsock_accept_unix;
+ zsock.can_read = zsock_can_read_unix;
+ zsock.wait = zsock_wait_unix;
+ zsock.add_timer = zsock_add_timer_unix;
+ zsock.remove_timer = zsock_remove_timer_unix;
+ return TRUE;
+#else
+ dummy_socks();
+ return TRUE;
+#endif
+}