/* -*- c -*-
*
* ----------------------------------------------------------------------
* CcXstream Client Library for XBOX Media Player (Server Discovery)
* ----------------------------------------------------------------------
*
* Copyright (c) 2002-2003 by PuhPuh
*
* This code is copyrighted property of the author. It can still
* be used for any non-commercial purpose following conditions:
*
* 1) This copyright notice is not removed.
* 2) Source code follows any distribution of the software
* if possible.
* 3) Copyright notice above is found in the documentation
* of the distributed software.
*
* Any express or implied warranties are disclaimed. Author is
* not liable for any direct or indirect damages caused by the use
* of this software.
*
* ----------------------------------------------------------------------
*
*/
#include "ccincludes.h"
#include "ccbuffer.h"
#include "ccxclient.h"
#include "ccxencode.h"
static unsigned long timeout_start(void);
static int timeout_exceeded(unsigned long start_time);
static unsigned long timeout_start()
{
#if defined (__linux__) || defined (__NetBSD__) || defined (__FreeBSD__) || defined (__CYGWIN__) || defined (sun)
struct timeval tv;
unsigned long r;
gettimeofday(&tv, NULL);
r = (((unsigned long)tv.tv_sec) % 200000000U) * 10U;
r += ((unsigned long)tv.tv_usec) / 100000U;
return r;
#elif defined (_XBOX)
return ((unsigned long)(GetTickCount()) / 100U);
#else
time_t t;
t = time(NULL);
return (((unsigned long)t) % 200000000U) * 10U;
#endif
}
static int timeout_exceeded(unsigned long start_time)
{
unsigned long t;
t = timeout_start();
return ((t < start_time) || ((start_time + 9) < t));
}
CcXstreamClientError ccx_client_discover_servers(CcXstreamServerDiscoveryCB callback, void *context)
{
struct sockaddr_in sa, ra;
#if defined (_XBOX) || defined (WIN32)
size_t sa_len, ra_len;
#else
socklen_t sa_len, ra_len;
#endif
unsigned long handle, p_len, p_handle;
unsigned char *packet, ch;
size_t packet_len;
int found = 0, l, c;
#if defined (_XBOX) || defined (WIN32)
SOCKET sock;
#else
int sock;
#endif
unsigned long t0;
fd_set rs;
struct timeval tv;
CcBufferRec buf[1], seen_buf[1];
char *p_address, *p_port, *p_version, *p_comment;
memset(&sa, 0, sizeof (sa));
sa.sin_family = AF_INET;
sa.sin_addr.s_addr = htonl(INADDR_BROADCAST);
sa.sin_port = htons(CC_XSTREAM_DEFAULT_PORT);
sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (sock < 0)
return CC_XSTREAM_CLIENT_COMMAND_FAILED;
c = 1;
setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char *)(&c), sizeof (c));
handle = cc_xstream_client_mkpacket_server_discovery(&packet, &packet_len);
sa_len = sizeof (sa);
CC_DEBUG(6, ("Sending a discovery datagram."));
sendto(sock, packet, packet_len, 0, (struct sockaddr *)(&sa), sa_len);
t0 = timeout_start();
cc_buffer_init(seen_buf);
while (1)
{
if (timeout_exceeded(t0))
{
cc_buffer_uninit(seen_buf);
break;
}
FD_ZERO(&rs);
FD_SET(sock, &rs);
tv.tv_sec = 0;
tv.tv_usec = 350000;
switch (select(sock + 1, &rs, NULL, NULL, &tv))
{
case -1:
CC_DEBUG(5, ("Select call fails."));
#if defined (_XBOX) || defined (WIN32)
closesocket(sock);
#else
close(sock);
#endif
cc_buffer_uninit(seen_buf);
cc_xfree(packet);
return (found > 0) ? CC_XSTREAM_CLIENT_OK : CC_XSTREAM_CLIENT_COMMAND_FAILED;
/*NOTREACHED*/
case 0:
/* Resend packet if we got timeout. */
CC_DEBUG(6, ("Resending the discovery datagram."));
sendto(sock, packet, packet_len, 0, (struct sockaddr *)(&sa), sa_len);
break;
default:
memset(&ra, 0, sizeof (ra));
cc_buffer_init(buf);
cc_buffer_append_space(buf, 2000);
ra_len = sizeof (ra);
l = recvfrom(sock, cc_buffer_ptr(buf), cc_buffer_len(buf), 0, (struct sockaddr *)(&ra), &ra_len);
if (l > 0)
{
cc_buffer_consume_end(buf, cc_buffer_len(buf) - l);
if (cc_xstream_buffer_decode_int(buf, &p_len) &&
(p_len == cc_buffer_len(buf)) &&
cc_xstream_buffer_decode_byte(buf, &ch) &&
((CcXstreamPacket)ch == CC_XSTREAM_XBMSP_PACKET_SERVER_DISCOVERY_REPLY) &&
cc_xstream_buffer_decode_int(buf, &p_handle) &&
(p_handle == handle) &&
cc_xstream_buffer_decode_string(buf, (unsigned char **)(&p_address), NULL) &&
cc_xstream_buffer_decode_string(buf, (unsigned char **)(&p_port), NULL) &&
cc_xstream_buffer_decode_string(buf, (unsigned char **)(&p_version), NULL) &&
cc_xstream_buffer_decode_string(buf, (unsigned char **)(&p_comment), NULL) &&
(cc_buffer_len(buf) == 0))
{
if (strlen(p_address) == 0)
{
cc_xfree(p_address);
#ifdef _XBOX
{
unsigned char *b;
b = (unsigned char *)(&(ra.sin_addr.s_addr));
p_address = cc_xmalloc(32);
sprintf(p_address, "%d.%d.%d.%d", (int)(b[0]), (int)(b[1]), (int)(b[2]), (int)(b[3]));
}
#else
p_address = cc_xstrdup(inet_ntoa(ra.sin_addr));
#endif
}
if (strlen(p_port) == 0)
{
cc_xfree(p_port);
p_port = cc_xmalloc(16);
#ifdef _XBOX
sprintf(p_port, "%d", (int)(ntohs(ra.sin_port)));
#else
snprintf(p_port, 16, "%d", (int)(ntohs(ra.sin_port)));
#endif
}
cc_buffer_append_string(buf, ">");
cc_buffer_append_string(buf, p_address);
cc_buffer_append_string(buf, ":");
cc_buffer_append_string(buf, p_port);
cc_buffer_append_string(buf, "<");
ch = 0;
/* Terminate both buffers with '\0' */
cc_buffer_append(buf, &ch, 1);
cc_buffer_append(seen_buf, &ch, 1);
if (strstr((char *)cc_buffer_ptr(seen_buf), (char *)cc_buffer_ptr(buf)) == NULL)
{
/* Don't forget to remove the terminating '\0' */
cc_buffer_consume_end(seen_buf, 1);
cc_buffer_append_string(seen_buf, (char *)cc_buffer_ptr(buf));
CC_DEBUG(6, ("New server %s", (char *)cc_buffer_ptr(buf)));
if (callback != NULL)
(*callback)(p_address, p_port, p_version, p_comment, context);
found++;
}
else
{
/* Don't forget to remove the terminating '\0' */
cc_buffer_consume_end(seen_buf, 1);
CC_DEBUG(6, ("Duplicate %s", (char *)cc_buffer_ptr(buf)));
}
cc_buffer_clear(buf);
cc_xfree(p_address);
cc_xfree(p_port);
cc_xfree(p_version);
cc_xfree(p_comment);
}
}
cc_buffer_uninit(buf);
break;
}
}
#if defined (_XBOX) || defined (WIN32)
closesocket(sock);
#else
close(sock);
#endif
cc_xfree(packet);
return (found > 0) ? CC_XSTREAM_CLIENT_OK : CC_XSTREAM_CLIENT_SERVER_NOT_FOUND;
}
/* eof (ccxdiscover.c) */
syntax highlighted by Code2HTML, v. 0.9.1