From 7f6002caba3f0a6749820c2772161caf55b8d267 Mon Sep 17 00:00:00 2001 From: neonloop Date: Fri, 7 May 2021 20:00:12 +0000 Subject: Initial commit (uqm-0.8.0) --- src/uqm/supermelee/netplay/nc_connect.ci | 300 +++++++++++++++++++++++++++++++ 1 file changed, 300 insertions(+) create mode 100644 src/uqm/supermelee/netplay/nc_connect.ci (limited to 'src/uqm/supermelee/netplay/nc_connect.ci') diff --git a/src/uqm/supermelee/netplay/nc_connect.ci b/src/uqm/supermelee/netplay/nc_connect.ci new file mode 100644 index 0000000..6c67fed --- /dev/null +++ b/src/uqm/supermelee/netplay/nc_connect.ci @@ -0,0 +1,300 @@ +/* + * Copyright 2006 Serge van den Boom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +// This file is part of netconnection.c, from where it is #included. + +static inline ConnectStateData *ConnectStateData_alloc(void); +static inline ConnectStateData *ConnectStateData_new(void); +static inline void ConnectStateData_free(ConnectStateData *connectStateData); +static void ConnectStateData_delete(ConnectStateData *connectStateData); + +static int NetConnection_go(NetConnection *conn); +static ListenState *NetConnection_serverGo(NetConnection *conn); +static ConnectState *NetConnection_clientGo(NetConnection *conn); +static void NetConnection_connected(NetConnection *conn); +static void NetConnection_connectedServerCallback(ListenState *listenState, + NetDescriptor *listenNd, NetDescriptor *newNd, + const struct sockaddr *addr, SOCKLEN_T addrLen); +static void NetConnection_connectedClientCallback(ConnectState *connectState, + NetDescriptor *newNd, const struct sockaddr *addr, SOCKLEN_T addrLen); +static void NetConnection_connectedServerErrorCallback( + ListenState *listenState, const ListenError *listenError); +static void NetConnection_connectedClientErrorCallback( + ConnectState *connectState, const ConnectError *connectError); + + +//////////////////////////////////////////////////////////////////////////// + + +static inline ConnectStateData * +ConnectStateData_alloc(void) { + return (ConnectStateData *) malloc(sizeof (ConnectStateData)); +} + +static inline ConnectStateData * +ConnectStateData_new(void) { + ConnectStateData *connectStateData = ConnectStateData_alloc(); + connectStateData->releaseFunction = + (NetConnectionStateData_ReleaseFunction) ConnectStateData_delete; + return connectStateData; +} + +static inline void +ConnectStateData_free(ConnectStateData *connectStateData) { + free(connectStateData); +} + +static void +ConnectStateData_delete(ConnectStateData *connectStateData) { + if (connectStateData->isServer) { + ListenState *listenState = connectStateData->state.listenState; + ListenState_close(listenState); + } else { + ConnectState *connectState = connectStateData->state.connectState; + ConnectState_close(connectState); + } + ConnectStateData_free(connectStateData); +} + + +//////////////////////////////////////////////////////////////////////////// + + +static int +NetConnection_go(NetConnection *conn) { + ConnectStateData *connectStateData; + + if (NetConnection_isConnected(conn)) + return 0; + + if (conn->options->isServer) { + ListenState *listenState; + listenState = NetConnection_serverGo(conn); + if (listenState == NULL) { + // errno is set + return -1; + } + connectStateData = ConnectStateData_new(); + connectStateData->state.listenState = listenState; + } else { + ConnectState *connectState; + connectState = NetConnection_clientGo(conn); + if (connectState == NULL) { + // errno is set + return -1; + } + connectStateData = ConnectStateData_new(); + connectStateData->state.connectState = connectState; + } + connectStateData->isServer = conn->options->isServer; + + NetConnection_setStateData(conn, (void *) connectStateData); + return 0; +} + +static ListenState * +NetConnection_serverGo(NetConnection *conn) { + ListenFlags listenFlags; + ListenState *result; + + assert(conn->state == NetState_unconnected); + assert(conn->options->isServer); + + NetConnection_setState(conn, NetState_connecting); + + memset (&listenFlags, 0, sizeof listenFlags); + listenFlags.familyDemand = +#if NETPLAY == NETPLAY_IPV4 + PF_inet; +#else + PF_unspec; +#endif + listenFlags.familyPrefer = PF_unspec; + listenFlags.backlog = NETPLAY_LISTEN_BACKLOG; + + result = listenPort(conn->options->port, IPProto_tcp, &listenFlags, + NetConnection_connectedServerCallback, + NetConnection_connectedServerErrorCallback, (void *) conn); + + return result; +} + +static ConnectState * +NetConnection_clientGo(NetConnection *conn) { + ConnectFlags connectFlags; + ConnectState *result; + + assert(conn->state == NetState_unconnected); + assert(!conn->options->isServer); + + NetConnection_setState(conn, NetState_connecting); + + memset (&connectFlags, 0, sizeof connectFlags); + connectFlags.familyDemand = +#if NETPLAY == NETPLAY_IPV4 + PF_inet; +#else + PF_unspec; +#endif + connectFlags.familyPrefer = PF_unspec; + connectFlags.timeout = NETPLAY_CONNECTTIMEOUT; + connectFlags.retryDelayMs = NETPLAY_RETRYDELAY; + + result = connectHostByName(conn->options->host, conn->options->port, + IPProto_tcp, &connectFlags, NetConnection_connectedClientCallback, + NetConnection_connectedClientErrorCallback, (void *) conn); + + return result; +} + +// Called when an incoming connection has been established. +// The caller gives up ownership of newNd +static void +NetConnection_connectedServerCallback(ListenState *listenState, + NetDescriptor *listenNd, NetDescriptor *newNd, + const struct sockaddr *addr, SOCKLEN_T addrLen) { + NetConnection *conn = + (NetConnection *) ListenState_getExtra(listenState); + + assert(conn->nd == NULL); + + conn->nd = newNd; + // No incRef(); the caller gives up ownership. + NetDescriptor_setExtra(conn->nd, (void *) conn); + + (void) Socket_setInteractive(NetDescriptor_getSocket(conn->nd)); + // Ignore errors; it's not a big deal. In debug mode, a message + // will already have been printed from the function itself. + + conn->stateFlags.discriminant = true; + + NetConnection_connected(conn); + (void) listenNd; + (void) addr; + (void) addrLen; +} + +// Called when an outgoing connection has been established. +// The caller gives up ownership of newNd +static void +NetConnection_connectedClientCallback(ConnectState *connectState, + NetDescriptor *newNd, + const struct sockaddr *addr, SOCKLEN_T addrLen) { + NetConnection *conn = + (NetConnection *) ConnectState_getExtra(connectState); + + assert(conn->nd == NULL); + + conn->nd = newNd; + // No incRef(); the caller gives up ownership. + NetDescriptor_setExtra(conn->nd, (void *) conn); + + (void) Socket_setInteractive(NetDescriptor_getSocket(conn->nd)); + // Ignore errors; it's not a big deal. In debug mode, a message + // will already have been printed from the function itself. + + conn->stateFlags.discriminant = false; + + NetConnection_connected(conn); + (void) addr; + (void) addrLen; +} + +// Called when a connection has been established. +static void +NetConnection_connected(NetConnection *conn) { + ConnectStateData *connectStateData; + + conn->stateFlags.connected = true; + NetConnection_setState(conn, NetState_init); + + connectStateData = (ConnectStateData *) NetConnection_getStateData(conn); + ConnectStateData_delete(connectStateData); + NetConnection_setStateData(conn, NULL); + + NetDescriptor_setReadCallback(conn->nd, dataReadyCallback); + NetDescriptor_setCloseCallback(conn->nd, closeCallback); + + (*conn->connectCallback)(conn); +} + +static void +NetConnection_connectedServerErrorCallback(ListenState *listenState, + const ListenError *listenError) { + NetConnection *conn = + (NetConnection *) ListenState_getExtra(listenState); + NetConnectionError error; + + conn->stateFlags.connected = false; + conn->stateFlags.disconnected = true; + ListenState_close(listenState); + NetConnection_setState(conn, NetState_unconnected); + + { + ConnectStateData *connectStateData; + connectStateData = + (ConnectStateData *) NetConnection_getStateData(conn); + ConnectStateData_free(connectStateData); + NetConnection_setStateData(conn, NULL); + } + + if (conn->errorCallback != NULL) { + error.state = NetState_connecting; + error.err = listenError->err; + error.extra.listenError = listenError; + //NetConnection_incRef(conn); + (*conn->errorCallback)(conn, &error); + //NetConnection_decRef(conn); + } + + NetConnection_close(conn); +} + +static void +NetConnection_connectedClientErrorCallback(ConnectState *connectState, + const ConnectError *connectError) { + NetConnection *conn = + (NetConnection *) ConnectState_getExtra(connectState); + NetConnectionError error; + + conn->stateFlags.connected = false; + conn->stateFlags.disconnected = true; + ConnectState_close(connectState); + NetConnection_setState(conn, NetState_unconnected); + + { + ConnectStateData *connectStateData; + connectStateData = + (ConnectStateData *) NetConnection_getStateData(conn); + ConnectStateData_free(connectStateData); + NetConnection_setStateData(conn, NULL); + } + + if (conn->errorCallback != NULL) { + error.state = NetState_connecting; + error.err = connectError->err; + error.extra.connectError = connectError; + //NetConnection_incRef(conn); + (*conn->errorCallback)(conn, &error); + //NetConnection_decRef(conn); + } + + NetConnection_close(conn); +} + + -- cgit v1.2.3