Extensions:Uni-Verse/verse ms

提供: wiki
移動先: 案内検索

Introduction

This page describes a simple C static library called verse_ms. The suffix "ms" stands for "master server". The purpose of the library is to encapsulate and hide the details about how to request and parse information from a Verse master server, from application programmers.

The idea is that this should lower the treshold for adding master server support to applications that already support Verse. This is good for users, since master server support makes it easier to find a Verse server to connect to.

The library is very small, and application developers are encouraged to simply include the source code directly in their code (for C or C++ applications, that is). There is no need to bother with a separate build and install of the library, and thus make it into a true dependency.

The code in verse_ms is licensed as public domain, so there should not be any license conflicts.

Getting verse_ms

The code for the verse_ms library lives in the same CVS module as the current reference master server implementation. This module is called verse-master, and lives in the main Verse CVS repository, so get it from there.

The API

This section describes the API implemented by the verse_ms library. It is split into two parts; one for sending queries to master servers, one for interpreting any responses.

Sending a Query

There is only a single function defined in the verse_ms library to query a master server. This is called sending a "get", and the function is:

 extern void verse_ms_get_send(const char *address, int fields, const char *tags);

The parameters are:

address
The IP address of the master server to which the query is to be sent. This should be a standard domain name, or dotted-IP address. You can append a port number, separating it from the address by a colon.
fields
This is a bit mask of which fields to include in the response. A field is simply some kind of extra information associated with each running Verse server, that is stored by the master server and made available to clients.
The client is free to chose the set of fields it is interested in, so that bandwidth can be conserved by not sending unwanted fields.
The current only defined field is the server description (set by the -ms:de server option to the reference server). This is represented by the symbolic constant VERSE_MS_FIELD_DESCRIPTION.
tags
This is a comma-separated list of tag names to filter against, or NULL to not do any tag filtering. Tag names are of the form [a-z][a-z0-9_]*, i.e. they start with a lower-case letter, and contain nothing but lower case letters, digits, and underscore characters after that. You can prepend a minus to exclude a tag from the results.

Note: There is no need to "connect" to the master server (as you usually do with ordinary Verse servers) before starting to use the verse_ms API.

Parsing a Response

The master server will respond to your client's query by sending a number of "list"-packets. These each contain information describing some number of registered Verse servers, so you need to pick them apart and extract the desired bits.

List packets are sent using standard Verse ping commands, so you must first register a callback on that command:

 verse_callback_set(void *) verse_send_ping, cb_ping, NULL);

The above will make Verse call your cb_ping() function from within verse_callback_update() when a ping is received.

At that point, you can use the verse_ms API to interpret the result. This is the function of interest:

 extern VMSServer ** verse_ms_list_parse(const char *list);

It has the following parameters:

list
This is the message string from the ping callback. It is assumed to contain a valid master server listing. If it does not, NULL is returned. Else, you get back a pointer to a vector of pointers to VMSServer structures, terminated by a NULL pointer.

Now, we need to take a look at the VMSServer structure. See the next section.

Server Information

As mentioned above, the verse_ms API returns information about existing Verse servers using a structure called VMSServer. This structure has the following definition:

 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;

The fields are sufficently described above to not warrant further explanations here.

Typically, an application will simply iterate over the vector of VMSServer structs, and use the information provided in each to fill in a user interface, print a list to the terminal, generate a web page, or whatever it is the client needs to do.

Fields

The only piece of information readily available directly in the VMSServer struct is the IP address of the server. This is considered the "base" information; all other information is arranged into fields that are associated with the address. Which fields are present depends on the format of the sent query, see above.

At the receiving end, fields are identified by name, since that is the most flexible way. You can use the following function to check if a given VMSServer instance contains a certain field:

extern int verse_ms_field_exists(const VMSServer *server, const char *name);

It will return 1 if the field exists in the server struct, 0 if it does not. The library provides symbolic constants for the known fields:

VERSE_MS_FIELD_DESCRIPTION_NAME
Request that the description field ("DE") is included in the response.

Fields can have values, which are simply strings. You can retrieve the value of a field using this function:

 extern const char * verse_ms_field_value(const VMSServer *server, const char *name);

It will return the value as a (read-only) string pointer, or NULL if the field was not defined in the given server.

In the general case, for a large number of fields, the above functions will be faster than doing a linear search.

When Done

When your client is done with the vector of VMSServer struct pointers returned from the call to verse_ms_list_parse(), it must be deallocated. This is done by simply calling free() on the returned pointer. This single call will free all memory used by the returned vector (including the actual VMSServer structs themselves, and all their fields). Neglecting to do this deallocation will lead to memory leaks.

Example Program

Below is a simple example program, written in C, that uses the verse_ms module to send a query to the master server(s) given on the command line, and then parse the responses.

The program does not terminate by itself, you must forcibly kill it in order to stop it.

The below code is also available in CVS, as the verse_ms-test.c file.

/*
 * A simple example program, showing how to use the verse_ms module.
 * 
 * Written October 2006 by Emil Brink. Released to the public domain.
*/

#include <stdio.h>
#include <stdlib.h>

#include "verse.h"
#include "verse_ms.h"

/* This gets called when we receive a ping from the master server. */
static void cb_ping(void *user, const char *address, const char *message)
{
	VMSServer	**s;
	unsigned int	i, j;

	/* Attempt to parse the message, as a master server response. */
	if((s = verse_ms_list_parse(message)) != NULL)
	{
		/* Go through results, print IP and all fields for each. */
		for(i = 0; s[i] != NULL; i++)
		{
			printf("%s\n", s[i]->ip);
			for(j = 0; j < s[i]->num_fields; j++)
				printf(" %s = '%s'\n",
				       s[i]->field[j].name,
				       s[i]->field[j].value);
		}
		free(s);	/* Free the server info. */
	}
}

int main(int argc, char *argv[])
{
	int	i;

	/* Register a callback to run when ping is received. */
	verse_callback_set((void *) verse_send_ping, (void *) cb_ping, NULL);

	/* Ping all master servers named on the command line. */
	for(i = 1; argv[i] != NULL; i++)
		verse_ms_get_send(argv[i], VERSE_MS_FIELD_DESCRIPTION, NULL);

	/* Spend forever just waiting for replies. */
	while(1)
	{
		verse_callback_update(10000);
	}

	return EXIT_SUCCESS;
}

Conclusions

This has been an introduction to the verse_ms utility module, for interacting with Verse master server(s).

It is hoped that the verse_ms module will help you add Verse master server support to your Verse-enabled application(s), thus making life easier for your users.