static void processDataTemplateSet(IpfixReceiver* ipfixReceiver, SourceID sourceId, IpfixSetHeader* set) {
static void processDataTemplateSet(IpfixParser* ipfixParser, SourceID sourceId, IpfixSetHeader* set) {
static void processDataTemplateSet(IpfixReceiver* ipfixReceiver, SourceID sourceId, IpfixSetHeader* set) {	IpfixDataTemplateHeader* th = (IpfixDataTemplateHeader*)&set->data;	byte* endOfSet = (byte*)set + ntohs(set->length);	byte* record = (byte*)&th->data;	/* DataTemplateSets are >= 4 byte, so we stop processing when only 3 bytes are left */	while (record < endOfSet - 3) {		BufferedTemplate* bt = (BufferedTemplate*)malloc(sizeof(BufferedTemplate));		DataTemplateInfo* ti = (DataTemplateInfo*)malloc(sizeof(DataTemplateInfo));		bt->sourceID = sourceId;		bt->templateID = ntohs(th->templateId);		bt->recordLength = 0;		bt->setID = ntohs(set->id);		bt->dataTemplateInfo = ti;		ti->userData = 0;		ti->fieldCount = ntohs(th->fieldCount);		ti->dataCount = ntohs(th->dataCount);		ti->fieldInfo = (FieldInfo*)malloc(ti->fieldCount * sizeof(FieldInfo));		int isLengthVarying = 0;		uint16_t fieldNo;		for (fieldNo = 0; fieldNo < ti->fieldCount; fieldNo++) {			ti->fieldInfo[fieldNo].type.id = ntohs(*(uint16_t*)((byte*)record+0));			ti->fieldInfo[fieldNo].type.length = ntohs(*(uint16_t*)((byte*)record+2));			ti->fieldInfo[fieldNo].offset = bt->recordLength; bt->recordLength+=ti->fieldInfo[fieldNo].type.length;			if (ti->fieldInfo[fieldNo].type.length == 65535) isLengthVarying=1;			if (ti->fieldInfo[fieldNo].type.id & 0x80) {				ti->fieldInfo[fieldNo].type.eid = ntohl(*(uint32_t*)((byte*)record+4));				record = (byte*)((byte*)record+8);				} else {				ti->fieldInfo[fieldNo].type.eid = 0;				record = (byte*)((byte*)record+4);				}			}		if (isLengthVarying) {			bt->recordLength = 65535;			for (fieldNo = 0; fieldNo < ti->fieldCount; fieldNo++) ti->fieldInfo[fieldNo].offset = 65535;			}		ti->dataInfo = (FieldInfo*)malloc(ti->fieldCount * sizeof(FieldInfo));		for (fieldNo = 0; fieldNo < ti->dataCount; fieldNo++) {			ti->dataInfo[fieldNo].type.id = ntohs(*(uint16_t*)((byte*)record+0));			ti->dataInfo[fieldNo].type.length = ntohs(*(uint16_t*)((byte*)record+2));			if (ti->dataInfo[fieldNo].type.id & 0x80) {				ti->dataInfo[fieldNo].type.eid = ntohl(*(uint32_t*)((byte*)record+4));				record = (byte*)((byte*)record+8);				} else {				ti->dataInfo[fieldNo].type.eid = 0;				record = (byte*)((byte*)record+4);				}			}				/* done with reading dataInfo, @c record now points to the fixed data block */		byte* dataStart = record;				int dataLength = 0;		for (fieldNo = 0; fieldNo < ti->dataCount; fieldNo++) {			ti->dataInfo[fieldNo].offset = dataLength;			if (ti->dataInfo[fieldNo].type.length == 65535) {				/* This is a variable-length field, get length from first byte and advance offset */				ti->dataInfo[fieldNo].type.length = *(uint8_t*)(dataStart + ti->dataInfo[fieldNo].offset);				ti->dataInfo[fieldNo].offset += 1;				if (ti->dataInfo[fieldNo].type.length == 255) {					/* First byte did not suffice, length is stored in next two bytes. Advance offset */					ti->dataInfo[fieldNo].type.length = *(uint16_t*)(dataStart + ti->dataInfo[fieldNo].offset);					ti->dataInfo[fieldNo].offset += 2;					}				}			dataLength += ti->dataInfo[fieldNo].type.length;			}					/* Copy fixed data block */		ti->data = (byte*)malloc(dataLength);		memcpy(ti->data,dataStart,dataLength);		/* Advance record to end of fixed data block, i.e. start of next template*/		record += dataLength;				bufferTemplate(ipfixReceiver->templateBuffer, bt); 		// FIXME: Template expiration disabled for debugging		// bt->expires = time(0) + TEMPLATE_EXPIRE_SECS;		int n;				for (n = 0; n < ipfixReceiver->callbackCount; n++) {			CallbackInfo* ci = &ipfixReceiver->callbackInfo[n];			if (ci->dataTemplateCallbackFunction) ci->dataTemplateCallbackFunction(ci->handle, sourceId, ti);			}  		}	}