www.pudn.com > kRtspProxyd.zip > proxy.c


/*  
  *  
  *  kRtspProxyd 
  *  
  *  Many basic functions for rtsp parsing 
  * 
  */ 
 
#include  
#include  
#include  
#include  
#include "proxy.h" 
#include "prototypes.h" 
 
#define MAX_SOCK_ADDR 128 
int	gUserLimit = 20; 
atomic_t	gNumUsers = ATOMIC_INIT(0); 
shok	*gShokList = NULL; 
 
static int gUDPPortMin = 2000; 
static int gUDPPortMax = 65536; 
atomic_t gNextPort = ATOMIC_INIT(-1); 
atomic_t gMaxPorts = ATOMIC_INIT(0); 
unsigned int gProxyIP; //sefIP 
 
 
t_cmd_map cmd_map[] = { 
	{"DESCRIBE",	ttDescribe}, 
	{"SETUP",	ttSetup},	 
	{"PLAY",	ttPlay}, 
	{"PAUSE",	ttPause}, 
	{"STOP",	ttStop}, 
	{"TEARDOWN",	ttTeardown}, 
	{"OPTIONS",     ttOptions}, 
	{"ANNOUNCE",    ttAnnounce}, 
	{"REDIRECT", 	ttRedirect}, 
	{"GET_PARAMETER", ttGetParameter}, 
	{"SET_PARAMETER", ttSetParameter}, 
	{NULL,		ttNone} 
}; 
 
char *str_sep(char **stringp, char *delim) 
{ 
	int j, dl, i, sl; 
	char *newstring, *ret; 
 
	if (*stringp == NULL) 
		return NULL; 
 
	dl = strlen(delim); 
	sl = strlen(*stringp); 
	newstring = NULL; 
	ret = *stringp; 
 
	for (i=0; i= 'A' && c <= 'Z') 
		return ((c - 'A') + 'a'); 
	return c; 
} 
 
 
int strn_casecmp(char *str1, char *str2, int l) 
{ 
	int	ret; 
	 
	ret = to_lower(*str1) - to_lower(*str2); 
	while (l-- && to_lower(*str1) && to_lower(*str2) && ((ret = to_lower(*str1++) - to_lower(*str2++)) == 0)) 
		; 
	return ret; 
} 
 
int is_command(char *inp, char *cmd, char *server) 
{ 
	int 	l; 
	char	*p; 
 
	l = strlen(inp); 
 
	if (l < 17)		/* "RTSP/1.0" (8) + " rtsp:// " (9) */ 
		return 0; 
	if (strn_casecmp(&inp[l-8], "RTSP/1.0", 8) != 0) 
		return 0; 
 
	p = inp; 
	while (*p && (*p != ' ')) 
		*cmd++ = *p++; 
	*cmd = '\0'; 
 
	if (strn_casecmp(p, " rtsp://", 8) != 0) 
		return 0; 
 
	p += 8; 
	while (*p && (*p != '/')) 
		*server++ = *p++; 
	*server = '\0'; 
 
	return 1; 
} 
 
/**********************************************/ 
int has_two_crlfs(char *s) 
{ 
	int		l, n; 
	char	*p; 
	l = strlen(s); 
	if (l < 4) 
		return 0; 
	n = 3; 
	p = s + n; 
	while (n < l) { 
		if (s[n] != '\n') 
			n += 1; 
		else if (s[n-1] != '\r' || s[n-2] != '\n' || s[n-3] != '\r') 
			n += 2; 
		else 
			return n+1; 
	} 
	return 0; 
} 
 
 
void send_rtsp_error(struct socket *sock, int refusal) 
{  
 
       char *refusal_string; 
 
       EnterFunction("send_rtsp_error"); 
        
	switch (refusal) { 
		case kServerNotFound: 
 			refusal_string = "RTSP/1.0 462 Destination unreachable\r\n"; 
			break; 
		case kUnknownError: 
 			refusal_string = "RTSP/1.0 500 Unknown proxy error\r\n"; 
			break; 
		case kPermissionDenied: 
 			refusal_string = "RTSP/1.0 403 Proxy denied\r\n"; 
			break; 
		case kTooManyUsers: 
 			refusal_string = "RTSP/1.0 503 Too many proxy users\r\n"; 
			break; 
		default: 
 			refusal_string = "RTSP/1.0 500 Unknown proxy error\r\n"; 
			break; 
	} 
 
	(void)SendBuffer(sock, refusal_string, strlen(refusal_string)); 
	LeaveFunction("send_rtsp_error"); 
} 
 
int str_casecmp(char *str1, char *str2) 
{ 
	int	ret; 
	 
	ret = *str1 - *str2; 
	while (*str1 && *str2 && ((ret = *str1++ - *str2++) == 0)) 
		; 
	return ret; 
} 
 
int cmd_to_transaction_type(char *cmd) 
{ 
	t_cmd_map	*map; 
	map = cmd_map; 
	while (map->cmd != NULL) { 
		if (str_casecmp(map->cmd, cmd) == 0) 
			return map->type; 
		map++; 
	} 
	return ttNone; 
} 
 
/**********************************************/ 
int has_trackID(char *inp, int *trackID) 
{ 
	int 	l; 
	char	*p; 
	l = strlen(inp); 
 
	if (l < 18)		/* "RTSP/1.0" (8) + "trackID=n " (10) */ 
		return 0; 
	if (strn_casecmp(inp + l - 8, "RTSP/1.0", 8) != 0) 
		return 0; 
 
	p = inp; 
	while (p) { 
		p = strchr(p, '='); 
		if (p - 7 < inp) { 
			p++; 
			continue; 
		} 
		if (strn_casecmp(p - 7, "trackid=", 8) != 0) { 
			p++; 
			continue; 
		} 
		*trackID = atoi(p + 1); 
		return 1; 
	} 
	return 0; 
} 
 
 
int track_id_to_idx(rtsp_session *s, int id) 
{ 
	int i; 
	for (i=0; inumTracks; i++) { 
		if (s->trk[i].ID == id) 
			return i; 
	} 
	return -1; 
} 
 
/**********************************************/ 
int has_client_port(char *inp, unsigned short *port) 
{ 
	int		l; 
	char	*p; 
	l = strlen(inp); 
 
	if (l < 23)		/* "Transport:<>client_port=n" (23) */ 
		return 0; 
	if (strn_casecmp(inp, "transport", 9) != 0) 
		return 0; 
	 
	p = inp; 
	while (p) { 
		p = strchr(p, '='); 
		if (p - 11 < inp) { 
			p++; 
			continue; 
		} 
		if (strn_casecmp(p - 11, "client_port=", 12) != 0) { 
			p++; 
			continue; 
		} 
		*port = atoi(p + 1); 
		*++p = '\0'; 
		return 1; 
	} 
	return 0; 
} 
 
 
ipList *find_ip_in_list(ipList *list, unsigned int ip) 
{ 
	ipList *cur = list; 
 
      EnterFunction("find_ip_in_list"); 
 
	while (cur) { 
	 
		if (cur->ip == ip) { 
			return cur; 
		} 
		cur = cur->next; 
	} 
      LeaveFunction("find_ip_in_list"); 
      return NULL; 
} 
 
shok *find_available_shok(unsigned int fromIP, unsigned int toIP, int withSib, const int CPUNR) 
{	 
	shok	*cur = threadinfo[CPUNR].gShokQueue; 
 
	while (cur) { 
		KRTSPROXYD_OUT(KERN_INFO " looking for IP %xin shok\n", toIP); 
		if (find_ip_in_list(cur->ips, toIP) == NULL) { 
			if (withSib) { 
				KRTSPROXYD_OUT(KERN_INFO "looking for IP %x in SIB shok\n", toIP); 
				if (find_ip_in_list(cur->sib->ips, toIP) == NULL) 
					return cur; 
			} 
			else 
				return cur; 
		} 
		cur = cur->next; 
	} 
 
	return NULL; 
} 
 
int add_ip_to_list(ipList **list, unsigned int ip) 
{ 
	ipList	*newEl; 
 
	newEl = (ipList*)kmalloc(sizeof(ipList), GFP_KERNEL); 
	if (!newEl) 
		return 0; 
	newEl->ip = ip; 
	newEl->what_to_do = NULL; 
	newEl->what_to_do_it_with = NULL; 
	newEl->next = *list; 
	*list = newEl; 
 
	return 1; 
} 
 
 struct socket *new_socket_tcp(void) 
{ 
	struct socket *sock; 
	int err; 
	 
       err = sock_create(PF_INET, SOCK_STREAM, IPPROTO_TCP, &sock); 
      	 
	if (err<0)  
       { 
	     KRTSPROXYD_OUT(KERN_ERR "Error during creation of tcp socket; terminating\n"); 
	     sock_release(sock); 
	     return NULL; 
	}     
	atomic_inc(&gMaxPorts); 
	return sock; 
} 
 
void set_socket_reuse_address(struct socket *skt) 
{ 
	int i = 1; 
	skt->sk->prot->setsockopt(skt->sk, SOL_SOCKET, SO_REUSEADDR, (char*)&i, sizeof(i)); 
} 
 
/**********************************************/ 
static struct socket *new_socket_udp(void) 
{ 
	struct socket *sock = NULL; 
	int err; 
	 
       err = sock_create(PF_INET, SOCK_DGRAM, IPPROTO_UDP, &sock); 
	if (err<0)  
       { 
	     KRTSPROXYD_OUT(KERN_ERR "Error during creation of udp socket; terminating\n"); 
	     sock_release(sock); 
	     return NULL; 
	}     
	atomic_inc(&gMaxPorts); 
	return sock; 
} 
 
int bind_socket_to_address(struct socket *skt, unsigned int address, unsigned short port, int is_listener) 
{ 
	struct sockaddr_in sin; 
	int err; 
 
	if (address == (unsigned int)0xFFFFFFF) 
		address = INADDR_ANY; 
		 
	memset(&sin, 0, sizeof(sin)); 
	sin.sin_family = AF_INET; 
	sin.sin_port = htons(port); 
	sin.sin_addr.s_addr = address; //already is network byte order! 
 
	err = skt->ops->bind(skt,(struct sockaddr*)&sin,sizeof(sin)); 
	if (err < 0) 
	{ 
		KRTSPROXYD_OUT(KERN_ERR "kRtspProxyd: Error binding socket. This means that some other \n"); 
		KRTSPROXYD_OUT(KERN_ERR "        daemon is (or was a short time ago) using port %i.\n",port); 
		return 0;	 
	} 
 
	/* Grrr... setsockopt() does this. */ 
//	skt->sk->reuse   = 1; //success!! 
       return 1; 
} 
 
//fromIp and toIp are all NBO 
shok *make_new_shok(unsigned int fromIP, unsigned int toIP, int withSib, const int CPUNR) 
{ 
	shok *theShok1 = NULL, *theShok2 = NULL; 
	struct socket *skt1 = NULL, *skt2 = NULL; 
	unsigned short port1 = (unsigned short)0xFFFF, port2 = (unsigned short)0xFFFF; 
 
	theShok1 = (shok*)kmalloc(sizeof(shok), GFP_KERNEL); 
	if (!theShok1) 
		goto bail_error; 
	if (withSib) { 
		theShok2 = (shok*)kmalloc(sizeof(shok), GFP_KERNEL); 
		if (!theShok2) 
			goto bail_error; 
	} 
 
	if (atomic_read(&gNextPort) == -1) 
		atomic_set(&gNextPort, gUDPPortMin); 
 
retry: 
 
	if ((skt1 = new_socket_udp()) == NULL) 
		goto bail_error; 
 
       	if ((atomic_read(&gNextPort) & 0x1) && withSib) //odd number 
			atomic_inc(&gNextPort); 
		if (atomic_read(&gNextPort) > gUDPPortMax) 
          		atomic_set(&gNextPort, gUDPPortMin); 
 while (bind_socket_to_address(skt1, fromIP, port1 = atomic_read(&gNextPort), 0) != 1) 
 	{ 
 	    atomic_inc(&gNextPort); 
 	    if ((atomic_read(&gNextPort) & 0x1) && withSib) //odd number 
			atomic_inc(&gNextPort); 
		if (atomic_read(&gNextPort) > gUDPPortMax) 
          		atomic_set(&gNextPort, gUDPPortMin); 
 	} 
 atomic_inc(&gNextPort); 
 
 if (withSib) { 
       	if ((skt2 = new_socket_udp()) == NULL) 
			goto bail_error; 
 
		if (bind_socket_to_address(skt2, fromIP, port2 = atomic_read(&gNextPort), 0) != 1) { 
			sock_release(skt1); 
			sock_release(skt2); 
			skt1 = NULL; 
			skt2 = NULL; 
			atomic_inc(&gNextPort); 
			goto retry; 
		} 
		else atomic_inc(&gNextPort); 
	} 
 
       make_socket_nonblocking(skt1); 
	theShok1->socket = skt1; 
	theShok1->port = port1; 
	theShok1->ips = NULL; 
 
	if (withSib) { 
              make_socket_nonblocking(skt2); 
 
		theShok2->socket = skt2; 
		theShok2->port = port2; 
		theShok2->ips = NULL; 
		theShok2->sib = theShok1; 
 
		theShok1->sib = theShok2; 
		theShok1->next = theShok2; 
		theShok2->next = threadinfo[CPUNR].gShokQueue; 
	} 
	else { 
		theShok1->sib = NULL; 
		theShok1->next = threadinfo[CPUNR].gShokQueue; 
	} 
 
	add_ips_to_shok(theShok1, fromIP, toIP, withSib); 
	threadinfo[CPUNR].gShokQueue = theShok1; 
 
	return theShok1;	 
 
bail_error: 
	sock_release(skt1); 
	sock_release(skt2); 
	if (theShok1 != NULL) 
		kfree(theShok1); 
	if (theShok2 != NULL) 
		kfree(theShok2); 
	return NULL; 
} 
 
/**********************************************/ 
int add_ips_to_shok(shok *theShok, unsigned int fromIP, unsigned int toIP, int withSib) 
{ 
	add_ip_to_list(&(theShok->ips), toIP); 
	if (withSib) 
		add_ip_to_list(&(theShok->sib->ips), toIP); 
	return 1; 
} 
 
/**********************************************/ 
int make_udp_port_pair(unsigned int fromIP, unsigned int toIP, shok **rtpSocket, shok **rtcpSocket, const int CPUNR) 
{ 
	shok	*theShok; 
 
	KRTSPROXYD_OUT(KERN_INFO "MAKE_UDP_PORT_PAIR from %x to %x\n", fromIP, toIP); 
 
	if ((theShok = find_available_shok(fromIP, toIP, 1, CPUNR)) != NULL) { 
		 
		add_ips_to_shok(theShok, fromIP, toIP, 1); 
	} 
	else { 
		theShok = make_new_shok(fromIP, toIP, 1, CPUNR); 
 
	} 
 
	if (theShok && theShok->sib) { 
		*rtpSocket = theShok; 
		*rtcpSocket = theShok->sib; 
		return 1; 
	} 
	else 
		return -1; 
} 
 
int has_content_length(char *inp, int *len) 
{ 
	int		l; 
	char	*p; 
	l = strlen(inp); 
 
	if (l < 16)		/* "Content-Length:n" (16) */ 
		return 0; 
	if (strn_casecmp(inp, "content-length", 14) != 0) 
		return 0; 
	p = strchr(inp, ':'); 
	p++; 
	while (*p && (*p == ' ')) 
		p++; 
	if (p) { 
		*len = atoi(p); 
		return 1; 
	} 
	else 
		return 0; 
} 
 
int has_sessionID(char *inp, char *sessionID) 
{ 
	int		l; 
	char	*p; 
	l = strlen(inp); 
 
	if (l < 9)		/* "Session:x" (9) */ 
		return 0; 
	if (strn_casecmp(inp, "session", 7) != 0) 
		return 0; 
	p = strchr(inp, ':'); 
	p++; 
	while (*p && (*p == ' ')) 
		p++; 
	if (p) { 
		strcpy(sessionID, p); 
		return 1; 
	} 
	else 
		return 0; 
} 
 
 
int upon_receipt_from(shok *theShok, int fromIP, do_routine doThis, void *withThis) 
{ 
	ipList	*listEl; 
	KRTSPROXYD_OUT(KERN_INFO "UPON_RECEIPT_FROM %x\n", fromIP); 
	listEl = find_ip_in_list(theShok->ips, fromIP); 
	if (!listEl) 
		return -1; 
	listEl->what_to_do = doThis; 
	listEl->what_to_do_it_with = withThis; 
	return 0; 
} 
 
/**********************************************/ 
int has_IN_IP(char *inp, char *str) 
{ 
	int		l; 
	char	*p; 
	l = strlen(inp); 
 
	if (l < 10)		/* "c=IN IP4 n" (10) */ 
		return 0; 
	if (strn_casecmp(inp, "c=IN IP4 ", 9) != 0) 
		return 0; 
	p = inp + 9; 
	while (*p && (*p == ' ')) 
		p++; 
 
	while (*p && ((*p >= '0' && *p <= '9') || *p == '.')) 
		*str++ = *p++; 
	*str = '\0'; 
	return 1; 
} 
 
char *source_eq_string(char *inp) 
{ 
	int		l; 
	char	*p; 
	l = strlen(inp); 
 
	if (l < 7)			/* source= */ 
		return NULL; 
	p = inp; 
	while (p) { 
		p = strchr(p, '='); 
		if (p - 6 < inp) { 
			p++; 
			continue; 
		} 
		if (strn_casecmp(&p[-6], "source=", 7) != 0) { 
			p++; 
			continue; 
		} 
		return &p[-6]; 
	} 
	return NULL; 
} 
 
int transfer_data(void *refCon, char *buf, int bufSize) 
{ 
	trans_pb	*tpb = (trans_pb*)refCon; 
	int			ret = 0; 
	int                  isRTCP = 0; 
       struct sockaddr_in sin; 
	if (!tpb) 
		return -1; 
	 
	sin.sin_family = AF_INET; 
	sin.sin_port = htons(tpb->send_to_port); 
	sin.sin_addr.s_addr = tpb->send_to_ip; 
 
	if (strstr(tpb->socketName,"RTCP")) 
	{	 
		isRTCP = 1; 
	} 
         
 
	ret = UdpSendBuffer(tpb->send_from->socket, buf, bufSize, O_NONBLOCK, (struct sockaddr *)&sin, sizeof(sin)); 
       KRTSPROXYD_OUT(KERN_INFO "Sent %d bytes to %s on port %d\n", ret, ntoa(tpb->send_to_ip), tpb->send_to_port); 
	return ret; 
} 
 
int has_ports(char *inp, unsigned int *client_port, unsigned int *server_port) 
{ 
	int		l, got_server = 0, got_client = 0; 
	char	*p; 
	l = strlen(inp); 
 
	if (l < 40)		/* "Transport:<>client_port=n-nserver_port=n-n" (40) */ 
		return 0; 
	if (strn_casecmp(inp, "transport", 9) != 0) 
		return 0; 
 
	p = inp; 
	while (p && !(got_client && got_server)) { 
		p = strchr(p, '='); 
		if (p - 11 < inp) { 
		} 
		else if (strn_casecmp(&p[-11], "client_port=", 12) == 0) { 
			got_client = 1; 
			*client_port = atoi(&p[1]); 
		} 
		else if (strn_casecmp(&p[-11], "server_port=", 12) == 0) { 
			got_server = 1; 
			*server_port = atoi(&p[1]); 
		} 
		p++; 
	} 
	if (got_client && got_server) 
		return 1; 
	else 
		return 0; 
} 
 
int connect_to_address(struct socket *skt, unsigned int address, unsigned port) 
{ 
	struct sockaddr_in sin; 
	memset(&sin, 0, sizeof(sin)); 
	sin.sin_family = AF_INET; 
	sin.sin_port = htons(port); //fixme? 
	sin.sin_addr.s_addr = address; //already network byte order!! 
        KRTSPROXYD_OUT(KERN_INFO "connect to server-addr:port %s, %d\n",ntoa(address),port); 
	return skt->ops->connect(skt, (struct sockaddr*)&sin, sizeof(sin), 0); 
} 
 
/* 
 *	Send a datagram to a given address. We move the address into kernel 
 *	space and check the user space data area is readable before invoking 
 *	the protocol. 
 */ 
 
int UdpSendBuffer(struct socket *sock, void * buff, size_t len, unsigned flags, 
			   struct sockaddr *addr, int addr_len) 
{ 
	int err = -1; 
	struct msghdr msg; 
	struct iovec iov; 
	mm_segment_t oldfs; 
	 
	if (!sock) 
		goto out; 
	iov.iov_base=buff; 
	iov.iov_len=len; 
	msg.msg_name=0; 
	msg.msg_iov=&iov; 
	msg.msg_iovlen=1; 
	msg.msg_control=NULL; 
	msg.msg_controllen=0; 
	msg.msg_namelen=0; 
	msg.msg_name=(void *)addr; 
	msg.msg_namelen=(__kernel_size_t)addr_len; 
        msg.msg_flags = MSG_DONTWAIT; 
 
	oldfs = get_fs(); set_fs(KERNEL_DS); 
       err = sock_sendmsg(sock, &msg, len); 
       set_fs(oldfs); 
 
out: 
	return err; 
} 
 
 
/**********************************************/ 
int remove_shok(shok *theShok, int withSib, const int CPUNR) 
{ 
	shok	*cur = NULL, *last; 
	//shok	*curSib = NULL; 
 
	cur = threadinfo[CPUNR].gShokQueue; 
	if (cur == theShok) { 
		threadinfo[CPUNR].gShokQueue = cur->next; 
		goto doSib; 
	} 
 
	last = cur; 
	cur = cur->next; 
	while (cur) { 
		if (cur == theShok) { 
			last->next = cur->next; 
			goto doSib; 
		} 
		last = cur; 
		cur = cur->next; 
	} 
	return 0; 
 
doSib: 
	if (cur->sib) 
		cur->sib->sib = NULL; 
	if (withSib && cur->sib) 
		remove_shok(cur->sib, 0, CPUNR); 
 
	{ 
		ipList *ipn, *ipl = cur->ips; 
		while (ipl) { 
			ipn = ipl->next; 
			kfree(ipn); 
			ipl = ipn; 
		} 
	} 
	sock_release(cur->socket); 
	kfree(cur); 
	return 1; 
} 
 
 
/**********************************************/ 
int remove_ip_from_list(ipList **list, int ip) 
{ 
	ipList	*last, *theEl = *list; 
 
	if (theEl->ip == ip) { //fix me!! nbo or hbo? 
		*list = theEl->next; 
		kfree(theEl); 
		return 1; 
	} 
 
	last = theEl; 
	theEl = theEl->next; 
	while (theEl) { 
		if (theEl->ip == ip) { 
			last->next = theEl->next; 
			kfree(theEl); 
			return 1; 
		} 
		last = theEl; 
		theEl = theEl->next; 
	} 
	return 0; 
} 
 
/**********************************************/ 
void remove_shok_ref(shok *theShok, unsigned int fromIP, unsigned int toIP, int withSib, const int CPUNR) 
{ 
	remove_ip_from_list(&(theShok->ips), toIP); 
	if (withSib) 
		remove_ip_from_list(&(theShok->sib->ips), toIP); 
	if (theShok->sib->ips == NULL) 
		remove_shok(theShok->sib, 0, CPUNR); 
	if (theShok->ips == NULL) 
		remove_shok(theShok, 0, CPUNR); 
} 
 
/* 
 *	Receive a frame from the socket and optionally record the address of the  
 *	sender. We verify the buffers are writable and if needed move the 
 *	sender address from kernel to user space. 
 */ 
 
int UdpReceiveBuffer(struct socket *sock, void * ubuf, size_t size, unsigned flags, struct sockaddr *addr, int *addr_len) 
{ 
	struct iovec iov; 
	struct msghdr msg; 
	char address[MAX_SOCK_ADDR]; 
	int err = -1; 
	mm_segment_t	oldfs; 
 
	if (!sock) 
		goto out; 
 
	msg.msg_control=NULL; 
	msg.msg_controllen=0; 
	msg.msg_iovlen=1; 
	msg.msg_iov=&iov; 
	iov.iov_len=(size_t)(size-1); 
	iov.iov_base=(void *)ubuf; 
	msg.msg_name= address; 
	msg.msg_namelen= MAX_SOCK_ADDR; 
	msg.msg_flags = 0;     
  
        oldfs = get_fs(); set_fs(KERNEL_DS); 
	err = sock_recvmsg(sock, &msg, size-1, MSG_DONTWAIT); 
	set_fs(oldfs); 
	if(err >= 0) 
         { 
          memcpy((void *)addr, (void *)address, *addr_len); 
          KRTSPROXYD_OUT(KERN_INFO "the FromIP is %s\n", ntoa(((struct sockaddr_in *)addr)->sin_addr.s_addr));  
          }   
out: 
	return err; 
} 
 
 
/**********************************************/ 
rtsp_session *new_session(void) 
{ 
	rtsp_session	*s; 
	int			  i; 
 
	s = (rtsp_session*)kmalloc(sizeof(rtsp_session), GFP_KERNEL); 
	if (s) { 
		s->next = NULL; 
		s->die = 0; //false 
         	s->client_skt = NULL; 
                s->new_session = 1; 
		s->client_ip = (unsigned int)0xFFFFFFFF; //255.255.255.255 invalid address 
		s->server_address = NULL; 
		s->server_skt = NULL; 
		s->server_ip = (unsigned int)0xFFFFFFFF; 
		s->server_port = 554; 
		s->server_skt_pending_connection = 0;//false 
		s->state = stRecvClientCommand; //initialize the status 
		s->transaction_type = ttNone; 
		s->sessionID = NULL; 
 
		s->cur_trk = 0; 
		for (i=0; itrk[i].ID = 0; 
			s->trk[i].ClientRTPPort = (unsigned short)0xFFFF; 
			s->trk[i].ServerRTPPort = (unsigned short)0xFFFF; 
			s->trk[i].RTP_S2P = NULL; 
			s->trk[i].RTCP_S2P = NULL; 
			s->trk[i].RTP_P2C = NULL; 
			s->trk[i].RTCP_P2C = NULL; 
			s->trk[i].RTP_S2C_tpb.status = NULL; 
			s->trk[i].RTP_S2C_tpb.send_from = NULL; 
			s->trk[i].RTP_S2C_tpb.send_to_ip = (unsigned int)0xFFFFFFFF; 
			s->trk[i].RTP_S2C_tpb.send_to_port = (unsigned short)0xFFFF; 
			s->trk[i].RTP_S2C_tpb.packetSendCount = 0; 
			s->trk[i].RTP_S2C_tpb.nextDropPacket = 0; 
			s->trk[i].RTP_S2C_tpb.droppedPacketCount = 0; 
 
			s->trk[i].RTCP_S2C_tpb.status = NULL; 
			s->trk[i].RTCP_S2C_tpb.send_from = NULL; 
			s->trk[i].RTCP_S2C_tpb.send_to_ip = (unsigned int)0xFFFFFFFF; 
			s->trk[i].RTCP_S2C_tpb.send_to_port = (unsigned short)0xFFFF; 
			s->trk[i].RTCP_S2C_tpb.packetSendCount = 0; 
			s->trk[i].RTCP_S2C_tpb.nextDropPacket = 0; 
			s->trk[i].RTCP_S2C_tpb.droppedPacketCount = 0; 
 
			s->trk[i].RTCP_C2S_tpb.status = NULL; 
			s->trk[i].RTCP_C2S_tpb.send_from = NULL; 
			s->trk[i].RTCP_C2S_tpb.send_to_ip = (unsigned int)0xFFFFFFFF; 
			s->trk[i].RTCP_C2S_tpb.send_to_port = (unsigned short)0xFFFF; 
			s->trk[i].RTCP_C2S_tpb.packetSendCount = 0; 
			s->trk[i].RTCP_C2S_tpb.nextDropPacket = 0; 
			s->trk[i].RTCP_C2S_tpb.droppedPacketCount = 0; 
 
		} 
		s->numTracks = 0; 
 
              //init buffers 
              s->cinbuf = (char*)get_free_page((int)GFP_KERNEL); 
		if (s->cinbuf == NULL)  
		{ 
			KRTSPROXYD_OUT(KERN_CRIT "kRtspProxyd: Not enough memory for basic needs\n"); 
			return NULL; 
		} 
              s->coutbuf = (char*)get_free_page((int)GFP_KERNEL); 
		if (s->coutbuf == NULL)  
		{ 
			KRTSPROXYD_OUT(KERN_CRIT "kRtspProxyd: Not enough memory for basic needs\n"); 
			free_page((unsigned long)s->cinbuf); 
			return NULL; 
		}  
		s->sinbuf = (char*)get_free_page((int)GFP_KERNEL); 
		if (s->sinbuf == NULL)  
		{ 
			KRTSPROXYD_OUT(KERN_CRIT "kRtspProxyd: Not enough memory for basic needs\n"); 
			free_page((unsigned long)s->cinbuf); 
			free_page((unsigned long)s->coutbuf); 
			return NULL; 
		}  
		s->soutbuf = (char*)get_free_page((int)GFP_KERNEL); 
		if (s->soutbuf == NULL)  
		{ 
			KRTSPROXYD_OUT(KERN_CRIT "kRtspProxyd: Not enough memory for basic needs\n"); 
			free_page((unsigned long)s->cinbuf); 
			free_page((unsigned long)s->coutbuf); 
                     free_page((unsigned long)s->sinbuf); 
			return NULL; 
		}		 
		 
		s->amtInClientInBuffer = 0; 
		s->amtInClientOutBuffer = 0; 
		s->amtInServerInBuffer = 0; 
		s->amtInServerOutBuffer = 0; 
		 
		s->totalContentLength = 0;	// headers + body 
		s->contentLength = 0;		// just body 
		s->haveParsedServerReplyHeaders = 0; 
 
	} 
 
	return s; 
}