diff options
author | Bardur Arantsson <bardur@scientician.net> | 2010-01-08 20:28:34 +0100 |
---|---|---|
committer | Bardur Arantsson <bardur@scientician.net> | 2010-01-08 23:46:06 +0100 |
commit | 6aa48afdd57d03314fdf4be6c9da911c32277c84 (patch) | |
tree | 2dc401f9aae2dc6736d2fc3811c8f8099d3eabe6 /src/z-sock.c |
Import tome-2.3.5.
Diffstat (limited to 'src/z-sock.c')
-rw-r--r-- | src/z-sock.c | 787 |
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 +} |