--- a/project_files/frontlib/hwconsts.h Fri Jun 15 19:57:25 2012 +0200
+++ b/project_files/frontlib/hwconsts.h Tue Jun 19 21:17:05 2012 +0200
@@ -8,6 +8,8 @@
#define HEDGEHOGS_PER_TEAM 8
#define NETGAME_DEFAULT_PORT 46631
+#define PROTOCOL_VERSION 42
+#define MIN_SERVER_VERSION 1
#define GAMEMOD_PERHOGAMMO_MASKBIT 22
#define GAMEMOD_SHAREDAMMO_MASKBIT 16
--- a/project_files/frontlib/ipc/gameconn.c Fri Jun 15 19:57:25 2012 +0200
+++ b/project_files/frontlib/ipc/gameconn.c Tue Jun 19 21:17:05 2012 +0200
@@ -1,5 +1,5 @@
#include "gameconn.h"
-#include "ipcconn.h"
+#include "ipcbase.h"
#include "ipcprotocol.h"
#include "../util/logging.h"
#include "../util/util.h"
@@ -15,7 +15,7 @@
} gameconn_state;
struct _flib_gameconn {
- flib_ipcconn *connection;
+ flib_ipcbase *ipcBase;
flib_vector *configBuffer;
flib_vector *demoBuffer;
char *playerName;
@@ -38,8 +38,8 @@
void (*onGameRecordedCb)(void *context, const uint8_t *record, int size, bool isSavegame);
void *onGameRecordedCtx;
- void (*onNetMessageCb)(void *context, const uint8_t *em, int size);
- void *onNetMessageCtx;
+ void (*onEngineMessageCb)(void *context, const uint8_t *em, int size);
+ void *onEngineMessageCtx;
bool running;
bool destroyRequested;
@@ -52,7 +52,7 @@
}
static void defaultCallback_onChat(void* context, const char *msg, bool teamchat) {}
static void defaultCallback_onGameRecorded(void *context, const uint8_t *record, int size, bool isSavegame) {}
-static void defaultCallback_onNetMessage(void *context, const uint8_t *em, int size) {}
+static void defaultCallback_onEngineMessage(void *context, const uint8_t *em, int size) {}
static void clearCallbacks(flib_gameconn *conn) {
conn->onConnectCb = &defaultCallback_onConnect;
@@ -60,17 +60,17 @@
conn->onErrorMessageCb = &defaultCallback_onErrorMessage;
conn->onChatCb = &defaultCallback_onChat;
conn->onGameRecordedCb = &defaultCallback_onGameRecorded;
- conn->onNetMessageCb = &defaultCallback_onNetMessage;
+ conn->onEngineMessageCb = &defaultCallback_onEngineMessage;
}
static flib_gameconn *flib_gameconn_create_partial(bool record, const char *playerName, bool netGame) {
flib_gameconn *result = NULL;
flib_gameconn *tempConn = flib_calloc(1, sizeof(flib_gameconn));
if(tempConn) {
- tempConn->connection = flib_ipcconn_create();
+ tempConn->ipcBase = flib_ipcbase_create();
tempConn->configBuffer = flib_vector_create();
tempConn->playerName = flib_strdupnull(playerName);
- if(tempConn->connection && tempConn->configBuffer && tempConn->playerName) {
+ if(tempConn->ipcBase && tempConn->configBuffer && tempConn->playerName) {
if(record) {
tempConn->demoBuffer = flib_vector_create();
}
@@ -135,7 +135,7 @@
clearCallbacks(conn);
conn->destroyRequested = true;
} else {
- flib_ipcconn_destroy(conn->connection);
+ flib_ipcbase_destroy(conn->ipcBase);
flib_vector_destroy(conn->configBuffer);
flib_vector_destroy(conn->demoBuffer);
free(conn->playerName);
@@ -149,7 +149,7 @@
flib_log_e("null parameter in flib_gameconn_getport");
return 0;
} else {
- return flib_ipcconn_port(conn->connection);
+ return flib_ipcbase_port(conn->ipcBase);
}
}
@@ -201,7 +201,7 @@
int result = -1;
if(!conn || (!data && len>0)) {
flib_log_e("null parameter in flib_gameconn_send_enginemsg");
- } else if(!flib_ipcconn_send_raw(conn->connection, data, len)) {
+ } else if(!flib_ipcbase_send_raw(conn->ipcBase, data, len)) {
demo_append(conn, data, len);
result = 0;
}
@@ -217,7 +217,7 @@
int size = snprintf((char*)converted+1, 256, "s%c%s", (char)msgtype, msg);
if(size>0) {
converted[0] = size>255 ? 255 : size;
- if(!flib_ipcconn_send_raw(conn->connection, converted, converted[0]+1)) {
+ if(!flib_ipcbase_send_raw(conn->ipcBase, converted, converted[0]+1)) {
demo_append(conn, converted, converted[0]+1);
result = 0;
}
@@ -233,7 +233,7 @@
flib_log_e("null parameter in flib_gameconn_send_chatmsg");
} else if(format_chatmessage(converted, playername, msg)) {
flib_log_e("Error formatting message in flib_gameconn_send_chatmsg");
- } else if(!flib_ipcconn_send_raw(conn->connection, converted, converted[0]+1)) {
+ } else if(!flib_ipcbase_send_raw(conn->ipcBase, converted, converted[0]+1)) {
demo_append(conn, converted, converted[0]+1);
result = 0;
}
@@ -285,23 +285,23 @@
}
}
-void flib_gameconn_onNetMessage(flib_gameconn *conn, void (*callback)(void *context, const uint8_t *em, int size), void* context) {
+void flib_gameconn_onEngineMessage(flib_gameconn *conn, void (*callback)(void *context, const uint8_t *em, int size), void* context) {
if(!conn) {
- flib_log_e("null parameter in flib_gameconn_onNetMessage");
+ flib_log_e("null parameter in flib_gameconn_onEngineMessage");
} else {
- conn->onNetMessageCb = callback ? callback : &defaultCallback_onNetMessage;
- conn->onNetMessageCtx = context;
+ conn->onEngineMessageCb = callback ? callback : &defaultCallback_onEngineMessage;
+ conn->onEngineMessageCtx = context;
}
}
static void flib_gameconn_wrappedtick(flib_gameconn *conn) {
if(conn->state == AWAIT_CONNECTION) {
- flib_ipcconn_accept(conn->connection);
- switch(flib_ipcconn_state(conn->connection)) {
+ flib_ipcbase_accept(conn->ipcBase);
+ switch(flib_ipcbase_state(conn->ipcBase)) {
case IPC_CONNECTED:
{
flib_constbuffer configBuffer = flib_vector_as_constbuffer(conn->configBuffer);
- if(flib_ipcconn_send_raw(conn->connection, configBuffer.data, configBuffer.size)) {
+ if(flib_ipcbase_send_raw(conn->ipcBase, configBuffer.data, configBuffer.size)) {
conn->state = FINISHED;
conn->onDisconnectCb(conn->onDisconnectCtx, GAME_END_ERROR);
return;
@@ -327,7 +327,7 @@
if(conn->state == CONNECTED) {
uint8_t msgbuffer[257];
int len;
- while(!conn->destroyRequested && (len = flib_ipcconn_recv_message(conn->connection, msgbuffer))>=0) {
+ while(!conn->destroyRequested && (len = flib_ipcbase_recv_message(conn->ipcBase, msgbuffer))>=0) {
if(len<2) {
flib_log_w("Received short message from IPC (<2 bytes)");
continue;
@@ -383,13 +383,13 @@
default: // Engine message
demo_append(conn, msgbuffer, len);
- conn->onNetMessageCb(conn->onNetMessageCtx, msgbuffer, len);
+ conn->onEngineMessageCb(conn->onEngineMessageCtx, msgbuffer, len);
break;
}
}
}
- if(flib_ipcconn_state(conn->connection) == IPC_NOT_CONNECTED) {
+ if(flib_ipcbase_state(conn->ipcBase) == IPC_NOT_CONNECTED) {
conn->state = FINISHED;
conn->onDisconnectCb(conn->onDisconnectCtx, GAME_END_ERROR);
}
--- a/project_files/frontlib/ipc/gameconn.h Fri Jun 15 19:57:25 2012 +0200
+++ b/project_files/frontlib/ipc/gameconn.h Tue Jun 19 21:17:05 2012 +0200
@@ -1,7 +1,6 @@
#ifndef GAMECONN_H_
#define GAMECONN_H_
-#include "../util/buffer.h"
#include "../model/gamesetup.h"
#include <stddef.h>
@@ -73,7 +72,7 @@
* ...needs to be passed on to the server in a net game
* handleEngineMessage(void *context, const uint8_t *em, int size)
*/
-void flib_gameconn_onNetMessage(flib_gameconn *conn, void (*callback)(void *context, const uint8_t *em, int size), void* context);
+void flib_gameconn_onEngineMessage(flib_gameconn *conn, void (*callback)(void *context, const uint8_t *em, int size), void* context);
// TODO efinish
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/frontlib/ipc/ipcbase.c Tue Jun 19 21:17:05 2012 +0200
@@ -0,0 +1,200 @@
+#include "ipcbase.h"
+#include "../util/logging.h"
+#include "../util/util.h"
+#include "../socket.h"
+
+#include <string.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+/*
+ * The receive buffer has to be able to hold any message that might be received. Normally
+ * the messages are at most 256 bytes, but the map preview contains 4097 bytes (4096 for a
+ * bitmap, 1 for the number of hogs which fit on the map).
+ *
+ * We don't need to worry about wasting a few kb though, and I like powers of two...
+ */
+struct _flib_ipcbase {
+ uint8_t readBuffer[8192];
+ int readBufferSize;
+
+ flib_acceptor *acceptor;
+ uint16_t port;
+
+ flib_tcpsocket *sock;
+};
+
+flib_ipcbase *flib_ipcbase_create() {
+ flib_ipcbase *result = flib_calloc(1, sizeof(flib_ipcbase));
+ flib_acceptor *acceptor = flib_acceptor_create(0);
+
+ if(!result || !acceptor) {
+ free(result);
+ flib_acceptor_close(acceptor);
+ return NULL;
+ }
+
+ result->acceptor = acceptor;
+ result->sock = NULL;
+ result->readBufferSize = 0;
+ result->port = flib_acceptor_listenport(acceptor);
+
+ flib_log_i("Started listening for IPC connections on port %u", (unsigned)result->port);
+ return result;
+}
+
+uint16_t flib_ipcbase_port(flib_ipcbase *ipc) {
+ if(!ipc) {
+ flib_log_e("null parameter in flib_ipcbase_port");
+ return 0;
+ }
+ return ipc->port;
+}
+
+void flib_ipcbase_destroy(flib_ipcbase *ipc) {
+ if(ipc) {
+ flib_acceptor_close(ipc->acceptor);
+ flib_socket_close(ipc->sock);
+ free(ipc);
+ }
+}
+
+IpcState flib_ipcbase_state(flib_ipcbase *ipc) {
+ if(!ipc) {
+ flib_log_e("null parameter in flib_ipcbase_state");
+ return IPC_NOT_CONNECTED;
+ } else if(ipc->sock) {
+ return IPC_CONNECTED;
+ } else if(ipc->acceptor) {
+ return IPC_LISTENING;
+ } else {
+ return IPC_NOT_CONNECTED;
+ }
+}
+
+static bool isMessageReady(flib_ipcbase *ipc) {
+ return ipc->readBufferSize >= ipc->readBuffer[0]+1;
+}
+
+static void receiveToBuffer(flib_ipcbase *ipc) {
+ if(ipc->sock) {
+ int size = flib_socket_nbrecv(ipc->sock, ipc->readBuffer+ipc->readBufferSize, sizeof(ipc->readBuffer)-ipc->readBufferSize);
+ if(size>=0) {
+ ipc->readBufferSize += size;
+ } else {
+ flib_socket_close(ipc->sock);
+ ipc->sock = NULL;
+ }
+ }
+}
+
+int flib_ipcbase_recv_message(flib_ipcbase *ipc, void *data) {
+ if(!ipc || !data) {
+ flib_log_e("null parameter in flib_ipcbase_recv_message");
+ return -1;
+ }
+
+ if(!isMessageReady(ipc)) {
+ receiveToBuffer(ipc);
+ }
+
+ if(isMessageReady(ipc)) {
+ int msgsize = ipc->readBuffer[0]+1;
+ memcpy(data, ipc->readBuffer, msgsize);
+ memmove(ipc->readBuffer, ipc->readBuffer+msgsize, ipc->readBufferSize-msgsize);
+ ipc->readBufferSize -= msgsize;
+ return msgsize;
+ } else if(!ipc->sock && ipc->readBufferSize>0) {
+ flib_log_w("Last message from engine data stream is incomplete (received %u of %u bytes)", (unsigned)ipc->readBufferSize, (unsigned)(ipc->readBuffer[0])+1);
+ ipc->readBufferSize = 0;
+ return -1;
+ } else {
+ return -1;
+ }
+}
+
+int flib_ipcbase_recv_map(flib_ipcbase *ipc, void *data) {
+ if(!ipc || !data) {
+ flib_log_e("null parameter in flib_ipcbase_recv_map");
+ return -1;
+ }
+
+ receiveToBuffer(ipc);
+
+ if(ipc->readBufferSize >= IPCBASE_MAPMSG_BYTES) {
+ memcpy(data, ipc->readBuffer, IPCBASE_MAPMSG_BYTES);
+ memmove(ipc->readBuffer, ipc->readBuffer+IPCBASE_MAPMSG_BYTES, ipc->readBufferSize-IPCBASE_MAPMSG_BYTES);
+ return IPCBASE_MAPMSG_BYTES;
+ } else {
+ return -1;
+ }
+}
+
+static void logSentMsg(const uint8_t *data, size_t len) {
+ if(flib_log_isActive(FLIB_LOGLEVEL_DEBUG)) {
+ size_t msgStart = 0;
+ while(msgStart < len) {
+ uint8_t msglen = data[msgStart];
+ if(msgStart+msglen < len) {
+ flib_log_d("[IPC OUT][%03u]%*.*s",(unsigned)msglen, (unsigned)msglen, (unsigned)msglen, data+msgStart+1);
+ } else {
+ uint8_t msglen2 = len-msgStart-1;
+ flib_log_d("[IPC OUT][%03u/%03u]%*.*s",(unsigned)msglen2, (unsigned)msglen, (unsigned)msglen2, (unsigned)msglen2, data+msgStart+1);
+ }
+ msgStart += (uint8_t)data[msgStart]+1;
+ }
+ }
+}
+
+int flib_ipcbase_send_raw(flib_ipcbase *ipc, const void *data, size_t len) {
+ if(!ipc || (!data && len>0)) {
+ flib_log_e("null parameter in flib_ipcbase_send_raw");
+ return -1;
+ }
+ if(!ipc->sock) {
+ flib_log_w("flib_ipcbase_send_raw: Not connected.");
+ return -1;
+ }
+
+ if(flib_socket_send(ipc->sock, data, len) == len) {
+ logSentMsg(data, len);
+ return 0;
+ } else {
+ flib_log_w("Failed or incomplete ICP write: engine connection lost.");
+ flib_socket_close(ipc->sock);
+ ipc->sock = NULL;
+ return -1;
+ }
+}
+
+int flib_ipcbase_send_message(flib_ipcbase *ipc, void *data, size_t len) {
+ if(!ipc || (!data && len>0)) {
+ flib_log_e("null parameter in flib_ipcbase_send_message");
+ return -1;
+ } else if(len>255) {
+ flib_log_e("Overlong message (%zu bytes) in flib_ipcbase_send_message", len);
+ return -1;
+ }
+
+ uint8_t sendbuf[256];
+ sendbuf[0] = len;
+ memcpy(sendbuf+1, data, len);
+ return flib_ipcbase_send_raw(ipc, sendbuf, len+1);
+}
+
+int flib_ipcbase_send_messagestr(flib_ipcbase *ipc, char *data) {
+ return flib_ipcbase_send_message(ipc, data, strlen(data));
+}
+
+void flib_ipcbase_accept(flib_ipcbase *ipc) {
+ if(!ipc) {
+ flib_log_e("null parameter in flib_ipcbase_accept");
+ } else if(!ipc->sock && ipc->acceptor) {
+ ipc->sock = flib_socket_accept(ipc->acceptor, true);
+ if(ipc->sock) {
+ flib_acceptor_close(ipc->acceptor);
+ ipc->acceptor = NULL;
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/frontlib/ipc/ipcbase.h Tue Jun 19 21:17:05 2012 +0200
@@ -0,0 +1,86 @@
+/*
+ * Low-level protocol support for the IPC connection to the engine.
+ */
+
+#ifndef IPCBASE_H_
+#define IPCBASE_H_
+
+#include <stddef.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+#define IPCBASE_MAPMSG_BYTES 4097
+
+typedef enum {IPC_NOT_CONNECTED, IPC_LISTENING, IPC_CONNECTED} IpcState;
+
+struct _flib_ipcbase;
+typedef struct _flib_ipcbase flib_ipcbase;
+
+/**
+ * Start an engine connection by listening on a random port. The selected port can
+ * be queried with flib_ipcbase_port and has to be passed to the engine.
+ *
+ * Returns NULL on error. Destroy the created object with flib_ipcbase_destroy.
+ *
+ * We stop accepting new connections once a connection has been established, so you
+ * need to create a new ipcbase in order to start a new connection.
+ */
+flib_ipcbase *flib_ipcbase_create();
+
+uint16_t flib_ipcbase_port(flib_ipcbase *ipc);
+
+/**
+ * Free resources and close sockets.
+ */
+void flib_ipcbase_destroy(flib_ipcbase *ipc);
+
+/**
+ * Determine the current connection state
+ */
+IpcState flib_ipcbase_state(flib_ipcbase *ipc);
+
+/**
+ * Receive a single message (up to 256 bytes) and copy it into the data buffer.
+ * Returns the length of the received message, a negative value if no message could
+ * be read.
+ *
+ * The first byte of a message is its content length, which is one less than the returned
+ * value.
+ *
+ * Note: When a connection is closed, you probably want to call this function until
+ * no further message is returned, to ensure you see all messages that were sent
+ * before the connection closed.
+ */
+int flib_ipcbase_recv_message(flib_ipcbase *ipc, void *data);
+
+/**
+ * Try to receive 4097 bytes. This is the size of the reply the engine sends
+ * when successfully queried for map data. The first 4096 bytes are a bit-packed
+ * twocolor image of the map (256x128), the last byte is the number of hogs that
+ * fit on the map.
+ */
+int flib_ipcbase_recv_map(flib_ipcbase *ipc, void *data);
+
+int flib_ipcbase_send_raw(flib_ipcbase *ipc, const void *data, size_t len);
+
+/**
+ * Write a single message (up to 255 bytes) to the engine. This call blocks until the
+ * message is completely written or the connection is closed or an error occurs.
+ *
+ * Calling this function in a state other than IPC_CONNECTED will fail immediately.
+ * Returns a negative value on failure.
+ */
+int flib_ipcbase_send_message(flib_ipcbase *ipc, void *data, size_t len);
+
+/**
+ * Convenience function for sending a 0-delimited string.
+ */
+int flib_ipcbase_send_messagestr(flib_ipcbase *ipc, char *data);
+
+/**
+ * Try to accept a connection. Only has an effect in state IPC_LISTENING.
+ */
+void flib_ipcbase_accept(flib_ipcbase *ipc);
+
+#endif /* IPCBASE_H_ */
+
--- a/project_files/frontlib/ipc/ipcconn.c Fri Jun 15 19:57:25 2012 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,200 +0,0 @@
-#include "ipcconn.h"
-#include "../util/logging.h"
-#include "../util/util.h"
-#include "../socket.h"
-
-#include <string.h>
-#include <stdbool.h>
-#include <stdlib.h>
-#include <stdio.h>
-
-/*
- * The receive buffer has to be able to hold any message that might be received. Normally
- * the messages are at most 256 bytes, but the map preview contains 4097 bytes (4096 for a
- * bitmap, 1 for the number of hogs which fit on the map).
- *
- * We don't need to worry about wasting a few kb though, and I like powers of two...
- */
-struct _flib_ipcconn {
- uint8_t readBuffer[8192];
- int readBufferSize;
-
- flib_acceptor *acceptor;
- uint16_t port;
-
- flib_tcpsocket *sock;
-};
-
-flib_ipcconn *flib_ipcconn_create() {
- flib_ipcconn *result = flib_malloc(sizeof(flib_ipcconn));
- flib_acceptor *acceptor = flib_acceptor_create(0);
-
- if(!result || !acceptor) {
- free(result);
- flib_acceptor_close(acceptor);
- return NULL;
- }
-
- result->acceptor = acceptor;
- result->sock = NULL;
- result->readBufferSize = 0;
- result->port = flib_acceptor_listenport(acceptor);
-
- flib_log_i("Started listening for IPC connections on port %u", (unsigned)result->port);
- return result;
-}
-
-uint16_t flib_ipcconn_port(flib_ipcconn *ipc) {
- if(!ipc) {
- flib_log_e("null parameter in flib_ipcconn_port");
- return 0;
- }
- return ipc->port;
-}
-
-void flib_ipcconn_destroy(flib_ipcconn *ipc) {
- if(ipc) {
- flib_acceptor_close(ipc->acceptor);
- flib_socket_close(ipc->sock);
- free(ipc);
- }
-}
-
-IpcConnState flib_ipcconn_state(flib_ipcconn *ipc) {
- if(!ipc) {
- flib_log_e("null parameter in flib_ipcconn_state");
- return IPC_NOT_CONNECTED;
- } else if(ipc->sock) {
- return IPC_CONNECTED;
- } else if(ipc->acceptor) {
- return IPC_LISTENING;
- } else {
- return IPC_NOT_CONNECTED;
- }
-}
-
-static bool isMessageReady(flib_ipcconn *ipc) {
- return ipc->readBufferSize >= ipc->readBuffer[0]+1;
-}
-
-static void receiveToBuffer(flib_ipcconn *ipc) {
- if(ipc->sock) {
- int size = flib_socket_nbrecv(ipc->sock, ipc->readBuffer+ipc->readBufferSize, sizeof(ipc->readBuffer)-ipc->readBufferSize);
- if(size>=0) {
- ipc->readBufferSize += size;
- } else {
- flib_socket_close(ipc->sock);
- ipc->sock = NULL;
- }
- }
-}
-
-int flib_ipcconn_recv_message(flib_ipcconn *ipc, void *data) {
- if(!ipc || !data) {
- flib_log_e("null parameter in flib_ipcconn_recv_message");
- return -1;
- }
-
- if(!isMessageReady(ipc)) {
- receiveToBuffer(ipc);
- }
-
- if(isMessageReady(ipc)) {
- int msgsize = ipc->readBuffer[0]+1;
- memcpy(data, ipc->readBuffer, msgsize);
- memmove(ipc->readBuffer, ipc->readBuffer+msgsize, ipc->readBufferSize-msgsize);
- ipc->readBufferSize -= msgsize;
- return msgsize;
- } else if(!ipc->sock && ipc->readBufferSize>0) {
- flib_log_w("Last message from engine data stream is incomplete (received %u of %u bytes)", (unsigned)ipc->readBufferSize, (unsigned)(ipc->readBuffer[0])+1);
- ipc->readBufferSize = 0;
- return -1;
- } else {
- return -1;
- }
-}
-
-int flib_ipcconn_recv_map(flib_ipcconn *ipc, void *data) {
- if(!ipc || !data) {
- flib_log_e("null parameter in flib_ipcconn_recv_map");
- return -1;
- }
-
- receiveToBuffer(ipc);
-
- if(ipc->readBufferSize >= IPCCONN_MAPMSG_BYTES) {
- memcpy(data, ipc->readBuffer, IPCCONN_MAPMSG_BYTES);
- memmove(ipc->readBuffer, ipc->readBuffer+IPCCONN_MAPMSG_BYTES, ipc->readBufferSize-IPCCONN_MAPMSG_BYTES);
- return IPCCONN_MAPMSG_BYTES;
- } else {
- return -1;
- }
-}
-
-static void logSentMsg(const uint8_t *data, size_t len) {
- if(flib_log_isActive(FLIB_LOGLEVEL_DEBUG)) {
- size_t msgStart = 0;
- while(msgStart < len) {
- uint8_t msglen = data[msgStart];
- if(msgStart+msglen < len) {
- flib_log_d("[IPC OUT][%03u]%*.*s",(unsigned)msglen, (unsigned)msglen, (unsigned)msglen, data+msgStart+1);
- } else {
- uint8_t msglen2 = len-msgStart-1;
- flib_log_d("[IPC OUT][%03u/%03u]%*.*s",(unsigned)msglen2, (unsigned)msglen, (unsigned)msglen2, (unsigned)msglen2, data+msgStart+1);
- }
- msgStart += (uint8_t)data[msgStart]+1;
- }
- }
-}
-
-int flib_ipcconn_send_raw(flib_ipcconn *ipc, const void *data, size_t len) {
- if(!ipc || (!data && len>0)) {
- flib_log_e("null parameter in flib_ipcconn_send_raw");
- return -1;
- }
- if(!ipc->sock) {
- flib_log_w("flib_ipcconn_send_raw: Not connected.");
- return -1;
- }
-
- if(flib_socket_send(ipc->sock, data, len) == len) {
- logSentMsg(data, len);
- return 0;
- } else {
- flib_log_w("Failed or incomplete ICP write: engine connection lost.");
- flib_socket_close(ipc->sock);
- ipc->sock = NULL;
- return -1;
- }
-}
-
-int flib_ipcconn_send_message(flib_ipcconn *ipc, void *data, size_t len) {
- if(!ipc || (!data && len>0)) {
- flib_log_e("null parameter in flib_ipcconn_send_message");
- return -1;
- } else if(len>255) {
- flib_log_e("Overlong message (%zu bytes) in flib_ipcconn_send_message", len);
- return -1;
- }
-
- uint8_t sendbuf[256];
- sendbuf[0] = len;
- memcpy(sendbuf+1, data, len);
- return flib_ipcconn_send_raw(ipc, sendbuf, len+1);
-}
-
-int flib_ipcconn_send_messagestr(flib_ipcconn *ipc, char *data) {
- return flib_ipcconn_send_message(ipc, data, strlen(data));
-}
-
-void flib_ipcconn_accept(flib_ipcconn *ipc) {
- if(!ipc) {
- flib_log_e("null parameter in flib_ipcconn_accept");
- } else if(!ipc->sock && ipc->acceptor) {
- ipc->sock = flib_socket_accept(ipc->acceptor, true);
- if(ipc->sock) {
- flib_acceptor_close(ipc->acceptor);
- ipc->acceptor = NULL;
- }
- }
-}
--- a/project_files/frontlib/ipc/ipcconn.h Fri Jun 15 19:57:25 2012 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,91 +0,0 @@
-/*
- * Low-level protocol support for the IPC connection to the engine.
- */
-
-#ifndef IPCCONN_H_
-#define IPCCONN_H_
-
-#include "../util/buffer.h"
-
-#include <stddef.h>
-#include <stdbool.h>
-
-#define IPCCONN_MAPMSG_BYTES 4097
-
-typedef enum {IPC_NOT_CONNECTED, IPC_LISTENING, IPC_CONNECTED} IpcConnState;
-
-struct _flib_ipcconn;
-typedef struct _flib_ipcconn flib_ipcconn;
-
-/**
- * Start an engine connection by listening on a random port. The selected port can
- * be queried with flib_ipcconn_port and has to be passed to the engine.
- *
- * The parameter "recordDemo" can be used to control whether demo recording should
- * be enabled for this connection. The localPlayerName is needed for demo
- * recording purposes.
- *
- * Returns NULL on error. Destroy the created object with flib_ipcconn_destroy.
- *
- * We stop accepting new connections once a connection has been established, so you
- * need to create a new ipcconn in order to start a new connection.
- */
-flib_ipcconn *flib_ipcconn_create();
-
-uint16_t flib_ipcconn_port(flib_ipcconn *ipc);
-
-/**
- * Free resources and close sockets.
- */
-void flib_ipcconn_destroy(flib_ipcconn *ipc);
-
-/**
- * Determine the current connection state
- */
-IpcConnState flib_ipcconn_state(flib_ipcconn *ipc);
-
-/**
- * Receive a single message (up to 256 bytes) and copy it into the data buffer.
- * Returns the length of the received message, a negative value if no message could
- * be read.
- *
- * The first byte of a message is its content length, which is one less than the returned
- * value.
- *
- * Note: When a connection is closed, you probably want to call this function until
- * no further message is returned, to ensure you see all messages that were sent
- * before the connection closed.
- */
-int flib_ipcconn_recv_message(flib_ipcconn *ipc, void *data);
-
-/**
- * Try to receive 4097 bytes. This is the size of the reply the engine sends
- * when successfully queried for map data. The first 4096 bytes are a bit-packed
- * twocolor image of the map (256x128), the last byte is the number of hogs that
- * fit on the map.
- */
-int flib_ipcconn_recv_map(flib_ipcconn *ipc, void *data);
-
-int flib_ipcconn_send_raw(flib_ipcconn *ipc, const void *data, size_t len);
-
-/**
- * Write a single message (up to 255 bytes) to the engine. This call blocks until the
- * message is completely written or the connection is closed or an error occurs.
- *
- * Calling this function in a state other than IPC_CONNECTED will fail immediately.
- * Returns a negative value on failure.
- */
-int flib_ipcconn_send_message(flib_ipcconn *ipc, void *data, size_t len);
-
-/**
- * Convenience function for sending a 0-delimited string.
- */
-int flib_ipcconn_send_messagestr(flib_ipcconn *ipc, char *data);
-
-/**
- * Call regularly to allow background work to proceed
- */
-void flib_ipcconn_accept(flib_ipcconn *ipc);
-
-#endif /* IPCCONN_H_ */
-
--- a/project_files/frontlib/ipc/mapconn.c Fri Jun 15 19:57:25 2012 +0200
+++ b/project_files/frontlib/ipc/mapconn.c Tue Jun 19 21:17:05 2012 +0200
@@ -1,5 +1,5 @@
#include "mapconn.h"
-#include "ipcconn.h"
+#include "ipcbase.h"
#include "ipcprotocol.h"
#include "../util/logging.h"
@@ -15,8 +15,8 @@
} mapconn_state;
struct _flib_mapconn {
- uint8_t mapBuffer[IPCCONN_MAPMSG_BYTES];
- flib_ipcconn *connection;
+ uint8_t mapBuffer[IPCBASE_MAPMSG_BYTES];
+ flib_ipcbase *ipcBase;
flib_vector *configBuffer;
mapconn_state progress;
@@ -60,9 +60,9 @@
flib_mapconn *result = NULL;
flib_mapconn *tempConn = flib_calloc(1, sizeof(flib_mapconn));
if(tempConn) {
- tempConn->connection = flib_ipcconn_create();
+ tempConn->ipcBase = flib_ipcbase_create();
tempConn->configBuffer = createConfigBuffer(seed, mapdesc);
- if(tempConn->connection && tempConn->configBuffer) {
+ if(tempConn->ipcBase && tempConn->configBuffer) {
tempConn->progress = AWAIT_CONNECTION;
clearCallbacks(tempConn);
result = tempConn;
@@ -84,7 +84,7 @@
clearCallbacks(conn);
conn->destroyRequested = true;
} else {
- flib_ipcconn_destroy(conn->connection);
+ flib_ipcbase_destroy(conn->ipcBase);
flib_vector_destroy(conn->configBuffer);
free(conn);
}
@@ -96,7 +96,7 @@
flib_log_e("null parameter in flib_mapconn_getport");
return 0;
} else {
- return flib_ipcconn_port(conn->connection);
+ return flib_ipcbase_port(conn->ipcBase);
}
}
@@ -120,12 +120,12 @@
static void flib_mapconn_wrappedtick(flib_mapconn *conn) {
if(conn->progress == AWAIT_CONNECTION) {
- flib_ipcconn_accept(conn->connection);
- switch(flib_ipcconn_state(conn->connection)) {
+ flib_ipcbase_accept(conn->ipcBase);
+ switch(flib_ipcbase_state(conn->ipcBase)) {
case IPC_CONNECTED:
{
flib_constbuffer configBuffer = flib_vector_as_constbuffer(conn->configBuffer);
- if(flib_ipcconn_send_raw(conn->connection, configBuffer.data, configBuffer.size)) {
+ if(flib_ipcbase_send_raw(conn->ipcBase, configBuffer.data, configBuffer.size)) {
conn->progress = FINISHED;
conn->onFailureCb(conn->onFailureCtx, "Error sending map information to the engine.");
return;
@@ -144,11 +144,11 @@
}
if(conn->progress == AWAIT_REPLY) {
- if(flib_ipcconn_recv_map(conn->connection, conn->mapBuffer) >= 0) {
+ if(flib_ipcbase_recv_map(conn->ipcBase, conn->mapBuffer) >= 0) {
conn->progress = FINISHED;
- conn->onSuccessCb(conn->onSuccessCtx, conn->mapBuffer, conn->mapBuffer[IPCCONN_MAPMSG_BYTES-1]);
+ conn->onSuccessCb(conn->onSuccessCtx, conn->mapBuffer, conn->mapBuffer[IPCBASE_MAPMSG_BYTES-1]);
return;
- } else if(flib_ipcconn_state(conn->connection) != IPC_CONNECTED) {
+ } else if(flib_ipcbase_state(conn->ipcBase) != IPC_CONNECTED) {
conn->progress = FINISHED;
conn->onFailureCb(conn->onSuccessCtx, "Engine connection closed unexpectedly.");
return;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/frontlib/net/netbase.c Tue Jun 19 21:17:05 2012 +0200
@@ -0,0 +1,248 @@
+#include "netbase.h"
+#include "../util/buffer.h"
+#include "../util/logging.h"
+#include "../util/util.h"
+#include "../socket.h"
+
+#include <string.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#define NET_READBUFFER_LIMIT (1024*1024)
+
+struct _flib_netbase {
+ flib_vector *readBuffer;
+ flib_tcpsocket *sock;
+};
+
+flib_netbase *flib_netbase_create(const char *server, uint16_t port) {
+ flib_netbase *result = NULL;
+ flib_netbase *newNet = flib_calloc(1, sizeof(flib_netbase));
+
+ if(newNet) {
+ newNet->readBuffer = flib_vector_create();
+ newNet->sock = flib_socket_connect(server, port);
+ if(newNet->readBuffer && newNet->sock) {
+ flib_log_i("Connected to server %s:%u", server, (unsigned)port);
+ result = newNet;
+ newNet = NULL;
+ }
+ }
+ flib_netbase_destroy(newNet);
+
+ return result;
+}
+
+void flib_netbase_destroy(flib_netbase *net) {
+ if(net) {
+ flib_socket_close(net->sock);
+ flib_vector_destroy(net->readBuffer);
+ free(net);
+ }
+}
+
+bool flib_netbase_connected(flib_netbase *net) {
+ if(!net) {
+ flib_log_e("null parameter in flib_netbase_connected");
+ return false;
+ } else if(net->sock) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+/**
+ * Parses and returns a message, and removes it from the vector.
+ */
+static flib_netmsg *parseMessage(flib_vector *vec) {
+ const uint8_t *partStart = flib_vector_data(vec);
+ const uint8_t *end = partStart+flib_vector_size(vec);
+ flib_netmsg *result = flib_netmsg_create();
+ if(!result) {
+ return NULL;
+ }
+
+ while(1) {
+ const uint8_t *partEnd = memchr(partStart, '\n', end-partStart);
+ if(!partEnd) {
+ // message incomplete
+ flib_netmsg_destroy(result);
+ return NULL;
+ } else if(partEnd-partStart == 0) {
+ // Zero-length part, message end marker. Remove the message from the vector.
+ uint8_t *vectorStart = flib_vector_data(vec);
+ size_t msgLen = partEnd+1-vectorStart;
+ memmove(vectorStart, partEnd+1, flib_vector_size(vec)-msgLen);
+ flib_vector_resize(vec, flib_vector_size(vec)-msgLen);
+ return result;
+ } else {
+ if(flib_netmsg_append_part(result, partStart, partEnd-partStart)) {
+ flib_netmsg_destroy(result);
+ return NULL;
+ }
+ partStart = partEnd+1; // Skip the '\n'
+ }
+ }
+ return NULL; // Never reached
+}
+
+/**
+ * Receive some bytes and add them to the buffer.
+ * Returns the number of bytes received.
+ * Automatically closes the socket if an error occurs
+ * and sets sock=NULL.
+ */
+static int receiveToBuffer(flib_netbase *net) {
+ uint8_t buffer[256];
+ if(!net->sock) {
+ return 0;
+ } else if(flib_vector_size(net->readBuffer) > NET_READBUFFER_LIMIT) {
+ flib_log_e("Net connection closed: Net message too big");
+ flib_socket_close(net->sock);
+ net->sock = NULL;
+ return 0;
+ } else {
+ int size = flib_socket_nbrecv(net->sock, buffer, sizeof(buffer));
+ if(size>=0) {
+ flib_vector_append(net->readBuffer, buffer, size);
+ return size;
+ } else {
+ flib_socket_close(net->sock);
+ net->sock = NULL;
+ return 0;
+ }
+ }
+}
+
+flib_netmsg *flib_netbase_recv_message(flib_netbase *net) {
+ if(!net) {
+ flib_log_e("null parameter in flib_netbase_recv_message");
+ return NULL;
+ }
+
+ flib_netmsg *msg;
+ while(!(msg=parseMessage(net->readBuffer))
+ && receiveToBuffer(net)) {}
+
+ if(msg) {
+ return msg;
+ } else if(!net->sock && flib_vector_size(net->readBuffer)>0) {
+ // Connection is down and we didn't get a complete message, just flush the rest.
+ flib_vector_resize(net->readBuffer, 0);
+ }
+ return NULL;
+}
+
+static void logSentMsg(const uint8_t *data, size_t len) {
+ if(flib_log_isActive(FLIB_LOGLEVEL_DEBUG)) {
+ flib_log_d("[NET OUT][%03u]%*.*s",(unsigned)len, (unsigned)len, (unsigned)len, data);
+ }
+}
+
+int flib_netbase_send_raw(flib_netbase *net, const void *data, size_t len) {
+ if(!net || (!data && len>0)) {
+ flib_log_e("null parameter in flib_netbase_send_raw");
+ return -1;
+ }
+ if(!net->sock) {
+ flib_log_w("flib_netbase_send_raw: Not connected.");
+ return -1;
+ }
+
+ if(flib_socket_send(net->sock, data, len) == len) {
+ logSentMsg(data, len);
+ return 0;
+ } else {
+ flib_log_w("Failed or incomplete write: net connection lost.");
+ flib_socket_close(net->sock);
+ net->sock = NULL;
+ return -1;
+ }
+}
+
+int flib_netbase_send_message(flib_netbase *net, flib_netmsg *msg) {
+ if(!net || !msg) {
+ flib_log_e("null parameter in flib_netbase_send_message");
+ return -1;
+ }
+
+ size_t totalSize = 0;
+ for(int i=0; i<msg->partCount; i++) {
+ totalSize += strlen(msg->parts[i]) + 1;
+ }
+ totalSize++; // Last part ends in two '\n' instead of one
+
+ uint8_t *buffer = flib_malloc(totalSize);
+ if(!buffer) {
+ return -1;
+ }
+ size_t pos = 0;
+ for(int i=0; i<msg->partCount; i++) {
+ size_t partsize = strlen(msg->parts[i]);
+ memcpy(buffer+pos, msg->parts[i], partsize);
+ pos += partsize;
+ buffer[pos++] = '\n';
+ }
+ buffer[pos++] = '\n';
+ return flib_netbase_send_raw(net, buffer, pos);
+}
+
+int flib_netbase_sendf(flib_netbase *net, const char *format, ...) {
+ int result = -1;
+ if(!net || !format) {
+ flib_log_e("null parameter in flib_netbase_sendf");
+ } else {
+ va_list argp;
+ va_start(argp, format);
+ char *buffer = flib_vasprintf(format, argp);
+ if(buffer) {
+ result = flib_netbase_send_raw(net, buffer, strlen(buffer));
+ }
+ free(buffer);
+ va_end(argp);
+ }
+ return result;
+}
+
+flib_netmsg *flib_netmsg_create() {
+ flib_netmsg *result = flib_calloc(1, sizeof(flib_netmsg));
+ if(result) {
+ result->partCount = 0;
+ result->parts = NULL;
+ return result;
+ } else {
+ return NULL;
+ }
+}
+
+void flib_netmsg_destroy(flib_netmsg *msg) {
+ if(msg) {
+ for(int i=0; i<msg->partCount; i++) {
+ free(msg->parts[i]);
+ }
+ free(msg->parts);
+ free(msg);
+ }
+}
+
+int flib_netmsg_append_part(flib_netmsg *msg, const void *part, size_t partlen) {
+ int result = -1;
+ if(!msg) {
+ flib_log_e("null parameter in flib_netmsg_append_part");
+ } else {
+ char **newParts = realloc(msg->parts, (msg->partCount+1)*sizeof(*msg->parts));
+ if(newParts) {
+ msg->parts = newParts;
+ msg->parts[msg->partCount] = flib_malloc(partlen+1);
+ if(msg->parts[msg->partCount]) {
+ memcpy(msg->parts[msg->partCount], part, partlen);
+ msg->parts[msg->partCount][partlen] = 0;
+ msg->partCount++;
+ result = 0;
+ }
+ }
+ }
+ return result;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/frontlib/net/netbase.h Tue Jun 19 21:17:05 2012 +0200
@@ -0,0 +1,72 @@
+/*
+ * Low-level protocol support for the network connection
+ */
+
+#ifndef NETBASE_H_
+#define NETBASE_H_
+
+#include <stddef.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+struct _flib_netbase;
+typedef struct _flib_netbase flib_netbase;
+
+typedef struct {
+ int partCount;
+ char **parts;
+} flib_netmsg;
+
+/**
+ * Start a connection to the specified Hedgewars server.
+ *
+ * Returns NULL on error. Destroy the created object with flib_netconn_destroy.
+ */
+flib_netbase *flib_netbase_create(const char *server, uint16_t port);
+
+/**
+ * Free resources and close sockets.
+ */
+void flib_netbase_destroy(flib_netbase *net);
+
+/**
+ * Determine the current connection state. Starts out true, and turns to
+ * false when we are disconnected from the server.
+ */
+bool flib_netbase_connected(flib_netbase *net);
+
+/**
+ * Receive a new message and return it as a flib_netmsg. The netmsg has to be
+ * destroyed with flib_netmsg_destroy after use.
+ * Returns NULL if no message is available.
+ *
+ * Note: When a connection is closed, you probably want to call this function until
+ * no further message is returned, to ensure you see all messages that were sent
+ * before the connection closed.
+ */
+flib_netmsg *flib_netbase_recv_message(flib_netbase *net);
+
+int flib_netbase_send_raw(flib_netbase *net, const void *data, size_t len);
+
+/**
+ * Write a single message to the server. This call blocks until the
+ * message is completely written or the connection is closed or an error occurs.
+ *
+ * Returns a negative value on failure.
+ */
+int flib_netbase_send_message(flib_netbase *net, flib_netmsg *msg);
+
+/**
+ * Send a message printf-style.
+ *
+ * flib_netbase_sendf(net, "%s\n\n", "TOGGLE_READY");
+ * flib_netbase_sendf(net, "%s\n%s\n%i\n\n", "CFG", "MAPGEN", MAPGEN_MAZE);
+ */
+int flib_netbase_sendf(flib_netbase *net, const char *format, ...);
+
+flib_netmsg *flib_netmsg_create();
+void flib_netmsg_destroy(flib_netmsg *msg);
+int flib_netmsg_append_part(flib_netmsg *msg, const void *param, size_t len);
+
+#endif /* NETBASE_H_ */
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/frontlib/net/netconn.c Tue Jun 19 21:17:05 2012 +0200
@@ -0,0 +1,469 @@
+/*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (c) 2006-2008 Igor Ulyanov <iulyanov@gmail.com>
+ * Copyright (c) 2004-2012 Andrey Korotaev <unC0Rr@gmail.com>
+ * Copyright (c) 2012 Simeon Maxein <smaxein@googlemail.com>
+ *
+ * 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; version 2 of the License
+ *
+ * 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
+ */
+
+#include "netconn.h"
+#include "netbase.h"
+#include "netprotocol.h"
+#include "../util/logging.h"
+#include "../util/util.h"
+
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+struct _flib_netconn {
+ flib_netbase *netBase;
+ char *playerName;
+
+ int netconnState; // One of the NETCONN_STATE constants
+
+ void (*onErrorCb)(void* context, int errorCode, const char *errorMsg);
+ void *onErrorCtx;
+
+ void (*onConnectedCb)(void *context, const char *serverMessage);
+ void *onConnectedCtx;
+
+ bool running;
+ bool destroyRequested;
+};
+
+static void defaultCallback_onError(void* context, int errorCode, const char *errormsg) {}
+static void defaultCallback_onConnected(void *context, const char *serverMessage) {}
+
+static void clearCallbacks(flib_netconn *conn) {
+ conn->onErrorCb = &defaultCallback_onError;
+ conn->onConnectedCb = &defaultCallback_onConnected;
+}
+
+
+flib_netconn *flib_netconn_create(const char *playerName, const char *host, uint16_t port) {
+ flib_netconn *result = NULL;
+ flib_netconn *newConn = flib_calloc(1, sizeof(flib_netconn));
+ if(newConn) {
+ newConn->netconnState = NETCONN_STATE_AWAIT_CONNECTED;
+ newConn->running = false;
+ newConn->destroyRequested = false;
+ clearCallbacks(newConn);
+ newConn->netBase = flib_netbase_create(host, port);
+ newConn->playerName = flib_strdupnull(playerName);
+ if(newConn->netBase && newConn->playerName) {
+ result = newConn;
+ newConn = NULL;
+ }
+ }
+ flib_netconn_destroy(newConn);
+ return result;
+}
+
+void flib_netconn_destroy(flib_netconn *conn) {
+ if(conn) {
+ if(conn->running) {
+ /*
+ * The function was called from a callback, so the tick function is still running
+ * and we delay the actual destruction. We ensure no further callbacks will be
+ * sent to prevent surprises.
+ */
+ clearCallbacks(conn);
+ conn->destroyRequested = true;
+ } else {
+ flib_netbase_destroy(conn->netBase);
+ free(conn->playerName);
+ free(conn);
+ }
+ }
+}
+
+void flib_netconn_onError(flib_netconn *conn, void (*callback)(void *context, int errorCode, const char *errorMsg), void* context) {
+ if(!conn) {
+ flib_log_e("null parameter in flib_netconn_onError");
+ } else {
+ conn->onErrorCb = callback ? callback : &defaultCallback_onError;
+ conn->onErrorCtx = context;
+ }
+}
+
+void flib_netconn_onConnected(flib_netconn *conn, void (*callback)(void *context, const char *serverMessage), void* context) {
+ if(!conn) {
+ flib_log_e("null parameter in flib_netconn_onConnected");
+ } else {
+ conn->onConnectedCb = callback ? callback : &defaultCallback_onConnected;
+ conn->onConnectedCtx = context;
+ }
+}
+
+static void flib_netconn_wrappedtick(flib_netconn *conn) {
+ flib_netmsg *netmsg;
+ flib_netbase *net = conn->netBase;
+ bool exit = false;
+
+ while(!exit && !conn->destroyRequested && (netmsg=flib_netbase_recv_message(conn->netBase))) {
+ if(netmsg->partCount==0) {
+ flib_log_w("Empty server message");
+ continue;
+ }
+
+ const char *cmd = netmsg->parts[0];
+
+ if (!strcmp(cmd, "NICK") && netmsg->partCount>=2) {
+ free(conn->playerName);
+ conn->playerName = flib_strdupnull(netmsg->parts[1]);
+ if(!conn->playerName) {
+ // TODO handle error
+ }
+ // TODO callback?
+ } else if (!strcmp(cmd, "PROTO")) {
+ // The server just echoes this back apparently
+ } else if (!strcmp(cmd, "ERROR")) {
+ // TODO: onErrorMessage?
+ if (netmsg->partCount == 2) {
+ conn->onErrorCb(conn->onErrorCtx, NETCONN_ERROR_FROM_SERVER, netmsg->parts[1]);
+ } else {
+ conn->onErrorCb(conn->onErrorCtx, NETCONN_ERROR_FROM_SERVER, "Unknown Error");
+ }
+ } else if(!strcmp(cmd, "WARNING")) {
+ // TODO: onWarnMessage?
+ if (netmsg->partCount == 2) {
+ conn->onErrorCb(conn->onErrorCtx, NETCONN_ERROR_FROM_SERVER, netmsg->parts[1]);
+ } else {
+ conn->onErrorCb(conn->onErrorCtx, NETCONN_ERROR_FROM_SERVER, "Unknown Warning");
+ }
+ } else if(!strcmp(cmd, "CONNECTED")) {
+ if(netmsg->partCount<3 || atol(netmsg->parts[2])<MIN_SERVER_VERSION) {
+ flib_log_w("Server too old");
+ flib_netbase_sendf(net, "%s\n%s\n\n", "QUIT", "Server too old");
+ // TODO actually disconnect?
+ conn->netconnState = NETCONN_STATE_DISCONNECTED;
+ conn->onErrorCb(conn->onErrorCtx, NETCONN_ERROR_SERVER_TOO_OLD, "Server too old");
+ exit = true;
+ } else {
+ flib_netbase_sendf(net, "%s\n%s\n\n", "NICK", conn->playerName);
+ flib_netbase_sendf(net, "%s\n%i\n\n", "PROTO", (int)PROTOCOL_VERSION);
+ conn->netconnState = NETCONN_STATE_LOBBY;
+ }
+ } else if(!strcmp(cmd, "PING")) {
+ if (netmsg->partCount > 1) {
+ flib_netbase_sendf(net, "%s\n%s\n\n", "PONG", netmsg->parts[1]);
+ } else {
+ flib_netbase_sendf(net, "%s\n\n", "PONG");
+ }
+ } else if(!strcmp(cmd, "ROOMS")) {
+ if(netmsg->partCount % 8 != 1) {
+ flib_log_w("Net: Malformed ROOMS message");
+ } else {
+ // TODO
+ //QStringList tmp = lst;
+ //tmp.removeFirst();
+ //m_roomsListModel->setRoomsList(tmp);
+ }
+ } else if (!strcmp(cmd, "SERVER_MESSAGE")) {
+ if(netmsg->partCount < 2) {
+ flib_log_w("Net: Empty SERVERMESSAGE message");
+ } else {
+ // TODO
+ // emit serverMessage(lst[1]);
+ }
+ } else if (!strcmp(cmd, "CHAT")) {
+ if(netmsg->partCount < 3) {
+ flib_log_w("Net: Empty CHAT message");
+ } else {
+ // TODO
+ // if (netClientState == InLobby)
+ // emit chatStringLobby(lst[1], HWProto::formatChatMsgForFrontend(lst[2]));
+ // else
+ // emit chatStringFromNet(HWProto::formatChatMsg(lst[1], lst[2]));
+ }
+ } else if (!strcmp(cmd, "INFO")) {
+ if(netmsg->partCount < 5) {
+ flib_log_w("Net: Malformed INFO message");
+ } else {
+ // TODO
+// QStringList tmp = lst;
+// tmp.removeFirst();
+// if (netClientState == InLobby)
+// emit chatStringLobby(tmp.join("\n").prepend('\x01'));
+// else
+// emit chatStringFromNet(tmp.join("\n").prepend('\x01'));
+ }
+ } else if(!strcmp(cmd, "SERVER_VARS")) {
+ // TODO
+// QStringList tmp = lst;
+// tmp.removeFirst();
+// while (tmp.size() >= 2)
+// {
+// if(tmp[0] == "MOTD_NEW") emit serverMessageNew(tmp[1]);
+// else if(tmp[0] == "MOTD_OLD") emit serverMessageOld(tmp[1]);
+// else if(tmp[0] == "LATEST_PROTO") emit latestProtocolVar(tmp[1].toInt());
+//
+// tmp.removeFirst();
+// tmp.removeFirst();
+// }
+ } else if (!strcmp(cmd, "CLIENT_FLAGS")) {
+ if(netmsg->partCount < 3 || strlen(netmsg->parts[1]) < 2) {
+ flib_log_w("Net: Malformed CLIENT_FLAGS message");
+ } else {
+ const char *flags = netmsg->parts[1];
+ bool setFlag = flags[0] == '+';
+
+ for(int i=1; flags[i]; i++) {
+ switch(flags[i]) {
+ case 'r':
+ for(int j = 2; j < netmsg->partCount; ++j) {
+ if (!strcmp(conn->playerName, netmsg->parts[i])) {
+ // TODO
+ // if (isChief && !setFlag) ToggleReady();
+ // else emit setMyReadyStatus(setFlag);
+ }
+ // TODO
+ // emit setReadyStatus(lst[i], setFlag);
+ }
+ break;
+ default:
+ flib_log_w("Net: Unknown flag %c in CLIENT_FLAGS message", flags[i]);
+ break;
+ }
+ }
+ }
+ } else if (!strcmp(cmd, "ADD_TEAM")) {
+ if(netmsg->partCount != 24) {
+ flib_log_w("Net: Bad ADD_TEAM message");
+ } else {
+ // TODO
+// QStringList tmp = lst;
+// tmp.removeFirst();
+// emit AddNetTeam(tmp);
+ }
+ } else if (!strcmp(cmd, "REMOVE_TEAM")) {
+ if(netmsg->partCount != 2) {
+ flib_log_w("Net: Bad REMOVETEAM message");
+ } else {
+ // TODO
+ // emit RemoveNetTeam(HWTeam(lst[1]));
+ }
+ } else if(!strcmp(cmd, "ROOMABANDONED")) {
+ conn->netconnState = NETCONN_STATE_LOBBY;
+// TODO
+// askRoomsList();
+// emit LeftRoom(tr("Room destroyed"));
+ } else if(!strcmp(cmd, "KICKED")) {
+ conn->netconnState = NETCONN_STATE_LOBBY;
+// TODO
+// askRoomsList();
+// emit LeftRoom(tr("You got kicked"));
+ } else if(!strcmp(cmd, "JOINED")) {
+ if(netmsg->partCount < 2) {
+ flib_log_w("Net: Bad JOINED message");
+ } else {
+ for(int i = 1; i < netmsg->partCount; ++i)
+ {
+ bool isMe = !strcmp(conn->playerName, netmsg->parts[i]);
+ if (isMe) {
+ conn->netconnState = NETCONN_STATE_ROOM;
+// TODO
+// emit EnteredGame();
+// emit roomMaster(isChief);
+// if (isChief)
+// emit configAsked();
+ }
+
+// TODO
+// emit nickAdded(lst[i], isChief && !isMe));
+// emit chatStringFromNet(tr("%1 *** %2 has joined the room").arg('\x03').arg(lst[i]));
+ }
+ }
+ } else if(!strcmp(cmd, "LOBBY:JOINED")) {
+ if(netmsg->partCount < 2) {
+ flib_log_w("Net: Bad JOINED message");
+ } else {
+ for(int i = 1; i < netmsg->partCount; ++i)
+ {
+ bool isMe = !strcmp(conn->playerName, netmsg->parts[i]);
+ if (isMe) {
+ conn->netconnState = NETCONN_STATE_LOBBY;
+ // TODO
+// RawSendNet(QString("LIST"));
+// emit connected();
+ }
+ // TODO
+// emit nickAddedLobby(lst[i], false);
+// emit chatStringLobby(lst[i], tr("%1 *** %2 has joined").arg('\x03').arg("|nick|"));
+ }
+ }
+ } else if(!strcmp(cmd, "LEFT")) {
+ if(netmsg->partCount < 2) {
+ flib_log_w("Net: Bad LEFT message");
+ } else {
+ // TODO
+// emit nickRemoved(lst[1]);
+// if (netmsg->partCount < 3)
+// emit chatStringFromNet(tr("%1 *** %2 has left").arg('\x03').arg(lst[1]));
+// else
+// emit chatStringFromNet(tr("%1 *** %2 has left (%3)").arg('\x03').arg(lst[1], lst[2]));
+ }
+ } else if(!strcmp(cmd, "ROOM") && netmsg->partCount >= 2) {
+ const char *subcmd = netmsg->parts[1];
+ if(!strcmp(subcmd, "ADD") && netmsg->partCount == 10) {
+ // TODO
+// QStringList tmp = lst;
+// tmp.removeFirst();
+// tmp.removeFirst();
+//
+// m_roomsListModel->addRoom(tmp);
+ } else if(!strcmp(subcmd, "UPD") && netmsg->partCount == 11) {
+ // TODO
+// QStringList tmp = lst;
+// tmp.removeFirst();
+// tmp.removeFirst();
+//
+// QString roomName = tmp.takeFirst();
+// m_roomsListModel->updateRoom(roomName, tmp);
+ } else if(!strcmp(subcmd, "DEL") && netmsg->partCount == 3) {
+ // TODO
+ // m_roomsListModel->removeRoom(lst[2]);
+ } else {
+ flib_log_w("Net: Unknown or malformed ROOM subcommand: %s", subcmd);
+ }
+ } else if(!strcmp(cmd, "LOBBY:LEFT")) {
+ if(netmsg->partCount < 2) {
+ flib_log_w("Net: Bad LOBBY:LEFT message");
+ } else {
+ // TODO
+// emit nickRemovedLobby(lst[1]);
+// if (netmsg->partCount < 3)
+// emit chatStringLobby(tr("%1 *** %2 has left").arg('\x03').arg(lst[1]));
+// else
+// emit chatStringLobby(lst[1], tr("%1 *** %2 has left (%3)").arg('\x03').arg("|nick|", lst[2]));
+ }
+ } else if (!strcmp(cmd, "RUN_GAME")) {
+ conn->netconnState = NETCONN_STATE_INGAME;
+ // TODO
+ // emit AskForRunGame();
+ } else if (!strcmp(cmd, "ASKPASSWORD")) {
+ // TODO
+ // emit AskForPassword(mynick);
+ } else if (!strcmp(cmd, "NOTICE")) {
+ if(netmsg->partCount < 2) {
+ flib_log_w("Net: Bad NOTICE message");
+ } else {
+ errno = 0;
+ long n = strtol(netmsg->parts[1], NULL, 10);
+ if(errno) {
+ flib_log_w("Net: Bad NOTICE message");
+ } else {
+ // TODO
+ // handleNotice(n);
+ }
+ }
+ } else if (!strcmp(cmd, "TEAM_ACCEPTED")) {
+ if (netmsg->partCount != 2) {
+ flib_log_w("Net: Bad TEAM_ACCEPTED message");
+ } else {
+ // TODO
+ // emit TeamAccepted(lst[1]);
+ }
+ } else if (!strcmp(cmd, "CFG")) {
+ if(netmsg->partCount < 3) {
+ flib_log_w("Net: Bad CFG message");
+ } else {
+ // TODO
+// QStringList tmp = lst;
+// tmp.removeFirst();
+// tmp.removeFirst();
+// if (lst[1] == "SCHEME")
+// emit netSchemeConfig(tmp);
+// else
+// emit paramChanged(lst[1], tmp);
+ }
+ } else if (!strcmp(cmd, "HH_NUM")) {
+ if (netmsg->partCount != 3) {
+ flib_log_w("Net: Bad TEAM_ACCEPTED message");
+ } else {
+ // TODO
+// HWTeam tmptm(lst[1]);
+// tmptm.setNumHedgehogs(lst[2].toUInt());
+// emit hhnumChanged(tmptm);
+ }
+ } else if (!strcmp(cmd, "TEAM_COLOR")) {
+ if (netmsg->partCount != 3) {
+ flib_log_w("Net: Bad TEAM_COLOR message");
+ } else {
+ // TODO
+// HWTeam tmptm(lst[1]);
+// tmptm.setColor(lst[2].toInt());
+// emit teamColorChanged(tmptm);
+ }
+ } else if (!strcmp(cmd, "EM")) {
+ if(netmsg->partCount < 2) {
+ flib_log_w("Net: Bad EM message");
+ } else {
+ // TODO
+// for(int i = 1; i < netmsg->partCount; ++i) {
+// QByteArray em = QByteArray::fromBase64(lst[i].toAscii());
+// emit FromNet(em);
+// }
+ }
+ } else if (!strcmp(cmd, "BYE")) {
+ if (netmsg->partCount < 2) {
+ flib_log_w("Net: Bad BYE message");
+ } else {
+ if (!strcmp(netmsg->parts[1], "Authentication failed")) {
+ // TODO
+ //emit AuthFailed();
+ }
+ // TODO
+// m_game_connected = false;
+// Disconnect();
+// emit disconnected(lst[1]);
+ }
+ } else if (!strcmp(cmd, "ADMIN_ACCESS")) {
+ // TODO
+ // emit adminAccess(true);
+ } else if (!strcmp(cmd, "ROOM_CONTROL_ACCESS")) {
+ if (netmsg->partCount < 2) {
+ flib_log_w("Net: Bad ROOM_CONTROL_ACCESS message");
+ } else {
+ // TODO
+// isChief = (lst[1] != "0");
+// emit roomMaster(isChief);
+ }
+ } else {
+ flib_log_w("Unknown server command: %s", cmd);
+ }
+ flib_netmsg_destroy(netmsg);
+ }
+}
+
+void flib_netconn_tick(flib_netconn *conn) {
+ if(!conn) {
+ flib_log_e("null parameter in flib_netconn_tick");
+ } else if(conn->running) {
+ flib_log_w("Call to flib_netconn_tick from a callback");
+ } else if(conn->netconnState == NETCONN_STATE_DISCONNECTED) {
+ flib_log_w("Call to flib_netconn_tick, but we are already done.");
+ } else {
+ conn->running = true;
+ flib_netconn_wrappedtick(conn);
+ conn->running = false;
+
+ if(conn->destroyRequested) {
+ flib_netconn_destroy(conn);
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/frontlib/net/netconn.h Tue Jun 19 21:17:05 2012 +0200
@@ -0,0 +1,45 @@
+#ifndef NETCONN_H_
+#define NETCONN_H_
+
+#include "../model/gamesetup.h"
+
+#include <stddef.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+#define NETCONN_STATE_AWAIT_CONNECTED 0
+#define NETCONN_STATE_LOBBY 1
+#define NETCONN_STATE_ROOM 2
+#define NETCONN_STATE_INGAME 3
+#define NETCONN_STATE_DISCONNECTED 10
+
+#define NETCONN_ERROR_SERVER_TOO_OLD 1
+#define NETCONN_ERROR_FROM_SERVER 2
+
+struct _flib_netconn;
+typedef struct _flib_netconn flib_netconn;
+
+flib_netconn *flib_netconn_create(const char *playerName, const char *host, uint16_t port);
+void flib_netconn_destroy(flib_netconn *conn);
+
+/**
+ * This is called when we can't stay connected due to a problem, e.g. because the
+ * server version is too old, or we are unexpectedly disconnected.
+ *
+ * Once this callback has been called, you should destroy the flib_netconn.
+ */
+void flib_netconn_onError(flib_netconn *conn, void (*callback)(void *context, int errorCode, const char *errormsg), void* context);
+
+/**
+ * This is called when we receive a CONNECTED message from the server, which should be the first
+ * message arriving from the server.
+ */
+void flib_netconn_onConnected(flib_netconn *conn, void (*callback)(void *context, const char *serverMessage), void* context);
+
+/**
+ * Perform I/O operations and call callbacks if something interesting happens.
+ * Should be called regularly.
+ */
+void flib_netconn_tick(flib_netconn *conn);
+
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/frontlib/net/netprotocol.h Tue Jun 19 21:17:05 2012 +0200
@@ -0,0 +1,7 @@
+#ifndef NETPROTOCOL_H_
+#define NETPROTOCOL_H_
+
+
+
+
+#endif /* NETPROTOCOL_H_ */
--- a/project_files/frontlib/socket.c Fri Jun 15 19:57:25 2012 +0200
+++ b/project_files/frontlib/socket.c Tue Jun 19 21:17:05 2012 +0200
@@ -121,6 +121,30 @@
return result;
}
+flib_tcpsocket *flib_socket_connect(const char *host, uint16_t port) {
+ flib_tcpsocket *result = NULL;
+ if(!host || port==0) {
+ flib_log_e("Invalid parameter in flib_socket_connect");
+ } else {
+ IPaddress ip;
+ if(SDLNet_ResolveHost(&ip,host,port)==-1) {
+ flib_log_e("SDLNet_ResolveHost: %s\n", SDLNet_GetError());
+ } else {
+ TCPsocket sock=SDLNet_TCP_Open(&ip);
+ if(!sock) {
+ flib_log_e("SDLNet_TCP_Open: %s\n", SDLNet_GetError());
+ } else {
+ result = flib_socket_create(sock);
+ if(result) {
+ sock = NULL;
+ }
+ }
+ SDLNet_TCP_Close(sock);
+ }
+ }
+ return result;
+}
+
void flib_socket_close(flib_tcpsocket *sock) {
if(sock) {
SDLNet_DelSocket(sock->sockset, (SDLNet_GenericSocket)sock->sock);
--- a/project_files/frontlib/socket.h Fri Jun 15 19:57:25 2012 +0200
+++ b/project_files/frontlib/socket.h Tue Jun 19 21:17:05 2012 +0200
@@ -49,6 +49,11 @@
flib_tcpsocket *flib_socket_accept(flib_acceptor *acceptor, bool localOnly);
/**
+ * Try to connect to the server at the given address.
+ */
+flib_tcpsocket *flib_socket_connect(const char *host, uint16_t port);
+
+/**
* Close the socket and free its memory.
* If the socket is already NULL, nothing happens.
*/
--- a/project_files/frontlib/test.c Fri Jun 15 19:57:25 2012 +0200
+++ b/project_files/frontlib/test.c Tue Jun 19 21:17:05 2012 +0200
@@ -1,14 +1,17 @@
#include "frontlib.h"
#include "util/logging.h"
+#include "util/buffer.h"
#include "model/map.h"
#include "model/weapon.h"
#include "model/schemelist.h"
#include "ipc/mapconn.h"
#include "ipc/gameconn.h"
+#include "net/netbase.h"
#include <stdlib.h>
#include <stdbool.h>
#include <assert.h>
+#include <string.h>
// Callback function that will be called when the map is rendered
static void handleMapSuccess(void *context, const uint8_t *bitmap, int numHedgehogs) {
@@ -204,18 +207,37 @@
//testSave();
//testGame();
- flib_cfg_meta *meta = flib_cfg_meta_from_ini("metasettings.ini");
- assert(meta);
- flib_schemelist *schemelist = flib_schemelist_from_ini(meta, "schemes.ini");
- assert(schemelist);
+ flib_netbase *conn = flib_netbase_create("140.247.62.101", 46631);
- flib_schemelist_to_ini("Copy of Schemelist.ini", schemelist);
- flib_schemelist_release(schemelist);
- flib_cfg_meta_release(meta);
-
- flib_weaponsetlist *weaponsets = flib_weaponsetlist_from_ini("weapons.ini");
- assert(!flib_weaponsetlist_to_ini("copy of weapons.ini", weaponsets));
- flib_weaponsetlist_release(weaponsets);
+ while(flib_netbase_connected(conn)) {
+ flib_netmsg *msg = flib_netbase_recv_message(conn);
+ if(msg && msg->partCount>0) {
+ flib_log_i("[NET IN] %s", msg->parts[0]);
+ for(int i=1; i<msg->partCount; i++) {
+ flib_log_i("[NET IN][-] %s", msg->parts[i]);
+ }
+ if(!strcmp(msg->parts[0], "CONNECTED")) {
+ flib_netmsg *nickmsg = flib_netmsg_create();
+ flib_netmsg_append_part(nickmsg, "NICK", 4);
+ flib_netmsg_append_part(nickmsg, "Medo42_frontlib", 15);
+ flib_netmsg *protomsg = flib_netmsg_create();
+ flib_netmsg_append_part(protomsg, "PROTO", 5);
+ flib_netmsg_append_part(protomsg, "42", 2);
+ flib_netbase_send_message(conn, nickmsg);
+ flib_netbase_send_message(conn, protomsg);
+ flib_netmsg_destroy(nickmsg);
+ flib_netmsg_destroy(protomsg);
+ }
+ if(!strcmp(msg->parts[0], "SERVER_MESSAGE")) {
+ flib_netmsg *quitmsg = flib_netmsg_create();
+ flib_netmsg_append_part(quitmsg, "QUIT", 4);
+ flib_netmsg_append_part(quitmsg, "Just testing", 12);
+ flib_netbase_send_message(conn, quitmsg);
+ flib_netmsg_destroy(quitmsg);
+ }
+ }
+ flib_netmsg_destroy(msg);
+ }
flib_quit();
return 0;
--- a/project_files/frontlib/util/buffer.c Fri Jun 15 19:57:25 2012 +0200
+++ b/project_files/frontlib/util/buffer.c Tue Jun 19 21:17:05 2012 +0200
@@ -37,16 +37,61 @@
}
}
-static void try_realloc(flib_vector *vec, size_t newCapacity) {
+static int setCapacity(flib_vector *vec, size_t newCapacity) {
+ if(newCapacity == vec->capacity) {
+ return 0;
+ }
void *newData = realloc(vec->data, newCapacity);
if(newData) {
vec->data = newData;
vec->capacity = newCapacity;
+ return 0;
+ } else {
+ return -1;
+ }
+}
+
+static int allocateExtraCapacity(flib_vector *vec, size_t extraCapacity) {
+ if(extraCapacity <= SIZE_MAX - vec->capacity) {
+ return setCapacity(vec, vec->capacity + extraCapacity);
+ } else {
+ return -1;
}
}
-static size_t getFreeCapacity(flib_vector *vec) {
- return vec->capacity - vec->size;
+int flib_vector_resize(flib_vector *vec, size_t newSize) {
+ if(!vec) {
+ flib_log_e("null parameter in flib_vector_resize");
+ return -1;
+ }
+
+ if(vec->capacity < newSize) {
+ // Resize exponentially for constant amortized time,
+ // But at least by as much as we need of course,
+ // and be extra careful with integer overflows...
+ size_t extraCapacity = (vec->capacity)/2;
+ size_t minExtraCapacity = newSize - vec->capacity;
+ if(extraCapacity < minExtraCapacity) {
+ extraCapacity = minExtraCapacity;
+ }
+
+ if(allocateExtraCapacity(vec, extraCapacity)) {
+ allocateExtraCapacity(vec, minExtraCapacity);
+ }
+ } else if(vec->capacity/2 > newSize) {
+ size_t newCapacity = newSize+newSize/4;
+ if(newCapacity < MIN_VECTOR_CAPACITY) {
+ newCapacity = MIN_VECTOR_CAPACITY;
+ }
+ setCapacity(vec, newCapacity);
+ }
+
+ if(vec->capacity >= newSize) {
+ vec->size = newSize;
+ return 0;
+ } else {
+ return -1;
+ }
}
int flib_vector_append(flib_vector *vec, const void *data, size_t len) {
@@ -55,35 +100,16 @@
return 0;
}
- if(getFreeCapacity(vec) < len) {
- // Resize exponentially for constant amortized time,
- // But at least by as much as we need of course,
- // and be extra careful with integer overflows...
- size_t extraCapacity = (vec->capacity)/2;
-
- size_t minExtraCapacity = len - getFreeCapacity(vec);
- if(extraCapacity < minExtraCapacity) {
- extraCapacity = minExtraCapacity;
- }
-
- if(extraCapacity <= SIZE_MAX - vec->capacity) {
- try_realloc(vec, vec->capacity+extraCapacity);
- }
-
- // Check if we were able to resize.
- // If not, try to allocate at least what we need.
- if(getFreeCapacity(vec) < len) {
- try_realloc(vec, vec->capacity+minExtraCapacity);
-
- // Still not working? Then we fail.
- if(getFreeCapacity(vec) < len) {
- return 0;
- }
- }
+ if(len > SIZE_MAX-vec->size) {
+ return 0;
}
- memmove(((uint8_t*)vec->data) + vec->size, data, len);
- vec->size += len;
+ size_t oldSize = vec->size;
+ if(flib_vector_resize(vec, vec->size+len)) {
+ return 0;
+ }
+
+ memmove(((uint8_t*)vec->data) + oldSize, data, len);
return len;
}
--- a/project_files/frontlib/util/buffer.h Fri Jun 15 19:57:25 2012 +0200
+++ b/project_files/frontlib/util/buffer.h Tue Jun 19 21:17:05 2012 +0200
@@ -41,6 +41,13 @@
void flib_vector_destroy(flib_vector *vec);
/**
+ * Resize the vector. This changes the size, and ensures the capacity is large enough to
+ * for the new size. Can also free memory if the new size is smaller. There is no guarantee
+ * about the contents of extra memory.
+ */
+int flib_vector_resize(flib_vector *vec, size_t newSize);
+
+/**
* Append the provided data to the end of the vector, enlarging it as required.
* Returns the ammount of data appended, which is either len (success) or 0 (out of memory).
* The vector remains unchanged if appending fails.