This is a quick draft for some better and sane network primitives. One
step toward better network code? Your opinion most welcome.

(Compiles but not tested yet. I cannot test it properly before adding
it (since I need another host to test against), and I'm not adding it
before I see some thumbs up.)

 - Per
Index: src/network.c
===================================================================
--- src/network.c	(revision 0)
+++ src/network.c	(revision 0)
@@ -0,0 +1,74 @@
+/*
+	This file is part of Warzone 2100.
+	Copyright (C) 1999-2004  Eidos Interactive
+	Copyright (C) 2005-2007  Warzone Resurrection Project
+
+	Warzone 2100 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.
+
+	Warzone 2100 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 Warzone 2100; if not, write to the Free Software
+	Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+/* Look at header file for documentation of interface */
+
+#include "network.h"
+
+/* globals - needed for inlining functions from header */
+NETMSG net_msg;
+enum net_direction_enum net_direction;
+
+bool net_string(char *value, uint16_t *length, uint16_t maxlength)
+{
+	uint16_t *store_length = (uint16_t *)&net_msg.body[net_msg.size];
+	char *store = &net_msg.body[net_msg.size + sizeof(uint16_t)];
+	size_t size;
+
+	// check length for size field before accessing it
+	if (sizeof(uint16_t) + net_msg.size > MaxMsgSize || !net_msg.status)
+	{
+		net_msg.status = FALSE;
+		return FALSE;
+	}
+	size = sizeof(char) * *store_length + sizeof(uint16_t);
+	// now check length for both fields
+	if (size + net_msg.size > MaxMsgSize)
+	{
+		net_msg.status = FALSE;
+		return FALSE;
+	}
+	assert(maxlength + net_msg.size + sizeof(uint16_t) <= MaxMsgSize);
+	if (net_direction == NET_WRITE)
+	{
+		assert(*length < maxlength);
+		assert(strnlen(value, maxlength) < *length);
+		*store_length = *length;
+		memcpy(store, value, *length);
+	} else {
+		*length = *store_length;
+		if (*length > maxlength)
+		{
+			debug(LOG_ERROR, "Packet string longer (%lu) than max size of %lu",
+			      (unsigned long)*length, (unsigned long)maxlength);
+			net_msg.status = FALSE;
+			return FALSE;
+		}
+		if (strnlen(store, *length) == *length)
+		{
+			debug(LOG_ERROR, "Packet string has no zero termination!");
+			net_msg.status = FALSE;
+			return FALSE;
+		}
+		memcpy(value, store, *length);
+	}
+	net_msg.size += size;
+	return TRUE;
+}
Index: src/network.h
===================================================================
--- src/network.h	(revision 0)
+++ src/network.h	(revision 0)
@@ -0,0 +1,145 @@
+/*
+	This file is part of Warzone 2100.
+	Copyright (C) 1999-2004  Eidos Interactive
+	Copyright (C) 2005-2007  Warzone Resurrection Project
+
+	Warzone 2100 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.
+
+	Warzone 2100 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 Warzone 2100; if not, write to the Free Software
+	Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#ifndef _network_h
+#define _network_h
+
+#include <arpa/inet.h>
+
+#include "lib/framework/frame.h"
+#include "statsdef.h"
+#include "base.h"
+#include "droiddef.h"
+#include "structuredef.h"
+#include "featuredef.h"
+#include "functiondef.h"
+#include "multiplay.h"
+#include "lib/netplay/netplay.h"
+
+/*** The new network API ***/
+
+enum net_direction_enum {
+	NET_READ, NET_WRITE, NET_INVALID
+};
+
+/*
+	This API is inspired by OpenGL and XDR. You use the same function
+	to both read and write, just with different binding (begin parameter).
+
+	These are the functions to use:
+	-------------------------------
+
+	net_begin(enum_direction_enum);
+
+	// pass a pointer to the value you wish to send or receive
+	net_uint8_t(uint8_t*);
+	net_uint16_t(uint16_t*);
+	net_uint32_t(uint32_t*);
+	net_uint64_t(uint64_t*);
+	net_int8_t(int8_t*);
+	net_int16_t(int16_t*);
+	net_int32_t(int32_t*);
+	net_int64_t(int64_t*);
+
+	// pass a pointer to the reference value (ID) of the object
+	// you wish to send or receive, then a pointer to the pointer
+	// of the object itself
+	net_object(uint32_t*, BASE_OBJECT**);
+
+	// send a string, pass the string and a pointer to its length, then
+	// the maximum length this field could ever (safely) have
+	net_string(char*, uint16_t*, uint16_t);
+
+	net_end();
+*/
+
+
+/*** Implementation follows ***/
+
+// these are private members - hands off!
+extern NETMSG net_msg;
+extern enum net_direction_enum net_direction;
+
+static inline void net_begin(enum net_direction_enum direction)
+{
+	net_direction = direction;
+	net_msg.size = 0;
+	net_msg.status = TRUE;
+}
+
+static inline void net_end(void)
+{
+	net_direction = NET_INVALID;
+}
+
+/* General template for most common send/receive functions. Or what you
+ * have to do when you do not use C++. Yes, I know. */
+#define NETFUNCDEF(valtype, hostswap, netswap) \
+	static inline bool net_ ## valtype (valtype *value) \
+	{ \
+		valtype *store = (valtype *)&net_msg.body[net_msg.size]; \
+		const int size = sizeof(valtype); \
+		\
+		if (size + net_msg.size > MaxMsgSize || !net_msg.status) \
+		{ \
+			net_msg.status = FALSE; \
+			return FALSE; \
+		} \
+		if (net_direction == NET_WRITE) \
+		{ \
+			*store = netswap(*value); \
+		} else { \
+			*value = hostswap(*store); \
+		} \
+		net_msg.size += size; \
+		return TRUE; \
+	}
+NETFUNCDEF(uint8_t, , )
+NETFUNCDEF(uint16_t, htons, ntohs)
+NETFUNCDEF(uint32_t, htonl, ntohl)
+NETFUNCDEF(int8_t, , )
+NETFUNCDEF(int16_t, htons, ntohs)
+NETFUNCDEF(int32_t, htonl, ntohl)
+
+/* Strings are sent prefixed with an uint16_t giving its actual length. The
+ * string must be null terminated. This one is too long to be inline. */
+bool net_string(char *value, uint16_t *length, uint16_t maxlength);
+
+static inline bool net_id(uint32_t *value, BASE_OBJECT **psObj)
+{
+	uint32_t *store = (uint32_t *)&net_msg.body[net_msg.size];
+	const int size = sizeof(uint32_t);
+
+	if (size + net_msg.size > MaxMsgSize || !net_msg.status)
+	{
+		net_msg.status = FALSE;
+		return FALSE;
+	}
+	if (net_direction == NET_WRITE)
+	{
+		*store = *value;
+	} else {
+		*psObj = IdToPointer(*store, ANYPLAYER);
+	}
+	net_msg.size += size;
+	return TRUE;
+}
+
+#endif
Index: src/Makefile.am
===================================================================
--- src/Makefile.am	(revision 1604)
+++ src/Makefile.am	(working copy)
@@ -28,7 +28,7 @@
 	researchdef.h resource.h scores.h scriptai.h scriptcb.h scriptextern.h scriptfuncs.h \
 	scriptobj.h scripttabs.h scriptvals.h selection.h seqdisp.h stats.h statsdef.h \
 	structure.h structuredef.h target.h text.h texture.h transporter.h visibility.h \
-	warcam.h warzoneconfig.h weapons.h winmain.h wrappers.h
+	warcam.h warzoneconfig.h weapons.h winmain.h wrappers.h network.h
 
 warzone2100_SOURCES = scriptvals_parser.tab.c scriptvals_lexer.lex.c \
 	level_lexer.lex.c ai.c aiexperience.c astar.c action.c advvis.c atmos.c bridge.c \
@@ -46,7 +46,7 @@
 	bucket3d.c clparse.c configuration.c csnap.c display3d.c drive.c function.c game.c \
 	ingameop.c keyedit.c loadsave.c mission.c multigifts.c multijoin.c multilimit.c \
 	multiplay.c multistruct.c oprint.c power.c projectile.c seqdisp.c structure.c \
-	target.c warzoneconfig.c
+	target.c warzoneconfig.c network.c
 
 warzone2100_LDADD = $(top_builddir)/lib/widget/libwidget.a \
 	$(top_builddir)/lib/sound/libsound.a $(top_builddir)/lib/sequence/libsequence.a \
Index: src/multiplay.c
===================================================================
--- src/multiplay.c	(revision 1604)
+++ src/multiplay.c	(working copy)
@@ -68,6 +68,8 @@
 #include "multistat.h"
 #include "multigifts.h"								// gifts and alliances.
 
+#include "network.h"
+
 // ////////////////////////////////////////////////////////////////////////////
 // ////////////////////////////////////////////////////////////////////////////
 // globals.
Index: src/Makefile.raw
===================================================================
--- src/Makefile.raw	(revision 1604)
+++ src/Makefile.raw	(working copy)
@@ -2,6 +2,7 @@
 include $(MAKERULES)/configure.mk
 
 SRC=ai.c \
+	network.c \
 	aiexperience.c \
 	astar.c \
 	action.c \
Index: lib/netplay/netplay.h
===================================================================
--- lib/netplay/netplay.h	(revision 1604)
+++ lib/netplay/netplay.h	(working copy)
@@ -67,7 +67,7 @@
 	uint8_t		paddedBytes;		// numberofbytes appended for encryption
 	uint8_t		type;			// type of packet
 	uint8_t		destination;		// player to send to, or NET_ALL_PLAYERS
-	uint16_t	counter;		// where in body we are currently
+	bool		status;			// whether packet is compiled successfully
 	char 		body[MaxMsgSize];
 } NETMSG;
 
@@ -112,7 +112,7 @@
 	uint32_t        bCaptureInUse;			// true if someone is speaking.
 	uint32_t        bAllowCaptureRecord;		// true if speech can be recorded.
 	uint32_t        bAllowCapturePlay;		// true if speech can be played.
-} NETPLAY, *LPNETPLAY;
+} NETPLAY;
 
 // ////////////////////////////////////////////////////////////////////////
 // variables
_______________________________________________
Warzone-dev mailing list
[email protected]
https://mail.gna.org/listinfo/warzone-dev

Reply via email to