Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/extern
diff options
context:
space:
mode:
authorNathan Letwory <nathan@letworyinteractive.com>2006-10-12 15:53:50 +0400
committerNathan Letwory <nathan@letworyinteractive.com>2006-10-12 15:53:50 +0400
commitb2a8417fce8d231188ee75062804be4d471c57be (patch)
tree86d163d10a0f486fc203e0c95619c6f2b06aa6b1 /extern
parent86e192ea40ececcade256e528c557d9018751cb8 (diff)
Add Verse master-server functionality
* added two files from verse-master * server list is available in outliner (new mode "Verse Servers") * verse sessions are now also in new mode "Verse Sessions" in outliner * fixed drawing of verse sessions and their nodes * in user preferences System & OpenGL master-server ip setting (default master.uni-verse.org) * in File>Verse entry "Get Servers" to get server list or * RMB on "Available Verse Servers" in outliner to "Refresh" server list Enjoy :)
Diffstat (limited to 'extern')
-rw-r--r--extern/verse/dist/Makefile3
-rw-r--r--extern/verse/dist/SConstruct6
-rw-r--r--extern/verse/dist/verse_ms.c286
-rw-r--r--extern/verse/dist/verse_ms.h72
-rw-r--r--extern/verse/make/msvc_7_0/libverse.vcproj6
5 files changed, 370 insertions, 3 deletions
diff --git a/extern/verse/dist/Makefile b/extern/verse/dist/Makefile
index 34cc10603b4..166fa1fd69c 100644
--- a/extern/verse/dist/Makefile
+++ b/extern/verse/dist/Makefile
@@ -30,7 +30,8 @@ LIBVERSE_SRC = $(PROT_OUT) v_bignum.c v_cmd_buf.c v_connect.c \
v_connection.c v_connection.h v_encryption.c \
v_func_storage.c v_internal_verse.h v_man_pack_node.c \
v_network.c v_network.h v_network_in_que.c v_network_out_que.c \
- v_pack.c v_pack.h v_pack_method.c v_prime.c v_randgen.c v_util.c
+ v_pack.c v_pack.h v_pack_method.c v_prime.c v_randgen.c v_util.c \
+ verse_ms.c
LIBVERSE_OBJ = $(patsubst %h,, $(LIBVERSE_SRC:%.c=%.o))
diff --git a/extern/verse/dist/SConstruct b/extern/verse/dist/SConstruct
index d54f299c3f6..b0b9ed3ef2f 100644
--- a/extern/verse/dist/SConstruct
+++ b/extern/verse/dist/SConstruct
@@ -110,7 +110,8 @@ lib_source_files = (['v_cmd_buf.c',
'v_prime.c',
'v_randgen.c',
'v_util.c',
- 'v_bignum.c'
+ 'v_bignum.c',
+ 'verse_ms.c'
])
lib_source_files.extend(cmd_gen_deps)
@@ -135,10 +136,11 @@ verselib_env.Append(CPPDEFINES = defines)
verseserver_env = verse_env.Copy()
verseserver_env.Append(CPPDEFINES = defines)
verseserver_env.Append (LIBPATH = ['.'])
+verseserver_env.Append (LIBS= ['verse'])
verseserver_env.Append (LIBS= platform_libs)
verselib_env.BlenderLib(libname='verse', sources=lib_source_files, includes=["."], defines = defines, libtype=['core', 'intern'], priority = [5, 5])
-verseserver_env.BlenderProg(builddir="#"+root_build_dir+os.sep, progname='verse', sources=server_source_files, libs=['verse'],
+verseserver_env.BlenderProg(builddir="#"+root_build_dir+os.sep, progname='verse', sources=server_source_files, libs=[],
libpath='#'+env['BF_BUILDDIR']+'/lib')
diff --git a/extern/verse/dist/verse_ms.c b/extern/verse/dist/verse_ms.c
new file mode 100644
index 00000000000..84f3fdb837b
--- /dev/null
+++ b/extern/verse/dist/verse_ms.c
@@ -0,0 +1,286 @@
+/*
+ * A helper library to send and parse master server pings. See the relevant
+ * header for details.
+ *
+ * This code was written in 2006 by Emil Brink. It is released as public domain.
+*/
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "verse.h"
+#include "verse_ms.h"
+
+/* Build and send a MS:GET packet. */
+void verse_ms_get_send(const char *address, int fields, const char *tags)
+{
+ char req[128];
+
+ strcpy(req, "MS:GET IP=");
+ if(fields & VERSE_MS_FIELD_DESCRIPTION)
+ strcat(req, "DE");
+ if(tags != NULL)
+ {
+ strcat(req, " TA=");
+ strcat(req, tags);
+ }
+ verse_send_ping(address, req);
+}
+
+/* Skip assign, i.e. "NAME=" string, at <msg>. Stores name into <put>, and then updates
+ * it. Returns NULL on parse error, in which case the <put> pointer is not advanced.
+*/
+static const char * skip_assign(char **put, const char *msg)
+{
+ if(isalpha(*msg))
+ {
+ char *p = put != NULL ? *put : NULL;
+
+ if(p != NULL)
+ *p++ = *msg;
+ msg++;
+ while(*msg && (isalnum(*msg) || *msg == '_'))
+ {
+ if(p != NULL)
+ *p++ = *msg;
+ msg++;
+ }
+ if(*msg == '=')
+ {
+ if(p != NULL)
+ *p++ = '\0';
+ if(put != NULL)
+ *put = p;
+ return msg + 1;
+ }
+ }
+ return NULL;
+}
+
+/** Skip value at <msg>, optionally storing de-quoted version through <put>,
+ * which is advanced. Returns NULL on parse error, without updating <put>.
+*/
+static const char * skip_value(char **put, const char *msg)
+{
+ char *p = (put != NULL) ? *put : NULL;
+
+ if(*msg == '"')
+ {
+ msg++;
+ while(*msg != '\0' && *msg != '"')
+ {
+ if(*msg == '\\')
+ {
+ if(msg[1] != '\0')
+ msg++;
+ else
+ return NULL;
+ }
+ if(p != NULL)
+ *p++ = *msg;
+ msg++;
+ }
+ if(*msg == '"')
+ {
+ if(p != NULL)
+ *p++ = '\0';
+ if(put != NULL)
+ *put = p;
+ msg++;
+ if(*msg == '\0' || isspace(*msg))
+ return msg;
+ }
+ return NULL;
+ }
+ while(*msg && !isspace(*msg))
+ {
+ if(*msg == '"')
+ return NULL;
+ if(p != NULL)
+ *p++ = *msg;
+ msg++;
+ }
+ if(p != NULL)
+ *p++ = '\0';
+ if(put != NULL)
+ *put = p;
+ return msg;
+}
+
+static const char * put_field(VMSField *field, char **put, const char *src)
+{
+ const char *ptr;
+ char *base = *put;
+
+ if((ptr = skip_assign(put, src)) != NULL && ptr - src > 1)
+ {
+ field->name = base;
+ src = ptr;
+ base = *put;
+ if((ptr = skip_value(put, src)) != NULL)
+ {
+ field->value = base;
+ return ptr;
+ }
+ }
+ return NULL;
+}
+
+static int cmp_fields(const void *a, const void *b)
+{
+ return strcmp(((const VMSField *) a)->name, ((const VMSField *) b)->name);
+}
+
+VMSServer ** verse_ms_list_parse(const char *msg)
+{
+ const char *word[384]; /* Takes quite a lot of stack space. */
+ const char *ptr;
+ char *put;
+ size_t num_word = 0, i, j, num_ip = 0, num_field, space = 0;
+ VMSServer **desc, *next;
+ VMSField *field;
+
+ if(strncmp(msg, "MS:LIST", 7) == 0)
+ msg += 7;
+ if(*msg != ' ')
+ return NULL;
+
+ /* Step one: split the string into words, at whitespace. Split is aware
+ * of quoting rules for value assignment, this is crucial. This split is
+ * non-invasive, meaning each "word" will be a suffix.
+ */
+ while(*msg)
+ {
+ while(isspace(*msg))
+ msg++;
+ ptr = skip_assign(NULL, msg);
+ if(ptr != NULL)
+ {
+ space += ptr - msg;
+ word[num_word++] = msg;
+ msg = ptr;
+ ptr = skip_value(NULL, msg);
+ if(ptr == NULL)
+ {
+ fprintf(stderr, "Parse error\n");
+ return NULL;
+ }
+ space += ptr - msg + 1;
+ msg = ptr;
+ }
+ else if(*msg != '\0')
+ {
+ fprintf(stderr, "Parse error\n");
+ return NULL;
+ }
+ }
+ /* Now, count how many words begin with "IP=". */
+ for(i = 0; i < num_word; i++)
+ {
+ if(strncmp(word[i], "IP=", 3) == 0)
+ num_ip++;
+ }
+/* printf("found %u IPs, %u bytes\n", num_ip, space);
+ printf("%u IP and %u words -> %u fields total\n", num_ip, num_word, num_word - num_ip);
+*/ num_field = num_word - num_ip;
+ /* Allocate the descriptions. */
+/* printf("allocating %u bytes\n", (num_ip + 1) * (sizeof *desc) + num_ip * sizeof **desc + num_field * sizeof (VMSField) + space);
+ printf(" %u for pointers, %u for structs, %u for fields, %u string\n",
+ (num_ip + 1) * (sizeof *desc), num_ip * sizeof **desc, num_field * sizeof (VMSField), space);
+*/ desc = malloc((num_ip + 1) * (sizeof *desc) + num_ip * sizeof **desc + num_field * sizeof (VMSField) + space);
+ next = (VMSServer *) (desc + (num_ip + 1));
+/* printf("desc store at %u\n", (char *) next - (char *) desc);*/
+ field = (VMSField *) (next + num_ip);
+/* printf("field store at %u\n", (char *) field - (char *) desc);*/
+ put = (char *) (field + num_field);
+/* printf("string store at %u\n", put - (char *) desc);*/
+ for(i = j = 0; i < num_word;)
+ {
+ if(strncmp(word[i], "IP=", 3) == 0)
+ {
+ desc[j] = next;
+ next->ip = put;
+ ptr = skip_value(&put, word[i] + 3);
+ next->num_fields = 0;
+ next->field = field;
+ for(i++; i < num_word && strncmp(word[i], "IP=", 3) != 0; i++, next->num_fields++, field++)
+ put_field(&next->field[next->num_fields], &put, word[i]);
+ if(next->num_fields > 0) /* Sort the fields, for binary search later. */
+ qsort(next->field, next->num_fields, sizeof *next->field, cmp_fields);
+ j++;
+ next++;
+ }
+ else
+ i++;
+ }
+ desc[j] = NULL;
+ return desc;
+}
+
+/* A binary search, exploiting that the fields are sorted. */
+static const VMSField * field_find(const VMSServer *ms, const char *name)
+{
+ int lo, hi, mid, rel;
+
+ if(ms == NULL || name == NULL)
+ return NULL;
+ lo = 0;
+ hi = ms->num_fields;
+ while(lo <= hi)
+ {
+ mid = (lo + hi) / 2;
+ rel = strcmp(name, ms->field[mid].name);
+ if(rel == 0)
+ return &ms->field[mid];
+ if(rel < 0)
+ hi = mid - 1;
+ else
+ lo = mid + 1;
+ }
+ return NULL;
+}
+
+int verse_ms_field_exists(const VMSServer *ms, const char *name)
+{
+ if(ms == NULL || name == NULL)
+ return 0;
+ return field_find(ms, name) != NULL;
+}
+
+const char * verse_ms_field_value(const VMSServer *ms, const char *name)
+{
+ const VMSField *f;
+
+ if((f = field_find(ms, name)) != NULL)
+ return f->value;
+ return NULL;
+}
+
+#if defined VERSE_MS_STANDALONE
+
+int main(void)
+{
+ VMSServer **servers = verse_ms_list_parse("MS:LIST IP=127.0.0.1:4951 DE=\"A test server, mainly for Eskil\" COOL=yes BACKUP=daily LANG=sv_SE "
+ "IP=130.237.221.74 DE=\"Test server on a puny laptop\" COOL=yes DORKY=no OPEN=absolutely "
+ "IP=127.0.0.1:5151 DE=\"This is a back slash: '\\\\', cool huh?\" "
+ "IP=127.0.0.1:6676 DE=\"a quote looks like this: \\\"\" IP=127.0.0.1:1122 ");
+
+ if(servers != NULL)
+ {
+ int i, j;
+
+ printf("Server info:\n");
+ for(i = 0; servers[i] != NULL; i++)
+ {
+ printf("%u: IP=%s\n", i, servers[i]->ip);
+ for(j = 0; j < servers[i]->num_fields; j++)
+ printf(" %s='%s'\n", servers[i]->field[j].name, servers[i]->field[j].value);
+ }
+ free(servers);
+ }
+ return EXIT_SUCCESS;
+}
+
+#endif /* VERSE_MS_STANDALONE */
diff --git a/extern/verse/dist/verse_ms.h b/extern/verse/dist/verse_ms.h
new file mode 100644
index 00000000000..5a27d3fd446
--- /dev/null
+++ b/extern/verse/dist/verse_ms.h
@@ -0,0 +1,72 @@
+/*
+ * This is Verse Master Server, a small help library to aid application developers
+ * make their applications interact with a Verse master server.
+ *
+ * There are two steps to the process:
+ *
+ * 1) Send a MS:GET request to a master server. This is done by the verse_ms_get_send()
+ * function, which calls verse_send_ping() internally.
+ *
+ * 2) Parse any returned MS:LIST packets. This is a two-step process. The application
+ * still owns the ping callback, and will need to check for received pings that
+ * start with MS:LIST, and call the verse_ms_list_parse() function to parse those.
+ *
+ * A successfully parsed MS:LIST packet will result in an array of VMSServer pointers
+ * being returned. Each VMSServer instance describes one server. Use the provided
+ * functions to query each server structure.
+ *
+ * The application should call free() on the returned vector, whenever it is done with
+ * the data (perhaps after copying it into application-defined data structures).
+ *
+ * For a lot more detail about the Verse master server protocol, please see
+ * the spec at <http://verse.blender.org/cms/Master_Server__v2.775.0.html>.
+ *
+ * This code was written in 2006 by Emil Brink. It is released as public domain.
+ *
+*/
+
+#define VERSE_MS_VERSION "1.0"
+
+#if defined __cplusplus
+extern "C" {
+#endif
+
+typedef struct {
+ const char *name; /* Field name. Upper-case. */
+ const char *value; /* Field value. Fully parsed, might contain spaces. */
+} VMSField;
+
+typedef struct {
+ const char *ip; /* IP address of server, in dotted decimal:port. */
+ unsigned int num_fields; /* Number of fields of extra info. */
+ VMSField *field; /* Vector of fields, or NULL if none. */
+} VMSServer;
+
+/* Formats and sends a MS:GET ping packet to the master server. The <fields> argument
+ * should be a combination of VERSE_MS_FIELD_ mask values. If <tags> is set, it should
+ * be a comma-separated set of include/exclude tags, like "a,b,-c,d,-e".
+*/
+#define VERSE_MS_FIELD_DESCRIPTION (1 << 0)
+extern void verse_ms_get_send(const char *address, int fields, const char *tags);
+
+/* Parses a master server response. This will be a string of the form "MS:LIST IP=blah ...",
+ * which is split into one struct per IP, and any additional fields parsed (unquoted etc).
+ * Returns an array of VMSServer pointers, which is NULL-terminated. Returns NULL if there
+ * was a parse error somewhere in the string, no partial success is possible.
+*/
+extern VMSServer ** verse_ms_list_parse(const char *list);
+
+/* This is the only standard field name, currently. */
+#define VERSE_MS_FIELD_DESCRIPTION_NAME "DE" /* Human-readable server description. */
+
+/* Checks wether the given server has a field with the given name. */
+extern int verse_ms_field_exists(const VMSServer *ms, const char *name);
+
+/* Returns the value for the named field in the given server, if present.
+ * If not, NULL is returned.
+*/
+extern const char * verse_ms_field_value(const VMSServer *ms, const char *name);
+
+#if defined __cplusplus
+}
+#endif
diff --git a/extern/verse/make/msvc_7_0/libverse.vcproj b/extern/verse/make/msvc_7_0/libverse.vcproj
index ecf6208ac3d..1c9bfbfce33 100644
--- a/extern/verse/make/msvc_7_0/libverse.vcproj
+++ b/extern/verse/make/msvc_7_0/libverse.vcproj
@@ -229,6 +229,9 @@ ECHO Done
<File
RelativePath="..\..\dist\v_util.c">
</File>
+ <File
+ RelativePath="..\..\dist\verse_ms.c">
+ </File>
</Filter>
<Filter
Name="Header Files"
@@ -267,6 +270,9 @@ ECHO Done
RelativePath="..\..\dist\v_util.h">
</File>
</Filter>
+ <File
+ RelativePath="..\..\dist\verse_ms.h">
+ </File>
</Files>
<Globals>
</Globals>