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/netconnection.c | 378 +++++++++++++++++++++++++++++ 1 file changed, 378 insertions(+) create mode 100644 src/uqm/supermelee/netplay/netconnection.c (limited to 'src/uqm/supermelee/netplay/netconnection.c') diff --git a/src/uqm/supermelee/netplay/netconnection.c b/src/uqm/supermelee/netplay/netconnection.c new file mode 100644 index 0000000..48ab46b --- /dev/null +++ b/src/uqm/supermelee/netplay/netconnection.c @@ -0,0 +1,378 @@ +/* + * 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 + */ + +#define NETCONNECTION_INTERNAL +#include "netplay.h" +#include "netconnection.h" + +#include "netrcv.h" + +#if defined(DEBUG) || defined(NETPLAY_DEBUG) +# include "libs/log.h" +#endif +#if defined(NETPLAY_DEBUG) && defined(NETPLAY_DEBUG_FILE) +# include "options.h" + // for configDir +#endif + +#include +#include +#if defined(NETPLAY_DEBUG) && defined(NETPLAY_DEBUG_FILE) +# include +# include +#endif + + +static void closeCallback(NetDescriptor *nd); +static void NetConnection_doClose(NetConnection *conn); + + +#include "nc_connect.ci" + +#if defined(NETPLAY_DEBUG) && defined(NETPLAY_DEBUG_FILE) +uio_Stream *netplayDebugFile; +#endif + +// Used as initial value for Agreement structures, by structure assignment. +const Agreement Agreement_nothingAgreed; + + +// The NetConnection keeps a pointer to the passed NetplayPeerOptions; +// do not free it as long as the NetConnection exists. +NetConnection * +NetConnection_open(int player, const NetplayPeerOptions *options, + NetConnection_ConnectCallback connectCallback, + NetConnection_CloseCallback closeCallback, + NetConnection_ErrorCallback errorCallback, + NetConnection_DeleteCallback deleteCallback, void *extra) { + NetConnection *conn; + + conn = malloc(sizeof (NetConnection)); + +#if defined(NETPLAY_DEBUG) && defined(NETPLAY_DEBUG_FILE) + { + char dumpFileName[PATH_MAX]; + time_t now; + struct tm *nowTm; + size_t strftimeResult; + + now = time (NULL); + if (now == (time_t) -1) { + log_add (log_Fatal, "time() failed: %s.", strerror (errno)); + abort (); + } + + nowTm = localtime(&now); + // XXX: I would like to use localtime_r(), but it isn't very + // portable (yet), and adding a check for it to the build.sh script + // is not worth the effort for a debugging function right now. + + strftimeResult = strftime (dumpFileName, sizeof dumpFileName, + "debug/netlog-%Y%m%d%H%M%S", nowTm); + if (strftimeResult == 0) { + log_add (log_Fatal, "strftime() failed: %s.", strerror (errno)); + abort (); + } + + // The user needs to create the debug/ dir manually. If there + // is no debug/ dir, no log will be created. + conn->debugFile = uio_fopen (configDir, dumpFileName, "wt"); + if (conn->debugFile == NULL) { + log_add (log_Debug, "Not creating a netplay debug log for " + "player %d.", player); + } else { + log_add (log_Debug, "Creating netplay debug log '%s' for " + "player %d.", dumpFileName, player); + if (netplayDebugFile == NULL) { + // Debug info relating to no specific network connection + // is sent to the first opened one. + netplayDebugFile = conn->debugFile; + } + } + } +#endif + + conn->nd = NULL; + conn->player = player; + conn->state = NetState_unconnected; + conn->options = options; + conn->extra = extra; + PacketQueue_init(&conn->queue); + + conn->connectCallback = connectCallback; + conn->closeCallback = closeCallback; + conn->errorCallback = errorCallback; + conn->deleteCallback = deleteCallback; + conn->readyCallback = NULL; + conn->readyCallbackArg = NULL; + conn->resetCallback = NULL; + conn->resetCallbackArg = NULL; + + conn->readBuf = malloc(NETPLAY_READBUFSIZE); + conn->readEnd = conn->readBuf; + + conn->stateData = NULL; + conn->stateFlags.connected = false; + conn->stateFlags.disconnected = false; + conn->stateFlags.discriminant = false; + conn->stateFlags.handshake.localOk = false; + conn->stateFlags.handshake.remoteOk = false; + conn->stateFlags.handshake.canceling = false; + conn->stateFlags.ready.localReady = false; + conn->stateFlags.ready.remoteReady = false; + conn->stateFlags.reset.localReset = false; + conn->stateFlags.reset.remoteReset = false; + conn->stateFlags.agreement = Agreement_nothingAgreed; + conn->stateFlags.inputDelay = 0; +#ifdef NETPLAY_CHECKSUM + conn->stateFlags.checksumInterval = NETPLAY_CHECKSUM_INTERVAL; +#endif + +#ifdef NETPLAY_STATISTICS + { + size_t i; + + conn->statistics.packetsReceived = 0; + conn->statistics.packetsSent = 0; + for (i = 0; i < PACKET_NUM; i++) + { + conn->statistics.packetTypeReceived[i] = 0; + conn->statistics.packetTypeSent[i] = 0; + } + } +#endif + + NetConnection_go(conn); + + return conn; +} + +static void +NetConnection_doDeleteCallback(NetConnection *conn) { + if (conn->deleteCallback != NULL) { + //NetConnection_incRef(conn); + conn->deleteCallback(conn); + //NetConnection_decRef(conn); + } +} + +static void +NetConnection_delete(NetConnection *conn) { + NetConnection_doDeleteCallback(conn); + if (conn->stateData != NULL) { + NetConnectionStateData_release(conn->stateData); + conn->stateData = NULL; + } + free(conn->readBuf); + PacketQueue_uninit(&conn->queue); + +#ifdef NETPLAY_DEBUG_FILE + if (conn->debugFile != NULL) { + if (netplayDebugFile == conn->debugFile) { + // There may be other network connections, with an open + // debug file, but we don't know about that. + // The debugging person just has to work around that. + netplayDebugFile = NULL; + } + uio_fclose(conn->debugFile); + } +#endif + + free(conn); +} + +static void +Netplay_doCloseCallback(NetConnection *conn) { + if (conn->closeCallback != NULL) { + //NetConnection_incRef(conn); + conn->closeCallback(conn); + //NetConnection_decRef(conn); + } +} + +// Auxiliary function for closing, used by both closeCallback() and +// NetConnection_close() +static void +NetConnection_doClose(NetConnection *conn) { + conn->stateFlags.connected = false; + conn->stateFlags.disconnected = true; + + // First the callback, so that it can still use the information + // of what is the current state, and the stateData: + Netplay_doCloseCallback(conn); + + NetConnection_setState(conn, NetState_unconnected); +} + +// Called when the NetDescriptor is shut down. +static void +closeCallback(NetDescriptor *nd) { + NetConnection *conn = (NetConnection *) NetDescriptor_getExtra(nd); + if (conn == NULL) + return; + conn->nd = NULL; + NetConnection_doClose(conn); +} + +// Close and release a NetConnection. +void +NetConnection_close(NetConnection *conn) { + if (conn->nd != NULL) { + NetDescriptor_setCloseCallback(conn->nd, NULL); + // We're not interested in the close callback of the + // NetDescriptor anymore. + NetDescriptor_close(conn->nd); + // This would queue the close callback. + conn->nd = NULL; + } + if (!conn->stateFlags.disconnected) + NetConnection_doClose(conn); + NetConnection_delete(conn); +} + +void +NetConnection_doErrorCallback(NetConnection *nd, int err) { + NetConnectionError error; + + if (nd->errorCallback != NULL) { + error.state = nd->state; + error.err = err; + } + (*nd->errorCallback)(nd, &error); +} + +void +NetConnection_setStateData(NetConnection *conn, + NetConnectionStateData *stateData) { + conn->stateData = stateData; +} + +NetConnectionStateData * +NetConnection_getStateData(const NetConnection *conn) { + return conn->stateData; +} + +void +NetConnection_setExtra(NetConnection *conn, void *extra) { + conn->extra = extra; +} + +void * +NetConnection_getExtra(const NetConnection *conn) { + return conn->extra; +} + +void +NetConnection_setReadyCallback(NetConnection *conn, + NetConnection_ReadyCallback callback, void *arg) { + conn->readyCallback = callback; + conn->readyCallbackArg = arg; +} + +NetConnection_ReadyCallback +NetConnection_getReadyCallback(const NetConnection *conn) { + return conn->readyCallback; +} + +void * +NetConnection_getReadyCallbackArg(const NetConnection *conn) { + return conn->readyCallbackArg; +} + +void +NetConnection_setResetCallback(NetConnection *conn, + NetConnection_ResetCallback callback, void *arg) { + conn->resetCallback = callback; + conn->resetCallbackArg = arg; +} + +NetConnection_ResetCallback +NetConnection_getResetCallback(const NetConnection *conn) { + return conn->resetCallback; +} + +void * +NetConnection_getResetCallbackArg(const NetConnection *conn) { + return conn->resetCallbackArg; +} + +void +NetConnection_setState(NetConnection *conn, NetState state) { +#ifdef NETPLAY_DEBUG + log_add(log_Debug, "NETPLAY: [%d] +/- Connection state changed to: " + "%s.\n", conn->player, netStateData[state].name); +#endif +#ifdef DEBUG + if (state == conn->state) { + log_add(log_Warning, "NETPLAY: [%d] Connection state set to %s " + "while already in that state.\n", + conn->player, netStateData[state].name); + } +#endif + conn->state = state; +} + +NetState +NetConnection_getState(const NetConnection *conn) { + return conn->state; +} + +bool +NetConnection_getDiscriminant(const NetConnection *conn) { + return conn->stateFlags.discriminant; +} + +const NetplayPeerOptions * +NetConnection_getPeerOptions(const NetConnection *conn) { + return conn->options; +} + +bool +NetConnection_isConnected(const NetConnection *conn) { + return conn->stateFlags.connected; +} + +int +NetConnection_getPlayerNr(const NetConnection *conn) { + return conn->player; +} + +size_t +NetConnection_getInputDelay(const NetConnection *conn) { + return conn->stateFlags.inputDelay; +} + +#ifdef NETPLAY_CHECKSUM +ChecksumBuffer * +NetConnection_getChecksumBuffer(NetConnection *conn) { + return &conn->checksumBuffer; +} + +size_t +NetConnection_getChecksumInterval(const NetConnection *conn) { + return conn->stateFlags.checksumInterval; +} +#endif /* NETPLAY_CHECKSUM */ + +#ifdef NETPLAY_STATISTICS +NetStatistics * +NetConnection_getStatistics(NetConnection *conn) { + return &conn->statistics; +} +#endif + -- cgit v1.2.3