Esempio n. 1
0
static void
test_value_AS(void) {

    xmlrpc_value *v;
    xmlrpc_value *v2;
    xmlrpc_value *v3;
    xmlrpc_env env;
    size_t len;

    /* Test parsing of 'A' and 'S'. */

    xmlrpc_env_init(&env);

    v = xmlrpc_build_value(&env, "((){})");
    TEST_NO_FAULT(&env);
    xmlrpc_decompose_value(&env, v, "(AS)", &v2, &v3);
    xmlrpc_DECREF(v);
    TEST_NO_FAULT(&env);
    TEST(XMLRPC_TYPE_ARRAY == xmlrpc_value_type(v2));
    TEST(XMLRPC_TYPE_STRUCT == xmlrpc_value_type(v3));
    len = xmlrpc_array_size(&env, v2);
    TEST_NO_FAULT(&env);
    TEST(len == 0);
    len = xmlrpc_struct_size(&env, v3);
    TEST_NO_FAULT(&env);
    TEST(len == 0);
    xmlrpc_DECREF(v2);
    xmlrpc_DECREF(v3);

    xmlrpc_env_clean(&env);
}
Esempio n. 2
0
xmlrpc_value* StartSendingVideo(xmlrpc_env *env, xmlrpc_value *param_array, void *user_data)
{
	MCU *mcu = (MCU *)user_data;
	MultiConf *conf = NULL;

	 //Parseamos
	int confId;
	int partId;
	char *sendVideoIp;
	int sendVideoPort;
	xmlrpc_value *rtpMap;
	xmlrpc_parse_value(env, param_array, "(iisiS)", &confId,&partId,&sendVideoIp,&sendVideoPort,&rtpMap);

	//Get the rtp map
	VideoCodec::RTPMap map;

	//Get map size
	int j = xmlrpc_struct_size(env,rtpMap);

	//Parse rtp map
	for (int i=0;i<j;i++)
	{
		xmlrpc_value *key, *val;
		const char *type;
		int codec;
		//Read member
		xmlrpc_struct_read_member(env,rtpMap,i,&key,&val);
		//Read name
		xmlrpc_parse_value(env,key,"s",&type);
		//Read value
		xmlrpc_parse_value(env,val,"i",&codec);
		//Add to map
		map[atoi(type)] = (VideoCodec::Type) codec;
		//Decrement ref counter
		xmlrpc_DECREF(key);
		xmlrpc_DECREF(val);
	}

	//Comprobamos si ha habido error
	if(env->fault_occurred)
		xmlerror(env,"Fault occurred\n");

	//Obtenemos la referencia
	if(!mcu->GetConferenceRef(confId,&conf))
		return xmlerror(env,"Conference does not exist");

	//La borramos
	int res = conf->StartSendingVideo(partId,sendVideoIp,sendVideoPort,map) != NULL;

	//Liberamos la referencia
	mcu->ReleaseConferenceRef(confId);

	//Salimos
	if(!res)
		return xmlerror(env,"Error\n");

	//Devolvemos el resultado
	return xmlok(env);
}
xmlrpc_value* MediaGatewayStartSendingText(xmlrpc_env *env, xmlrpc_value *param_array, void *user_data)
{
	MediaGateway *mediaGateway = (MediaGateway *)user_data;
	MediaBridgeSession *session = NULL;

	 //Parseamos
	int sessionId;
	char *sendTextIp;
	int sendTextPort;
	xmlrpc_value *rtpMap;
	xmlrpc_parse_value(env, param_array, "(isiS)", &sessionId,&sendTextIp,&sendTextPort,&rtpMap);

	//Comprobamos si ha habido error
	if(env->fault_occurred)
		return 0;

	//Get the rtp map
	TextCodec::RTPMap map;

	//Get map size
	int j = xmlrpc_struct_size(env,rtpMap);

	//Parse rtp map
	for (int i=0;i<j;i++)
	{
		xmlrpc_value *key, *val;
		const char *type;
		int codec;
		//Read member
		xmlrpc_struct_read_member(env,rtpMap,i,&key,&val);
		//Read name
		xmlrpc_parse_value(env,key,"s",&type);
		//Read value
		xmlrpc_parse_value(env,val,"i",&codec);
		//Add to map
		map[atoi(type)] = (TextCodec::Type) codec;
		//Decrement ref counter
		xmlrpc_DECREF(key);
		xmlrpc_DECREF(val);
	}

	//Obtenemos la referencia
	if(!mediaGateway->GetMediaBridgeRef(sessionId,&session))
		return xmlerror(env,"La sessionerencia no existe\n");

	//La borramos
	int res = session->StartSendingText(sendTextIp,sendTextPort,map);

	//Liberamos la referencia
	mediaGateway->ReleaseMediaBridgeRef(sessionId);

	//Salimos
	if(!res)
		return xmlerror(env,"Error\n");

	//Devolvemos el resultado
	return xmlok(env);
}
Esempio n. 4
0
xmlrpc_value* StartReceivingText(xmlrpc_env *env, xmlrpc_value *param_array, void *user_data)
{
	MCU *mcu = (MCU *)user_data;
	MultiConf *conf = NULL;

	 //Parseamos
	int confId;
	int partId;
	xmlrpc_value *rtpMap;
	xmlrpc_parse_value(env, param_array, "(iiS)", &confId,&partId,&rtpMap);

	//Get the rtp map
	TextCodec::RTPMap map;

	int j = xmlrpc_struct_size(env,rtpMap);

	//Parse rtp map
	for (int i=0;i<j;i++)
	{
		xmlrpc_value *key, *val;
		const char *type;
		int codec;
		//Read member
		xmlrpc_struct_read_member(env,rtpMap,i,&key,&val);
		//Read name
		xmlrpc_parse_value(env,key,"s",&type);
		//Read value
		xmlrpc_parse_value(env,val,"i",&codec);
		//Add to map
		map[atoi(type)] = (TextCodec::Type) codec;
		//Decrement ref counter
		xmlrpc_DECREF(key);
		xmlrpc_DECREF(val);
	}

	//Comprobamos si ha habido error
	if(env->fault_occurred)
		xmlerror(env,"Fault occurred\n");

	//Obtenemos la referencia
	if(!mcu->GetConferenceRef(confId,&conf))
		return xmlerror(env,"Conference does not exist");

	//La borramos
	int recTextPort = conf->StartReceivingText(partId,map);

	//Liberamos la referencia
	mcu->ReleaseConferenceRef(confId);

	//Salimos
	if(!recTextPort)
		return xmlerror(env,"No se ha podido terminar la conferencia\n");

	//Devolvemos el resultado
	return xmlok(env,xmlrpc_build_value(env,"(i)",recTextPort,recTextPort));
}
Esempio n. 5
0
value_struct::operator map<string, xmlrpc_c::value>() const {

    this->validateInstantiated();

    env_wrap env;
    unsigned int structSize;

    structSize = xmlrpc_struct_size(&env.env_c, this->cValueP);
    throwIfError(env);

    map<string, xmlrpc_c::value> retval;

    for (unsigned int i = 0; i < structSize; ++i) {
        class cMemberWrapper {
        public:
            xmlrpc_value *keyP;
            xmlrpc_value *valueP;

            cMemberWrapper(xmlrpc_value *const structP,
                           unsigned int const index) {

                env_wrap env;

                xmlrpc_struct_read_member(&env.env_c, structP, index,
                                          &keyP, &valueP);

                throwIfError(env);
            }

            ~cMemberWrapper() {
                xmlrpc_DECREF(keyP);
                xmlrpc_DECREF(valueP);
            }
        };

        cMemberWrapper memberWrapper(this->cValueP, i);

        cStringWrapper keyWrapper(memberWrapper.keyP);

        string const key(keyWrapper.str, keyWrapper.length);

        retval[key] = xmlrpc_c::value(memberWrapper.valueP);
    }

    return retval;
}
Esempio n. 6
0
static void
validateParseResponseResult(xmlrpc_value * const valueP) {

    xmlrpc_env env;

    xmlrpc_value * s;
    xmlrpc_int32 int_max;
    xmlrpc_int32 int_min;
    xmlrpc_int32 int_one;
    xmlrpc_bool bool_false;
    xmlrpc_bool bool_true;
    char * str_hello;
    char * str_untagged;
    char * datetime;
    unsigned char * b64_data;
    size_t b64_len;
    double negone;
    double zero;
    double one;

    xmlrpc_env_init(&env);

    xmlrpc_decompose_value(
        &env, valueP, "((iibbs68())idddSs)", 
        &int_max, &int_min,
        &bool_false, &bool_true, &str_hello,
        &b64_data, &b64_len, &datetime,
        &int_one, &negone, &zero, &one, &s, &str_untagged);

    TEST_NO_FAULT(&env);
    TEST(int_max == INT_MAX);
    TEST(int_min == INT_MIN);
    TEST(!bool_false);
    TEST(bool_true);
    TEST(strlen(str_hello) == strlen("Hello, world! <&>"));
    TEST(streq(str_hello, "Hello, world! <&>"));
    TEST(b64_len == 11);
    TEST(memcmp(b64_data, "base64 data", b64_len) == 0);
    TEST(streq(datetime, "19980717T14:08:55"));
    TEST(int_one == 1);
    TEST(negone == -1.0);
    TEST(zero == 0.0);
    TEST(one == 1.0);
    TEST(streq(str_untagged, "Untagged string"));
    free(str_hello);
    free(b64_data);
    free(datetime);
    free(str_untagged);

    {
        /* Analyze the contents of our struct. */

        xmlrpc_value * sval;
        int size, sval_int;

        TEST(s != NULL);
        size = xmlrpc_struct_size(&env, s);
        TEST_NO_FAULT(&env);
        TEST(size == 2);
        sval = xmlrpc_struct_get_value(&env, s, "ten <&>");
        TEST_NO_FAULT(&env);
        xmlrpc_decompose_value(&env, sval, "i", &sval_int);
        TEST_NO_FAULT(&env);
        TEST(sval_int == 10);
        sval = xmlrpc_struct_get_value(&env, s, "twenty");
        TEST_NO_FAULT(&env);
        xmlrpc_decompose_value(&env, sval, "i", &sval_int);
        TEST_NO_FAULT(&env);
        TEST(sval_int == 20);
        xmlrpc_DECREF(s);
    }    

    xmlrpc_env_clean(&env);
}
Esempio n. 7
0
static void
test_struct (void) {

    xmlrpc_env env;
    xmlrpc_value * value1P;
    xmlrpc_value *s, *i, *i1, *i2, *i3, *key, *value;
    size_t size;
    int present;
    xmlrpc_bool bval;
    char const weirdKey[] = {'f', 'o', 'o', '\0', 'b', 'a', 'r'};

    xmlrpc_env_init(&env);

    /* Create a struct. */
    s = xmlrpc_struct_new(&env);
    TEST_NO_FAULT(&env);
    TEST(s != NULL);
    TEST(XMLRPC_TYPE_STRUCT == xmlrpc_value_type(s));
    size = xmlrpc_struct_size(&env, s);
    TEST_NO_FAULT(&env);
    TEST(size == 0);

    /* Create some elements to insert into our struct. */
    i1 = xmlrpc_build_value(&env, "s", "Item #1");
    TEST_NO_FAULT(&env);
    i2 = xmlrpc_build_value(&env, "s", "Item #2");
    TEST_NO_FAULT(&env);
    i3 = xmlrpc_build_value(&env, "s", "Item #3");
    TEST_NO_FAULT(&env);

    /* Insert a single item. */
    xmlrpc_struct_set_value(&env, s, "foo", i1);
    TEST_NO_FAULT(&env);
    size = xmlrpc_struct_size(&env, s);
    TEST_NO_FAULT(&env);
    TEST(size == 1);

    /* Insert an item whose key has the same hash value as "foo". */
    xmlrpc_struct_set_value(&env, s, "qmdebdw", i2);
    TEST_NO_FAULT(&env);
    size = xmlrpc_struct_size(&env, s);
    TEST_NO_FAULT(&env);
    TEST(size == 2);
    i = xmlrpc_struct_get_value(&env, s, "foo");
    TEST_NO_FAULT(&env);
    TEST(i == i1);
    i = xmlrpc_struct_get_value(&env, s, "qmdebdw");
    TEST_NO_FAULT(&env);
    TEST(i == i2);

    /* Replace an existing element with a different element. */
    xmlrpc_struct_set_value(&env, s, "foo", i3);
    TEST_NO_FAULT(&env);
    size = xmlrpc_struct_size(&env, s);
    TEST_NO_FAULT(&env);
    TEST(size == 2);
    i = xmlrpc_struct_get_value(&env, s, "foo");
    TEST_NO_FAULT(&env);
    TEST(i == i3);

    /* Insert an item with a NUL in the key */
    xmlrpc_struct_set_value_n(&env, s, weirdKey, sizeof(weirdKey), i2);
    TEST_NO_FAULT(&env);
    size = xmlrpc_struct_size(&env, s);
    TEST_NO_FAULT(&env);
    TEST(size == 3);

    test_struct_get_element(s, i3, i2, weirdKey, sizeof(weirdKey));

    /* Replace an existing element with the same element (tricky). */
    xmlrpc_struct_set_value(&env, s, "foo", i3);
    TEST_NO_FAULT(&env);
    size = xmlrpc_struct_size(&env, s);
    TEST_NO_FAULT(&env);
    TEST(size == 3);
    i = xmlrpc_struct_get_value(&env, s, "foo");
    TEST_NO_FAULT(&env);
    TEST(i == i3);

    /* Test for the presence and absence of elements. */
    present = xmlrpc_struct_has_key(&env, s, "foo");
    TEST_NO_FAULT(&env);
    TEST(present);
    present = xmlrpc_struct_has_key(&env, s, "qmdebdw");
    TEST_NO_FAULT(&env);
    TEST(present);
    present = xmlrpc_struct_has_key(&env, s, "bogus");
    TEST_NO_FAULT(&env);
    TEST(!present);

    /* Make sure our typechecks work correctly. */
    xmlrpc_struct_size(&env, i1);
    TEST_FAULT(&env, XMLRPC_TYPE_ERROR);

    xmlrpc_struct_has_key(&env, i1, "foo");
    TEST_FAULT(&env, XMLRPC_TYPE_ERROR);

    xmlrpc_struct_set_value(&env, i1, "foo", i2);
    TEST_FAULT(&env, XMLRPC_TYPE_ERROR);

    xmlrpc_struct_set_value_v(&env, s, s, i2);
    TEST_FAULT(&env, XMLRPC_TYPE_ERROR);

    /* Test cleanup code (w/memprof). */
    xmlrpc_DECREF(s);

    s = xmlrpc_build_value(&env, "{s:s,s:i,s:b}",
                           "foo", "Hello!",
                           "bar", (xmlrpc_int32) 1,
                           "baz", (xmlrpc_bool) 0);
    TEST_NO_FAULT(&env);
    TEST(s != NULL);
    TEST(xmlrpc_value_type(s) == XMLRPC_TYPE_STRUCT);
    size = xmlrpc_struct_size(&env, s);
    TEST_NO_FAULT(&env);
    TEST(size == 3);
    present = xmlrpc_struct_has_key(&env, s, "foo");
    TEST_NO_FAULT(&env);
    TEST(present);
    present = xmlrpc_struct_has_key(&env, s, "bar");
    TEST_NO_FAULT(&env);
    TEST(present);
    present = xmlrpc_struct_has_key(&env, s, "baz");
    TEST_NO_FAULT(&env);
    TEST(present);
    xmlrpc_struct_read_value(&env, s, "baz", &value1P);
    TEST_NO_FAULT(&env);
    xmlrpc_read_bool(&env, value1P, &bval);
    TEST_NO_FAULT(&env);
    TEST(!bval);
    xmlrpc_DECREF(value1P);

    testStructReadout(s, 3);

    test_struct_decompose(s);

    /* Test type check. */
    xmlrpc_struct_get_key_and_value(&env, i1, 0, &key, &value);
    TEST_FAULT(&env, XMLRPC_TYPE_ERROR);
    TEST(key == NULL && value == NULL);
    
    /* Test bounds checks. */
    xmlrpc_struct_get_key_and_value(&env, s, -1, &key, &value);
    TEST_FAULT(&env, XMLRPC_INDEX_ERROR);
    TEST(key == NULL && value == NULL);

    xmlrpc_struct_get_key_and_value(&env, s, 3, &key, &value);
    TEST_FAULT(&env, XMLRPC_INDEX_ERROR);
    TEST(key == NULL && value == NULL);
    
    /* Test cleanup code (w/memprof). */
    xmlrpc_DECREF(s);

    xmlrpc_DECREF(i1);
    xmlrpc_DECREF(i2);
    xmlrpc_DECREF(i3);
    xmlrpc_env_clean(&env);
}
Esempio n. 8
0
int main( int argc, char *argv[] )
{

	xmlrpc_env env;
	xmlrpc_value * resultP;
	xmlrpc_value * keyP;
	xmlrpc_value * valueP;
	int struct_size;
	int i, j;
	size_t length;
	const char * str_key_value;
	xmlrpc_int   int_key_value;
	unsigned int max_hits = 0;
	unsigned int rows = 0;
	int rv;
	char *uri;
	int options;		/* what kind of nodes should be processed */
	int uri_pos;		/* position of first non option argument */
	char stropts[16];
	int  pos = 0;
	int  mask_length = 32;	/* 32 means NO aggregate */

	if (argc-1 < 1) {
		print_help();
		exit(0);
	}
	uri_pos = process_options(argc, argv, &options, &mask_length);
	switch (options) {
		case OPT_HOT:
				sprintf(stropts, "HOT");
				break;
		case OPT_ALL:
				sprintf(stropts, "ALL");
				break;
		case OPT_WARM:
				sprintf(stropts, "WARM");
				break;
	}
	printf("Nodes = %s\n", stropts);
	printf("Mask  = /%d\n", mask_length);

	/* Start up our XML-RPC client library. */
	xmlrpc_client_init(XMLRPC_CLIENT_NO_FLAGS, NAME, VERSION);
	
	/* Initialize our error-handling environment. */
	xmlrpc_env_init(&env);

	/* prototype:
	   xmlrpc_value * xmlrpc_client_call(xmlrpc_env * const envP,
	                                     const char * const server_url, const char * const method_name,
	                                     const char * const format, ...);
	 */
	asprintf(&uri, "http://%s/RPC2", argv[uri_pos]);
	resultP = xmlrpc_client_call(&env, uri,
	                             "pike.top",
	                             "(s)", stropts);
	free(uri);
	die_if_fault_occurred_line(&env, __LINE__);
	
	/* parse returned structure */
	if ( xmlrpc_value_type(resultP) != XMLRPC_TYPE_STRUCT ) {
		printf("unexpected result - should be structure\n");
		xmlrpc_env_clean(&env);
		xmlrpc_client_cleanup();
		exit(1);
	}

	struct_size = xmlrpc_struct_size(&env, resultP);
	die_if_fault_occurred_line(&env, __LINE__);
//	printf("Struct size: %d\n", struct_size);

	if ( ! get_int_from_struct_by_name(resultP, MAX_HITS, &max_hits) ) {
		fprintf(stderr, "ERROR: %s not foung in result\n", MAX_HITS);
		exit (1);
	}
	printf("max_hits = %d\n", max_hits);
	if ( ! get_int_from_struct_by_name(resultP, NUMBER_OF_ROWS, &rows) ) {
		fprintf(stderr, "ERROR: %s not foung in result\n", NUMBER_OF_ROWS);
		exit (1);
	}
	printf("rows = %d\n", rows);
	TopItem top_items[rows];
	TopItem *item;			/* tmp item ptr */
	TopItem *result_items = top_items;	/* if no aggregation use this */
	memset(top_items, 0, sizeof(top_items));

	/* aggregated values */
	
	if ( rows == 0 )
		return 0;
	
	for ( i = 0, item = top_items; i < rows; ++i, ++item ) {
		if ( ! read_row(resultP, i, item) ) {
			fprintf(stderr, "ERROR: while reading row number %d\n", i);
		}
		/* fill in ipv4 addr */
//		printf("item[%d].ip_addr = %s, len = %d\n", i, item->ip_addr, strlen(item->ip_addr));
		rv = inet_pton(AF_INET, item->ip_addr, &item->ipv4_addr);
		if ( rv > 0 ) {
//			printf("IPv4 addr: %x\n", item->ipv4_addr);
		} else {
			fprintf(stderr, "IP conversion failed - not an IPv4 address: '%s'\n", item->ip_addr);	/* conversion failed from any reason */
			printf("item[%d].ipv4_addr = %x\n", i, item->ipv4_addr);
		}
			
	}

	assert( rows > 0 );
	/* if IP mask length is shorter than 32 then aggregate list according to the mask */
	if ( mask_length < 32 ) {
		uint32_t ip_mask = htonl(mask(mask_length));
		
		qsort(top_items, rows, sizeof(TopItem), compare_TopItem_ipv4_addr);		/* sort by IPv4 */

		/* skip items without ipv4 address */
		i = 0;	/* index of non aggregated items */
		while (!top_items[i].ipv4_addr && i < rows ) {
			printf("Skip item[%d] - do not has IPv4 address: %s\n", i, top_items[i].ip_addr);
			memset(&top_items[i], 0, sizeof(TopItem));
			++i;
		}

		j = 0;	/* index of aggregated items */
		if ( i == 0 )
			++i;
		
		top_items[0].ipv4_addr &= ip_mask;
		top_items[0].num_of_ips = 1;
		inet_ntop(AF_INET, &top_items[0].ipv4_addr, top_items[0].ip_addr, sizeof(top_items[0].ip_addr));
		while ( i < rows ) {
			top_items[i].ipv4_addr &= ip_mask;
			
			if ( top_items[j].ipv4_addr == top_items[i].ipv4_addr ) {
				top_items[j].leaf_hits[0] += top_items[i].leaf_hits[0];
				top_items[j].leaf_hits[1] += top_items[i].leaf_hits[1];
				++(top_items[j].num_of_ips);
				++i;
			}
			else {
				++j;
				top_items[j] = top_items[i];
				top_items[j].num_of_ips = 1;
				inet_ntop(AF_INET, &top_items[j].ipv4_addr, top_items[j].ip_addr, sizeof(top_items[j].ip_addr));
				++i;
			}
		}
		rows = j + 1;
	}

	qsort(top_items, rows, sizeof(TopItem), compare_TopItem_hits_reverse);

	print_rows( top_items, rows, mask_length );

	/* Dispose of our result value. */
	xmlrpc_DECREF(resultP);

	/* Clean up our error-handling environment. */
	xmlrpc_env_clean(&env);
	/* Shutdown our XML-RPC client library. */
	xmlrpc_client_cleanup();

	return 0;
}
static void
test_struct (void) {

    xmlrpc_env env;
    xmlrpc_value *s, *i, *i1, *i2, *i3, *key, *value;
    size_t size;
    int present;
    xmlrpc_int32 ival;
    xmlrpc_bool bval;
    char *sval;
    char const weirdKey[] = {'f', 'o', 'o', '\0', 'b', 'a', 'r'};

    xmlrpc_env_init(&env);

    /* Create a struct. */
    s = xmlrpc_struct_new(&env);
    TEST_NO_FAULT(&env);
    TEST(s != NULL);
    TEST(XMLRPC_TYPE_STRUCT == xmlrpc_value_type(s));
    size = xmlrpc_struct_size(&env, s);
    TEST_NO_FAULT(&env);
    TEST(size == 0);

    /* Create some elements to insert into our struct. */
    i1 = xmlrpc_build_value(&env, "s", "Item #1");
    TEST_NO_FAULT(&env);
    i2 = xmlrpc_build_value(&env, "s", "Item #2");
    TEST_NO_FAULT(&env);
    i3 = xmlrpc_build_value(&env, "s", "Item #3");
    TEST_NO_FAULT(&env);

    /* Insert a single item. */
    xmlrpc_struct_set_value(&env, s, "foo", i1);
    TEST_NO_FAULT(&env);
    size = xmlrpc_struct_size(&env, s);
    TEST_NO_FAULT(&env);
    TEST(size == 1);

    /* Insert two more items with conflicting hash codes. (We assume that
    ** nobody has changed the hash function.) */
    xmlrpc_struct_set_value(&env, s, "bar", i2);
    TEST_NO_FAULT(&env);
    xmlrpc_struct_set_value(&env, s, "aas", i3);
    TEST_NO_FAULT(&env);
    size = xmlrpc_struct_size(&env, s);
    TEST_NO_FAULT(&env);
    TEST(size == 3);

    /* Replace an existing element with a different element. */
    xmlrpc_struct_set_value(&env, s, "aas", i1);
    TEST_NO_FAULT(&env);
    size = xmlrpc_struct_size(&env, s);
    TEST_NO_FAULT(&env);
    TEST(size == 3);

    /* Insert an item with a NUL in the key */
    xmlrpc_struct_set_value_n(&env, s, weirdKey, sizeof(weirdKey), i2);
    TEST_NO_FAULT(&env);
    size = xmlrpc_struct_size(&env, s);
    TEST_NO_FAULT(&env);
    TEST(size == 4);

    test_struct_get_element(s, i1, i2, weirdKey, sizeof(weirdKey));

    /* Replace an existing element with the same element (tricky). */
    xmlrpc_struct_set_value(&env, s, "aas", i1);
    TEST_NO_FAULT(&env);
    size = xmlrpc_struct_size(&env, s);
    TEST_NO_FAULT(&env);
    TEST(size == 4);
    i = xmlrpc_struct_get_value(&env, s, "aas");
    TEST_NO_FAULT(&env);
    TEST(i == i1);

    /* Test for the presence and absence of elements. */
    present = xmlrpc_struct_has_key(&env, s, "aas");
    TEST_NO_FAULT(&env);
    TEST(present);
    present = xmlrpc_struct_has_key(&env, s, "bogus");
    TEST_NO_FAULT(&env);
    TEST(!present);

    /* Make sure our typechecks work correctly. */
    xmlrpc_struct_size(&env, i1);
    TEST_FAULT(&env, XMLRPC_TYPE_ERROR);

    xmlrpc_struct_has_key(&env, i1, "foo");
    TEST_FAULT(&env, XMLRPC_TYPE_ERROR);

    xmlrpc_struct_set_value(&env, i1, "foo", i2);
    TEST_FAULT(&env, XMLRPC_TYPE_ERROR);

    xmlrpc_struct_set_value_v(&env, s, s, i2);
    TEST_FAULT(&env, XMLRPC_TYPE_ERROR);

    /* Test cleanup code (w/memprof). */
    xmlrpc_DECREF(s);

    /* Build a struct using our automagic struct builder. */
    s = xmlrpc_build_value(&env, "{s:s,s:i,s:b}",
                           "foo", "Hello!",
                           "bar", (xmlrpc_int32) 1,
                           "baz", (xmlrpc_bool) 0);
    TEST_NO_FAULT(&env);
    TEST(s != NULL);
    TEST(XMLRPC_TYPE_STRUCT == xmlrpc_value_type(s));
    size = xmlrpc_struct_size(&env, s);
    TEST_NO_FAULT(&env);
    TEST(size == 3);
    present = xmlrpc_struct_has_key(&env, s, "foo");
    TEST_NO_FAULT(&env);
    TEST(present);
    present = xmlrpc_struct_has_key(&env, s, "bar");
    TEST_NO_FAULT(&env);
    TEST(present);
    present = xmlrpc_struct_has_key(&env, s, "baz");
    TEST_NO_FAULT(&env);
    TEST(present);
    i = xmlrpc_struct_get_value(&env, s, "baz");
    TEST_NO_FAULT(&env);
    xmlrpc_decompose_value(&env, i, "b", &bval);
    TEST_NO_FAULT(&env);
    TEST(!bval);

    testStructReadout(s, 3);

    /* Test our automagic struct parser. */
    xmlrpc_decompose_value(&env, s, "{s:b,s:s,s:i,*}",
                           "baz", &bval,
                           "foo", &sval,
                           "bar", &ival);
    TEST_NO_FAULT(&env);
    TEST(ival == 1);
    TEST(!bval);
    TEST(strcmp(sval, "Hello!") == 0);
    free(sval);

    /* Test automagic struct parser with value of wrong type. */
    xmlrpc_decompose_value(&env, s, "{s:b,s:i,*}",
                           "baz", &bval,
                           "foo", &sval);
    TEST_FAULT(&env, XMLRPC_TYPE_ERROR);

    /* Test automagic struct parser with bad key. */
    xmlrpc_decompose_value(&env, s, "{s:b,s:i,*}",
                           "baz", &bval,
                           "nosuch", &sval);
    TEST_FAULT(&env, XMLRPC_INDEX_ERROR);

    /* Test type check. */
    xmlrpc_struct_get_key_and_value(&env, i1, 0, &key, &value);
    TEST_FAULT(&env, XMLRPC_TYPE_ERROR);
    TEST(key == NULL && value == NULL);
    
    /* Test bounds checks. */
    xmlrpc_struct_get_key_and_value(&env, s, -1, &key, &value);
    TEST_FAULT(&env, XMLRPC_INDEX_ERROR);
    TEST(key == NULL && value == NULL);

    xmlrpc_struct_get_key_and_value(&env, s, 3, &key, &value);
    TEST_FAULT(&env, XMLRPC_INDEX_ERROR);
    TEST(key == NULL && value == NULL);
    
    /* Test cleanup code (w/memprof). */
    xmlrpc_DECREF(s);

    xmlrpc_DECREF(i1);
    xmlrpc_DECREF(i2);
    xmlrpc_DECREF(i3);
    xmlrpc_env_clean(&env);
}