/*

		Local loopback functions
		
*/

#include "netfone.h"

//	LOOP_FLUSH  --  Flush any queued loopback packets

void loop_flush(LPCLIENT_DATA d)
{
	while (d->llhead != NULL) {
		LPSTR b = (LPSTR) d->llhead;
		
		d->llhead = d->llhead->llnext;
		GlobalFreePtr(b); 
	}
	d->llhead = d->lltail = NULL;
	d->localLoopback &= ~LOOPBACK_PLAYING;
}

//	LOOP_SENDTO  --  Place a packet in the loopback queue

int loop_sendto(LPCLIENT_DATA d, const char *buf, int len,
				const struct sockaddr *to, int tolen)
{
	struct localLoop *p = GlobalAllocPtr(GPTR,
								sizeof(struct localLoop) + len);
	
	if (p == NULL) {
		WSASetLastError(WSAENOBUFS);
		return SOCKET_ERROR;
	}
	p->llnext = NULL;
	p->lllen = len;
	p->llsamples = currentInputSamples;
	memcpy(&p->lladdr, to, len);
	memcpy(p->llpacket, buf, len);
	if (d->llhead == NULL) {
		d->llhead = d->lltail = p;
	} else {
		d->lltail->llnext = p;
		d->lltail = p;
	}
	return len;
}

//	LOOP_RECVFROM  --  Receive a loop-back packet

int loop_recvfrom(LPCLIENT_DATA d, char *buf, int len,
                   struct sockaddr *from, int *fromlen)
{
	struct localLoop *p = d->llhead;
	int pktlen;	

	if (p == NULL) {
		WSASetLastError(WSAEWOULDBLOCK);
		return SOCKET_ERROR;
	}
	d->llhead = p->llnext;
	pktlen = p->lllen;
	if (*fromlen < sizeof p->lladdr) {
		WSASetLastError(WSAEFAULT);
		GlobalFreePtr(p);
		return SOCKET_ERROR;
	}
	if (p->lllen > len) {
		WSASetLastError(WSAEWOULDBLOCK);
		GlobalFreePtr(p);
		return SOCKET_ERROR;
	} 
	memcpy(from, &p->lladdr, sizeof p->lladdr);
	*fromlen = sizeof p->lladdr;
	memcpy(buf, p->llpacket, p->lllen);
	GlobalFreePtr(p);

	return pktlen;
}

/*	LOOP_SAMPLES  --  Return number of samples in next loopback
					  packet.  If none is queued, return zero.  */
					  
int loop_samples(LPCLIENT_DATA d)
{
	struct localLoop *p = d->llhead;	

	return (p == NULL) ? 0 : p->llsamples;
}

/*  LOOP_CONTROL_PORT  --  Returns TRUE if a loopback packet is
						   queued and it is destined for the control
						   port.  */
						   
BOOL loop_control_port(LPCLIENT_DATA d)
{
	struct localLoop *p = d->llhead;	

	return (p == NULL) ? 0 : (ntohs(p->lladdr.sin_port) & 1);
}						   					  

