• About TV's server
  • New in version 3.10
  • About the source code
  • About protocols/plugins
  • TV's server API
  • Protocol Initialisation
  • Protocol binding
  • Protocol Listening and handling
  • Protocol data storage
  • Control panel
  • Multi column list
  • Time and date
  • Http protocol functions
  • Unimplemented and/or replaced functions
  • Protocol initialization

    index About Protocol initialization
    One plug-in (a DLL-file) is able to provide more than one protocol, these protocols need to be identified somehow. At first, when the plug-in gets loaded into the memory, the plug-in hands over a list of names with protocols this plug-in is providing. TV's server will create an unique number (ProtocolSession) for every protocol and will pass this number to the plug-in. The plug-in will be requested to load the plug-in . On success, this unique number will be able to used for the services (like data storage) TV's server has to offer.

    Requirements
    The plug-in should at least export the functions GetProtocolNames and StartProtocol.

    GetProtocolNames function
    The function GetProtocolNames needs to pass a list of names of protocols this plug-in is providing.

    StartProtocol function
    The function StartProtocol needs to initiate the protocol. A ProtocolSession, uniqe for every protocol, will be created and will be passed through this function, therefore it will be called for every protocol separately. This function should at least make a call to the following functions: Optionally it can call function (before calling the AcceptProtocol function): Passing protocol names example
    This example will show how to implement the function GetProtocolNames. This example exports the protocol TCPIP and HTTP. Below there is an example of function StartProtocol.
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include "tvsserver_base
    .h"
    #include "tvs_redefine_api_names
    .h"
    
    int GetNullTerminatedListSize(char* list);
    
    char* supportedProtocols = "C_HTTP\0C_TCPIP\0\0";
    
    /*This function should return a list of protocols it supports*/
    int __stdcall GetProtocolNames(char *buf, int *len) {
    	int size;
    
    	if(len==0) return 0;
    
    	size = GetNullTerminatedListSize(supportedProtocols); //calculate the size of the list
    
    	//if the buffer is not big enough, return the size that is needed
    	if(*len==0 || *len<size) {
    		*len = size;
    			return 1;
    	}
    
    	//copy the list to the buffer and return
    	memcpy(buf, supportedProtocols, size);
    	return 1;
    }
    
    /*This function will calculate the size, in bytes, of a null-terminated list*/
    int GetNullTerminatedListSize(char* list) {
    	int cnt=0;
    	int len;
    
    	if(list==0) return 0;
    	
    	while(*list!=0) { //The terminating null byte is found, this is the end of the list
    		len = strlen(list);
    		list += len + 1; //add the size of the item +1 to get the next item
    		cnt += len + 1;
    	}
    	cnt++; //add the last zero byte
    
    	return cnt; //return the size of the list
    }
    
    Start protocol example
    The next example will show how to implement the function StartProtocol.
    #include <stdio.h>
    #include <string.h>
    #include <winsock2.h>
    #include "tvsserver_base
    .h"
    #include "tvs_redefine_api_names
    .h"
    #include <stdlib.h>
    
    // Need to link with Ws2_32.lib
    #pragma comment(lib, "ws2_32.lib")
    
    #define HTTP_AMMOUNT_OF_SUB_OPTIONS 1
    #define TCPIP_AMMOUNT_OF_SUB_OPTIONS 2
    
    typedef struct MyTCPIPstruct{
    	int socket;
    } MyTCPIPstruct;
    
    typedef struct MyHTTPstruct{
    	char* serverPath;
    } MyHTTPstruct;
    
    ProtocolSession *http_psess;
    ProtocolSession *tcpip_psess;
    
    #define OPT_TCP_PORT 1
    #define OPT_TCP_VERSION6 2
    
    #define HTTP_AMMOUNT_OF_SUPPPORTED_COMMANDS 3
    char* httpSupportedCommands[HTTP_AMMOUNT_OF_SUPPPORTED_COMMANDS] = {"GET", "POST", "HEAD"};
    
    char* createProtocolSignatureFromArray(char* p_array[], int ammountItems);
    
    int __stdcall StartProtocol(ProtocolSession *psess) {
    	ControlPanelOptions *cpo;
    	WORD wVersionRequested;
    	WSADATA wsaData;
    	int retv=0;
    	char* tempProtocolSignatureStructure=0;
    
    	/* Use the MAKEWORD(lowbyte, highbyte) macro declared in Windef.h */
    	wVersionRequested = MAKEWORD(2, 2);
    
    	if(!strcmp(psess->protocolName, "C_HTTP")) { //init the HTTP protocol
    		http_psess = psess;
    
    		tempProtocolSignatureStructure = createProtocolSignatureFromArray(httpSupportedCommands, HTTP_AMMOUNT_OF_SUPPPORTED_COMMANDS);
    
    		//Set the protocol type to PT_LABORER, make room for the MyHTTPstruct structure in the ListenSession and ClientSession and pass the supported API version.
    		if(!SetProtocolInformation(
    			psess, 
    			PT_LABORER | PT_SUPPORT_PSIGN,
    			(ProtocolSignature*) tempProtocolSignatureStructure,
    			sizeof(MyHTTPstruct),
    			V_TV_SERVER_1)
    		)
    			return false;
    
    		//Create a ControlPanelOptions strcuture with room for 1 suboption.
    		cpo = (ControlPanelOptions*) malloc(
    			sizeof(ControlPanelOptions) + 
    			sizeof(ControlPanelOption)*HTTP_AMMOUNT_OF_SUB_OPTIONS // +1 subOption
    		);
    
    		/*Empty memory and fill in the size, in bytes*/
    		memset(cpo, 0, sizeof(ControlPanelOptions) + sizeof(ControlPanelOption)*HTTP_AMMOUNT_OF_SUB_OPTIONS);
    		cpo->size = sizeof(ControlPanelOptions) + sizeof(ControlPanelOption)*HTTP_AMMOUNT_OF_SUB_OPTIONS;
    
    		//The name of this protocol, communicated to the user, will be "HTTP-plugin"
    		cpo->main.size = sizeof(ControlPanelOption);
    		cpo->main.optionName  = "HTTP-C-plugin"; //the name of this protocol
    
    		//suboption number 1
    		cpo->subOptions[0].size = sizeof(ControlPanelOption);
    		cpo->subOptions[0].name = "opt1"; //identifier name used by the function GetPluginData and SavePluginData
    		cpo->subOptions[0].optionName = "Server-path"; //label of this option
    		cpo->subOptions[0].userValue = (UserValueOption*) malloc(sizeof(UserValueOption));
    		cpo->subOptions[0].userValue->type = TD_ASCII_STRING; //the pointer on defaultValue is a ascii string.
    		cpo->subOptions[0].userValue->defaultValue = "c:\\WWWroot\\"; //default value of this option
    		cpo->subOptions[0].userValue->defaultValueSize = strlen((char*) cpo->subOptions[0].userValue->defaultValue); 
    		cpo->subOptions[0].flags = CPO_GEN_LISTENSESSION_OPTION; //a valid option for the listensession
    
    		SetControlPanelOptions(psess, cpo);
    
    		retv = AcceptProtocol(psess); //retv=false the protocol is rejected, retv=true the protocol is loaded
    
    		free(cpo->subOptions[0].userValue);
    		free(cpo);
    
    	} else if(!strcmp(psess->protocolName, "C_TCPIP")) { //init the TCP/IP protocol
    		tcpip_psess = psess;
    
    		if(!SetProtocolInformation(
    			psess, //ProtocolSession
    			PT_RECEIVER, //Set the type to receiver protocol
    			0, //No Protcol signature for for a PT_RECEIVER protocol
    			sizeof(MyTCPIPstruct), //In every ListenSession and ClientSession I want enough room in the data member for my structure
    			V_TV_SERVER_1) //This protocol supports API version 1
    		)
    			return false;
    
    		//Create a ControlPanelOptions strcuture with room for 1 suboption.
    		cpo = (ControlPanelOptions*) malloc(
    			sizeof(ControlPanelOptions) + 
    			sizeof(ControlPanelOption)*TCPIP_AMMOUNT_OF_SUB_OPTIONS // +2 subOption
    		);
    
    		/*Empty memory and fill in the size, in bytes*/
    		memset(cpo, 0, sizeof(ControlPanelOptions) + sizeof(ControlPanelOption)*TCPIP_AMMOUNT_OF_SUB_OPTIONS);
    		cpo->size = sizeof(ControlPanelOptions) + sizeof(ControlPanelOption)*TCPIP_AMMOUNT_OF_SUB_OPTIONS;
    
    		//The name of this protocol, communicated to the user, will be "HTTP-plugin"
    		cpo->main.size = sizeof(ControlPanelOption);
    		cpo->main.optionName  = "TCP/IP-C-plugin"; //the name of this protocol
    
    		//suboption number 1
    		cpo->subOptions[0].size = sizeof(ControlPanelOption);
    		cpo->subOptions[0].name = (char*) OPT_TCP_PORT; //identifier integer, instead of a name used by the function GetPluginData and SavePluginData
    		cpo->subOptions[0].optionName = "Port"; //label of this option
    		cpo->subOptions[0].userValue = (UserValueOption*) malloc(sizeof(UserValueOption));
    		cpo->subOptions[0].userValue->type = TD_SHORT_INT; //the defaultValue is an integer
    		cpo->subOptions[0].userValue->defaultValue = (void*) 80; //default value of this option
    		cpo->subOptions[0].userValue->defaultValueSize = 0; 
    		cpo->subOptions[0].flags = CPO_GEN_LISTENSESSION_OPTION | GDPD_NAME_IS_INTEGER | CPO_GEN_LISTENSESSION_READONLY; //a valid option for the listensession, member name is an integer and cannot be modified on a running service
    
    		//suboption number 2
    		cpo->subOptions[1].size = sizeof(ControlPanelOption);
    		cpo->subOptions[1].name = (char*) OPT_TCP_VERSION6; //identifier integer, instead of a name used by the function GetPluginData and SavePluginData
    		cpo->subOptions[1].optionName = "Use version6"; //label of this option
    		cpo->subOptions[1].userValue = (UserValueOption*) malloc(sizeof(UserValueOption));
    		cpo->subOptions[1].userValue->type = TD_BOOLEAN; //the defaultValue is an boolean
    		cpo->subOptions[1].userValue->defaultValue = (void*) 0; //default value of this option is false
    		cpo->subOptions[1].userValue->defaultValueSize = 0; 
    		cpo->subOptions[0].flags = CPO_GEN_LISTENSESSION_OPTION | GDPD_NAME_IS_INTEGER | CPO_GEN_LISTENSESSION_READONLY; //a valid option for the listensession, member name is an integer and cannot be modified on a running service
    
    		SetControlPanelOptions(psess, cpo);
    
    		//Startup the Socket stack
    		if(WSAStartup(wVersionRequested, &wsaData))
    			return 0;
    
    		//We will not make a call to SetControlPanelOptions and immediately call AcceptProtocol
    		retv = AcceptProtocol(psess); //retv=false the protocol is rejected, retv=true the protocol is loaded
    
    		free(cpo->subOptions[0].userValue);
    		free(cpo);
    	}
    
    	//Free the ProtocolSignatureStructure if allocated
    	if(tempProtocolSignatureStructure)
    		free(tempProtocolSignatureStructure); 
    
    	return retv;
    }
    
    char* createProtocolSignatureFromArray(char* p_array[], int ammountItems) {
    	int bufSize, i, tmpLen;
    	char* tmpBuf, *retBuf;
    
    	//Calculate the size of every integer that will contain the size of the command (that last one is zero)
    	bufSize = (ammountItems + 1) * sizeof(int);
    
    	//Calculate the size of the buf members for the ProtocolSignature structure
    	for(i=0; i<ammountItems; i++) {
    		bufSize += strlen(p_array[i]);
    	}
    
    	//Allocate size for the ProtocolSignature structure
    	retBuf = (char*) malloc(bufSize);
    
    	tmpBuf = retBuf;
    	//Copy every item with there size to the array
    	for(i=0; i<ammountItems; i++) {
    		tmpLen = strlen(p_array[i]);
    		*(int*)tmpBuf = tmpLen;
    		tmpBuf += sizeof(int);
    		strcpy(tmpBuf, p_array[i]);
    		tmpBuf += tmpLen;
    	}
    
    	*(int*)tmpBuf = 0;
    
    	return retBuf;
    }