--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/frontlib/socket.c Sun Jun 03 01:24:18 2012 +0200
@@ -0,0 +1,149 @@
+#include "socket.h"
+#include "logging.h"
+#include <stdlib.h>
+#include <SDL_net.h>
+#include <time.h>
+
+typedef struct _flib_tcpsocket {
+ TCPsocket sock;
+ SDLNet_SocketSet sockset;
+} _flib_tcpsocket;
+
+typedef struct _flib_acceptor {
+ TCPsocket sock;
+ uint16_t port;
+} _flib_acceptor;
+
+static uint32_t get_peer_ip(TCPsocket sock) {
+ IPaddress *addr = SDLNet_TCP_GetPeerAddress(sock);
+ return SDLNet_Read32(&addr->host);
+}
+
+static bool connection_is_local(TCPsocket sock) {
+ return get_peer_ip(sock) == (uint32_t)((127UL<<24)+1); // 127.0.0.1
+}
+
+flib_acceptor flib_acceptor_create(uint16_t port) {
+ flib_acceptor result = malloc(sizeof(_flib_acceptor));
+ if(!result) {
+ flib_log_e("Out of memory!");
+ return NULL;
+ }
+
+ IPaddress addr;
+ addr.host = INADDR_ANY;
+
+ if(port > 0) {
+ result->port = port;
+ SDLNet_Write16(port, &addr.port);
+ result->sock = SDLNet_TCP_Open(&addr);
+ if(result->sock) {
+ return result;
+ } else {
+ flib_log_e("Unable to listen on port %u: %s", port, SDLNet_GetError());
+ free(result);
+ return NULL;
+ }
+ } else {
+ /* SDL_net does not seem to have a way to listen on a random unused port
+ and find out which port that is, so let's try to find one ourselves. */
+ // TODO: Is socket binding fail-fast on all platforms?
+ srand(time(NULL));
+ rand();
+ for(int i=0; i<1000; i++) {
+ // IANA suggests using ports in the range 49152-65535 for things like this
+ result->port = 49152+(rand()%(65535-49152));
+ SDLNet_Write16(result->port, &addr.port);
+ result->sock = SDLNet_TCP_Open(&addr);
+ if(result->sock) {
+ return result;
+ } else {
+ flib_log_i("Unable to listen on port %u: %s", result->port, SDLNet_GetError());
+ }
+ }
+ flib_log_e("Unable to listen on a random unused port.");
+ free(result);
+ return NULL;
+ }
+}
+
+uint16_t flib_acceptor_listenport(flib_acceptor acceptor) {
+ return acceptor->port;
+}
+
+void flib_acceptor_close(flib_acceptor *acceptorptr) {
+ if(acceptorptr == NULL || *acceptorptr == NULL) {
+ return;
+ }
+ SDLNet_TCP_Close((*acceptorptr)->sock);
+ free(*acceptorptr);
+ *acceptorptr = NULL;
+}
+
+flib_tcpsocket flib_socket_accept(flib_acceptor acceptor, bool localOnly) {
+ flib_tcpsocket result = NULL;
+ if(!acceptor) {
+ return NULL;
+ }
+ while(result==NULL) {
+ TCPsocket sock = SDLNet_TCP_Accept(acceptor->sock);
+ if(!sock) {
+ // No incoming connections
+ return NULL;
+ }
+ if(localOnly && !connection_is_local(sock)) {
+ flib_log_i("Rejected nonlocal connection attempt from %s", flib_format_ip(get_peer_ip(sock)));
+ SDLNet_TCP_Close(sock);
+ } else {
+ result = malloc(sizeof(_flib_tcpsocket));
+ if(result==NULL) {
+ flib_log_e("Out of memory!");
+ SDLNet_TCP_Close(sock);
+ return NULL;
+ }
+ result->sock = sock;
+ result->sockset = SDLNet_AllocSocketSet(1);
+ if(result->sockset==NULL) {
+ flib_log_e("Out of memory!");
+ SDLNet_TCP_Close(sock);
+ free(result);
+ return NULL;
+ }
+ SDLNet_AddSocket(result->sockset, (SDLNet_GenericSocket)result->sock);
+ }
+ }
+ return result;
+}
+
+void flib_socket_close(flib_tcpsocket *sockptr) {
+ if(sockptr==NULL || *sockptr == NULL) {
+ return;
+ }
+ flib_tcpsocket sock = *sockptr;
+ SDLNet_DelSocket(sock->sockset, (SDLNet_GenericSocket)sock->sock);
+ SDLNet_TCP_Close(sock->sock);
+ SDLNet_FreeSocketSet(sock->sockset);
+ free(sock);
+ *sockptr = NULL;
+}
+
+int flib_socket_nbrecv(flib_tcpsocket sock, void *data, int maxlen) {
+ if(!sock) {
+ flib_log_e("Attempt to receive on a NULL socket.");
+ return -1;
+ }
+ int readySockets = SDLNet_CheckSockets(sock->sockset, 0);
+ if(readySockets>0) {
+ int size = SDLNet_TCP_Recv(sock->sock, data, maxlen);
+ return size>0 ? size : -1;
+ } else if(readySockets==0) {
+ return 0;
+ } else {
+ flib_log_e("Error in select system call: %s", SDLNet_GetError());
+ return -1;
+ }
+}
+
+int flib_socket_send(flib_tcpsocket sock, void *data, int len) {
+ return SDLNet_TCP_Send(sock->sock, data, len);
+}