summaryrefslogtreecommitdiff
path: root/Source/DirectFB/lib/voodoo/play.c
diff options
context:
space:
mode:
Diffstat (limited to 'Source/DirectFB/lib/voodoo/play.c')
-rwxr-xr-xSource/DirectFB/lib/voodoo/play.c935
1 files changed, 935 insertions, 0 deletions
diff --git a/Source/DirectFB/lib/voodoo/play.c b/Source/DirectFB/lib/voodoo/play.c
new file mode 100755
index 0000000..a262472
--- /dev/null
+++ b/Source/DirectFB/lib/voodoo/play.c
@@ -0,0 +1,935 @@
+/*
+ (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org)
+ (c) Copyright 2000-2004 Convergence (integrated media) GmbH
+
+ All rights reserved.
+
+ Written by Denis Oliver Kropp <dok@directfb.org>,
+ Andreas Hundt <andi@fischlustig.de>,
+ Sven Neumann <neo@directfb.org>,
+ Ville Syrjälä <syrjala@sci.fi> and
+ Claudio Ciccani <klan@users.sf.net>.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+#include <config.h>
+
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <sys/ioctl.h>
+#include <sys/poll.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/wait.h>
+
+#include <net/if.h>
+
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+
+#include <directfb_version.h>
+
+#include <direct/clock.h>
+#include <direct/debug.h>
+#include <direct/interface.h>
+#include <direct/list.h>
+#include <direct/mem.h>
+#include <direct/memcpy.h>
+#include <direct/messages.h>
+#include <direct/thread.h>
+#include <direct/util.h>
+
+#include <voodoo/conf.h>
+#include <voodoo/internal.h>
+#include <voodoo/message.h>
+#include <voodoo/play.h>
+#include <voodoo/play_internal.h>
+
+#ifdef MACOS
+#define min(a,b) ((a) < (b) ? (a) : (b))
+#define max(a,b) ((a) > (b) ? (a) : (b))
+#endif
+
+D_DEBUG_DOMAIN( Voodoo_Play, "Voodoo/Play", "Voodoo Play" );
+
+/**********************************************************************************************************************/
+
+typedef struct {
+ DirectLink link;
+
+ VoodooPlayVersion version;
+ VoodooPlayInfo info;
+
+ long long last_seen;
+ long long broadcast;
+
+ char addr[64];
+} PlayerNode;
+
+/**********************************************************************************************************************/
+
+static void player_send_info( VoodooPlayer *player,
+ const in_addr_t *in_addr,
+ bool discover );
+
+static void *player_main_loop( DirectThread *thread,
+ void *arg );
+
+/**********************************************************************************************************************/
+
+static const int one = 1;
+
+VoodooPlayVersion g_VoodooPlay_version;
+VoodooPlayInfo g_VoodooPlay_info;
+
+/**********************************************************************************************************************/
+
+static VoodooPlayer *g_VoodooPlayer;
+
+/**********************************************************************************************************************/
+
+/*
+ * FIXME
+ */
+static void
+generate_uuid( u8 *buf )
+{
+ int i;
+
+ srand( direct_clock_get_abs_micros() );
+
+ for (i=0; i<16; i++) {
+ buf[i] = rand();
+ }
+}
+
+/**********************************************************************************************************************/
+
+pthread_mutex_t gplayermut = PTHREAD_MUTEX_INITIALIZER;
+
+
+DirectResult createSocketForPlayer (int * retfd)
+{
+ int fd = -1;
+ *retfd = -1;
+ DirectResult ret;
+ struct sockaddr_in addr;
+ D_INFO("Voodoo/Player: Creating the Socket for player 0x%08x\n",(int) g_VoodooPlayer);
+ /* Create the player socket. */
+ fd = socket( PF_INET, SOCK_DGRAM, 0 );
+ if (fd < 0) {
+ ret = errno2result( errno );
+ D_PERROR( "Voodoo/Player: Could not create the socket via socket()!\n" );
+
+ return ret;
+ }
+
+ /* Allow reuse of local address. */
+ if (setsockopt( fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one) ) < 0)
+ D_PERROR( "Voodoo/Player: Could not set SO_REUSEADDR!\n" );
+
+ if (setsockopt( fd, SOL_SOCKET, SO_BROADCAST, &one, sizeof(one) ) < 0)
+ D_PERROR( "Voodoo/Player: Could not set SO_BROADCAST!\n" );
+
+ /* Bind the socket to the local port. */
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr = inet_addr( "0.0.0.0" );
+ addr.sin_port = htons( 2323 );
+
+ if (bind( fd, (struct sockaddr*) &addr, sizeof(addr) )) {
+ ret = errno2result( errno );
+ D_PERROR( "Voodoo/Player: Could not bind() the socket!\n" );
+ close( fd );
+
+ return ret;
+ }
+
+ *retfd = fd;
+ return DR_OK;
+
+
+}
+
+
+DirectResult
+voodoo_player_create( const VoodooPlayInfo *info,
+ VoodooPlayer **ret_player )
+{
+ DirectResult ret;
+ int fd;
+
+ VoodooPlayer *player;
+ pthread_mutex_lock(&gplayermut);
+ D_ASSERT( ret_player != NULL );
+
+ if (g_VoodooPlayer) {
+ *ret_player = g_VoodooPlayer;
+ pthread_mutex_unlock(&gplayermut);
+ return DR_OK;
+ }
+
+ ret = createSocketForPlayer(&fd);
+ if ( ret != DR_OK)
+ {
+ pthread_mutex_unlock(&gplayermut);
+ return ret;
+
+ }
+
+
+
+ /* Allocate player structure. */
+ player = D_CALLOC( 1, sizeof(VoodooPlayer) );
+ if (!player) {
+ D_WARN( "out of memory" );
+ close( fd );
+ pthread_mutex_unlock(&gplayermut);
+ return DR_NOLOCALMEMORY;
+ }
+
+ pthread_mutex_init( &player->lock, NULL );
+
+ /* Initialize player structure. */
+ player->fd = fd;
+
+ /* Fill version struct */
+ player->version.v[0] = VPVF_LITTLE_ENDIAN | VPVF_32BIT_SERIALS;
+ player->version.v[1] = DIRECTFB_MAJOR_VERSION;
+ player->version.v[2] = DIRECTFB_MINOR_VERSION;
+ player->version.v[3] = DIRECTFB_MICRO_VERSION;
+
+ /* Fill info struct */
+ direct_snputs( player->info.name, voodoo_config->play_info.name, VOODOO_PLAYER_NAME_LENGTH );
+ direct_snputs( player->info.vendor, voodoo_config->play_info.vendor, VOODOO_PLAYER_VENDOR_LENGTH );
+ direct_snputs( player->info.model, voodoo_config->play_info.model, VOODOO_PLAYER_MODEL_LENGTH );
+ direct_memcpy( player->info.uuid, voodoo_config->play_info.uuid, 16 );
+
+ if (info)
+ player->info = *info;
+
+ if (!player->info.name[0])
+ direct_snputs( player->info.name, "Unnamed Player", VOODOO_PLAYER_NAME_LENGTH );
+
+ if (!player->info.vendor[0])
+ direct_snputs( player->info.vendor, "Unknown Vendor", VOODOO_PLAYER_VENDOR_LENGTH );
+
+ if (!player->info.model[0])
+ direct_snputs( player->info.model, "Unknown Model", VOODOO_PLAYER_MODEL_LENGTH );
+
+ if (!player->info.uuid[0])
+ generate_uuid( player->info.uuid );
+
+ player->info.flags |= VPIF_LINK;
+
+ D_MAGIC_SET( player, VoodooPlayer );
+
+
+ g_VoodooPlay_version = player->version;
+ g_VoodooPlay_info = player->info;
+
+
+ char buf[33];
+
+ snprintf( buf, sizeof(buf), "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
+ player->info.uuid[0], player->info.uuid[1], player->info.uuid[2], player->info.uuid[3], player->info.uuid[4],
+ player->info.uuid[5], player->info.uuid[6], player->info.uuid[7], player->info.uuid[8], player->info.uuid[9],
+ player->info.uuid[10], player->info.uuid[11], player->info.uuid[12], player->info.uuid[13], player->info.uuid[14],
+ player->info.uuid[15] );
+
+ D_INFO( "Running player '%s' with UUID %s!\n", player->info.name, buf );
+
+ /* Start messaging thread */
+ player->thread = direct_thread_create( DTT_DEFAULT, player_main_loop, player, "Voodoo/Player" );
+
+ /* Return the new player. */
+ *ret_player = player;
+
+ if (!g_VoodooPlayer)
+ g_VoodooPlayer = player;
+
+ pthread_mutex_unlock(&gplayermut);
+ return DR_OK;
+}
+
+DirectResult
+voodoo_player_destroy( VoodooPlayer *player )
+{
+ pthread_mutex_lock(&gplayermut);
+ D_MAGIC_ASSERT( player, VoodooPlayer );
+
+ if (g_VoodooPlayer == player)
+ {
+ pthread_mutex_unlock(&gplayermut);
+ return DR_OK;
+ }
+ D_INFO("Voodoo/Player: Destroying the player 0x%08x\n",(int) player);
+ player->quit = true;
+
+ direct_thread_join( player->thread );
+ direct_thread_destroy( player->thread );
+
+ close( player->fd );
+
+ pthread_mutex_destroy( &player->lock );
+
+ D_MAGIC_CLEAR( player );
+
+ D_FREE( player );
+ g_VoodooPlayer = NULL;
+ pthread_mutex_unlock(&gplayermut);
+ return DR_OK;
+}
+
+DirectResult
+voodoo_player_broadcast( VoodooPlayer *player )
+{
+#if !VOODOO_PLAY_FAKE
+ int ret;
+#ifdef MACOS
+ char *ptr, lastname[IFNAMSIZ];
+#else
+ int i;
+#endif
+ struct ifreq req[16];
+ struct ifconf conf;
+
+ D_MAGIC_ASSERT( player, VoodooPlayer );
+
+ player->broadcast++;
+
+ conf.ifc_buf = (char*) req;
+ conf.ifc_len = sizeof(req);
+
+ ret = ioctl( player->fd, SIOCGIFCONF, &conf );
+ if (ret) {
+ D_PERROR( "Voodoo/Player: ioctl( SIOCGIFCONF ) failed!\n" );
+ return DR_FAILURE;
+ }
+
+#ifdef MACOS
+ // TIV: On iPhone (and I believe in general on BSD, you can't just plainly iterate on struct size)
+
+ lastname[0] = 0;
+
+ for (ptr = conf.ifc_buf; ptr < conf.ifc_buf + conf.ifc_len; )
+ {
+ char buf[100];
+ int len, flags;
+ struct ifreq ifrcopy, *ifr = (struct ifreq *)ptr;
+ struct sockaddr_in *addr = (struct sockaddr_in*) &ifr->ifr_broadaddr;
+
+ len = max(sizeof(struct sockaddr), ifr->ifr_addr.sa_len);
+ ptr += sizeof(ifr->ifr_name) + len; // for next one in buffer
+
+ if (strncmp(lastname, ifr->ifr_name, IFNAMSIZ) == 0)
+ {
+ continue; /* already processed this interface */
+ }
+
+ memcpy(lastname, ifr->ifr_name, IFNAMSIZ);
+
+ ifrcopy = *ifr;
+ ioctl( player->fd, SIOCGIFFLAGS, &ifrcopy);
+ flags = ifrcopy.ifr_flags;
+ if ((flags & IFF_UP) == 0)
+ {
+ D_INFO( "Voodoo/Player: %-16s is not up.\n", ifrcopy.ifr_name );
+ continue; // ignore if interface not up
+ }
+
+ ret = ioctl( player->fd, SIOCGIFBRDADDR, ifr );
+ if (ret) {
+ D_PERROR( "Voodoo/Player: ioctl( SIOCGIFBRDADDR ) %-16s failed!\n", ifr->ifr_name );
+ continue;
+ }
+
+ if (addr->sin_addr.s_addr) {
+ inet_ntop( AF_INET, &addr->sin_addr, buf, sizeof(buf) );
+
+ D_INFO( "Voodoo/Player: %-16s (%s)\n", ifr->ifr_name, buf );
+ }
+ else {
+ ret = ioctl( player->fd, SIOCGIFDSTADDR, ifr );
+ if (ret) {
+ D_PERROR( "Voodoo/Player: ioctl( SIOCGIFDSTADDR ) failed!\n" );
+ continue;
+ }
+
+ inet_ntop( AF_INET, &addr->sin_addr, buf, sizeof(buf) );
+
+ D_INFO( "Voodoo/Player: %-16s (%s) (P-t-P)\n", ifr->ifr_name, buf );
+ }
+
+ player_send_info( player, &addr->sin_addr.s_addr, true );
+ }
+#else
+ D_INFO( "Voodoo/Player: Detected %d interfaces\n", conf.ifc_len/sizeof(req[0]) );
+
+ for (i=0; i<conf.ifc_len/sizeof(req[0]); i++) {
+ struct sockaddr_in *addr = (struct sockaddr_in*) &req[i].ifr_broadaddr;
+ char buf[100];
+
+ ret = ioctl( player->fd, SIOCGIFBRDADDR, &req[i] );
+ if (ret) {
+ D_PERROR( "Voodoo/Player: ioctl( SIOCGIFBRDADDR ) failed!\n" );
+ continue;
+ }
+
+ if (addr->sin_addr.s_addr) {
+ inet_ntop( AF_INET, &addr->sin_addr, buf, sizeof(buf) );
+
+ D_INFO( "Voodoo/Player: %-16s (%s)\n", req[i].ifr_name, buf );
+ }
+ else {
+ ret = ioctl( player->fd, SIOCGIFDSTADDR, &req[i] );
+ if (ret) {
+ D_PERROR( "Voodoo/Player: ioctl( SIOCGIFDSTADDR ) failed!\n" );
+ continue;
+ }
+
+ inet_ntop( AF_INET, &addr->sin_addr, buf, sizeof(buf) );
+
+ D_INFO( "Voodoo/Player: %-16s (%s) (P-t-P)\n", req[i].ifr_name, buf );
+ }
+
+ //addr->sin_addr.s_addr = inet_addr( "192.168.1.150" );
+ //addr->sin_addr.s_addr = inet_addr( "192.168.255.255" );
+
+ player_send_info( player, &addr->sin_addr.s_addr, true );
+ }
+#endif
+#endif
+
+ return DR_OK;
+}
+
+DirectResult
+voodoo_player_lookup( VoodooPlayer *player,
+ const u8 uuid[16],
+ VoodooPlayInfo *ret_info,
+ char *ret_addr,
+ int max_addr )
+{
+ PlayerNode *node;
+
+ D_MAGIC_ASSERT( player, VoodooPlayer );
+
+ pthread_mutex_lock( &player->lock );
+
+ direct_list_foreach (node, player->nodes) {
+ if (!uuid || !memcmp( node->info.uuid, uuid, 16 )) {
+ if (ret_info)
+ direct_memcpy( ret_info, &node->info, sizeof(VoodooPlayInfo) );
+
+ if (ret_addr)
+ direct_snputs( ret_addr, node->addr, max_addr );
+
+ pthread_mutex_unlock( &player->lock );
+ return DR_OK;
+ }
+ }
+
+ if (uuid && !memcmp( player->info.uuid, uuid, 16 )) {
+ if (ret_info)
+ direct_memcpy( ret_info, &player->info, sizeof(VoodooPlayInfo) );
+
+ if (ret_addr)
+ direct_snputs( ret_addr, "127.0.0.1", max_addr );
+
+ pthread_mutex_unlock( &player->lock );
+ return DR_OK;
+ }
+
+ pthread_mutex_unlock( &player->lock );
+
+ return DR_ITEMNOTFOUND;
+}
+
+DirectResult
+voodoo_player_lookup_by_address( VoodooPlayer *player,
+ const char *addr,
+ VoodooPlayInfo *ret_info )
+{
+ PlayerNode *node;
+
+ D_MAGIC_ASSERT( player, VoodooPlayer );
+
+ pthread_mutex_lock( &player->lock );
+
+ direct_list_foreach (node, player->nodes) {
+ if (!addr || !strcmp( node->addr, addr )) {
+ direct_memcpy( ret_info, &node->info, sizeof(VoodooPlayInfo) );
+
+ pthread_mutex_unlock( &player->lock );
+ return DR_OK;
+ }
+ }
+
+ if (addr && !strcmp( "127.0.0.1", addr )) {
+ direct_memcpy( ret_info, &player->info, sizeof(VoodooPlayInfo) );
+
+ pthread_mutex_unlock( &player->lock );
+ return DR_OK;
+ }
+
+ pthread_mutex_unlock( &player->lock );
+
+ return DR_ITEMNOTFOUND;
+}
+
+DirectResult
+voodoo_player_enumerate( VoodooPlayer *player,
+ VoodooPlayerCallback callback,
+ void *ctx )
+{
+ PlayerNode *node;
+ long long now = direct_clock_get_abs_millis();
+
+
+ D_MAGIC_ASSERT( player, VoodooPlayer );
+
+ pthread_mutex_lock( &player->lock );
+
+ direct_list_foreach (node, player->nodes) {
+ if (node->broadcast != player->broadcast && direct_clock_get_abs_millis() - node->last_seen > 1000)
+ continue;
+
+ if (callback( ctx, &node->info, &node->version,
+ node->addr, now - node->last_seen ) == DENUM_CANCEL)
+ break;
+ }
+
+ pthread_mutex_unlock( &player->lock );
+
+ return DR_OK;
+}
+
+/**********************************************************************************************************************/
+
+__attribute__((unused))
+static void
+player_send_info( VoodooPlayer *player,
+ const in_addr_t *in_addr,
+ bool discover )
+{
+ int ret;
+ struct sockaddr_in addr;
+ VoodooPlayMessage msg;
+ PlayerNode *node;
+
+ D_MAGIC_ASSERT( player, VoodooPlayer );
+
+ msg.version = player->version;
+ msg.type = discover ? VPMT_DISCOVER : VPMT_SENDINFO;
+ msg.info = player->info;
+
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr = *in_addr;
+ addr.sin_port = htons( 2323 );
+
+ ret = sendto( player->fd, &msg, sizeof(msg), 0, (struct sockaddr*) &addr, sizeof(addr) );
+ if (ret < 0) {
+ D_PERROR( "Voodoo/Player: sendto() failed!\n" );
+ return;
+ }
+
+ if (!discover && voodoo_config->forward_nodes) {
+ direct_list_foreach (node, player->nodes) {
+ VoodooPlayInfo info = node->info;
+
+ info.flags |= VPIF_LEVEL2;
+
+ msg.version = node->version;
+ msg.type = discover ? VPMT_DISCOVER : VPMT_SENDINFO;
+ msg.info = info;
+
+ ret = sendto( player->fd, &msg, sizeof(msg), 0, (struct sockaddr*) &addr, sizeof(addr) );
+ if (ret < 0) {
+ D_PERROR( "Voodoo/Player: sendto() failed!\n" );
+ return;
+ }
+ }
+ }
+}
+
+static void
+player_save_info( VoodooPlayer *player,
+ const VoodooPlayMessage *msg,
+ const char *addr )
+{
+ PlayerNode *node;
+
+ D_MAGIC_ASSERT( player, VoodooPlayer );
+
+ direct_list_foreach (node, player->nodes) {
+ if (!memcmp( node->info.uuid, msg->info.uuid, 16 )) {
+ if (msg->info.flags & VPIF_LEVEL2 && !(node->info.flags & VPIF_LEVEL2)) {
+ node->version = msg->version;
+ node->info = msg->info;
+
+ direct_snputs( node->addr, addr, sizeof(node->addr) );
+ }
+ node->version = msg->version;
+ node->info = msg->info;
+
+ node->last_seen = direct_clock_get_abs_millis();
+ node->broadcast = player->broadcast;
+
+ direct_snputs( node->addr, addr, sizeof(node->addr) );
+
+ return;
+
+ }
+ }
+
+ node = D_CALLOC( 1, sizeof(PlayerNode) );
+ if (!node) {
+ D_OOM();
+ return;
+ }
+
+ node->version = msg->version;
+ node->info = msg->info;
+
+ node->last_seen = direct_clock_get_abs_millis();
+ node->broadcast = player->broadcast;
+
+ direct_snputs( node->addr, addr, sizeof(node->addr) );
+
+
+ direct_list_append( &player->nodes, &node->link );
+}
+
+#if !VOODOO_PLAY_FAKE
+static void *
+player_main_loop( DirectThread *thread, void *arg )
+{
+ VoodooPlayer *player = arg;
+ int ret;
+ struct sockaddr_in addr;
+ socklen_t addr_len = sizeof(addr);
+ VoodooPlayMessage msg;
+ char buf[100];
+
+ D_MAGIC_ASSERT( player, VoodooPlayer );
+
+ while (!player->quit) {
+ struct pollfd pf;
+
+ pf.fd = player->fd;
+ pf.events = POLLIN;
+
+ switch (poll( &pf, 1, 100 )) {
+ default:
+ ret = recvfrom( player->fd, &msg, sizeof(msg), 0, (struct sockaddr*) &addr, &addr_len );
+ if (ret < 0) {
+ D_PERROR( "Voodoo/Player: recvfrom() failed!\n" );
+ close(player->fd);
+ ret = createSocketForPlayer(&player->fd);
+
+ continue;
+ }
+
+ inet_ntop( AF_INET, &addr.sin_addr, buf, sizeof(buf) );
+
+ pthread_mutex_lock( &player->lock );
+
+ /* Send reply if message is not from ourself */
+ if (memcmp( msg.info.uuid, player->info.uuid, 16 )) {
+ switch (msg.type) {
+ case VPMT_DISCOVER:
+ D_INFO( "Voodoo/Player: Received DISCOVER from '%s' (%s)\n", msg.info.name, buf );
+ player_send_info( player, &addr.sin_addr.s_addr, false );
+ break;
+
+ case VPMT_SENDINFO:
+ D_INFO( "Voodoo/Player: Received SENDINFO from '%s' (%s)\n", msg.info.name, buf );
+ player_save_info( player, &msg, buf );
+ break;
+
+ default:
+ D_ERROR( "Voodoo/Player: Received unknown message (%s)\n", buf );
+ break;
+ }
+ }
+ else
+ D_INFO( "Voodoo/Player: Received message from ourself (%s)\n", buf );
+
+ pthread_mutex_unlock( &player->lock );
+ break;
+
+ case 0:
+ D_DEBUG( "Voodoo/Player: Timeout during poll()\n" );
+ break;
+
+ case -1:
+ if (errno != EINTR) {
+ D_PERROR( "Voodoo/Player: Could not poll() the socket!\n" );
+ close(player->fd);
+ ret = createSocketForPlayer(&player->fd);
+ // player->quit = true;
+ }
+ break;
+ }
+ }
+
+ return DR_OK;
+}
+#else
+
+static DirectResult
+send_discover_and_receive_info( int fd,
+ VoodooPlayVersion *ret_version,
+ VoodooPlayInfo *ret_info )
+{
+ int ret;
+ VoodooMessageHeader header;
+
+ D_INFO( "Voodoo/Player: Sending VMSG_DISCOVER message via Voodoo TCP port...\n" );
+
+ header.size = sizeof(VoodooMessageHeader);
+ header.serial = 0;
+ header.type = VMSG_DISCOVER;
+
+ ret = write( fd, &header, sizeof(header) );
+ if (ret < 0) {
+ ret = errno2result( errno );
+ D_PERROR( "Voodoo/Player: Failed to send VMSG_DISCOVER message via Voodoo TCP port!\n" );
+ return ret;
+ }
+
+
+
+ struct pollfd pfd;
+
+ pfd.events = POLL_IN;
+ pfd.fd = fd;
+
+ // wait for up to one second (old server will not reply anything, so we have to timeout)
+ ret = poll( &pfd, 1, 1000 );
+ if (ret < 0) {
+ ret = errno2result( errno );
+ D_PERROR( "Voodoo/Player: Failed to wait for reply after sending VMSG_DISCOVER message via Voodoo TCP port!\n" );
+ return ret;
+ }
+
+ if (ret == 0) {
+ D_INFO( "Voodoo/Player: Old Voodoo Server without VMSG_DISCOVER support (timeout waiting for reply)\n" );
+ return DR_UNSUPPORTED;
+ }
+
+ D_INFO( "Voodoo/Player: New Voodoo Server with VMSG_DISCOVER support, reading version/info (SENDINFO) reply...\n" );
+
+
+ struct {
+ VoodooMessageHeader header;
+ VoodooPlayVersion version;
+ VoodooPlayInfo info;
+ } msg;
+
+ size_t got = 0;
+
+ while (got < sizeof(msg)) {
+ ret = read( fd, (void*) &msg + got, sizeof(msg) - got );
+ if (ret < 0) {
+ ret = errno2result( errno );
+ D_PERROR( "Voodoo/Player: Failed to read after sending VMSG_DISCOVER message via Voodoo TCP port!\n" );
+ return ret;
+ }
+
+ got += ret;
+ }
+
+
+ if (msg.header.type != VMSG_SENDINFO) {
+ D_ERROR( "Voodoo/Player: Received message after sending VMSG_DISCOVER message via Voodoo TCP port is no VMSG_SENDINFO!\n");
+ return DR_INVARG;
+ }
+
+ *ret_version = msg.version;
+ *ret_info = msg.info;
+
+ D_INFO( "Voodoo/Player: Voodoo Server sent name '%s', version %d.%d.%d\n",
+ msg.info.name, msg.version.v[1], msg.version.v[2], msg.version.v[3] );
+
+ return DR_OK;
+}
+
+static void
+player_try_connect( VoodooPlayer *player,
+ u32 addr )
+{
+ DirectResult ret;
+ int fd, err;
+ struct in_addr sin_addr = { addr };
+
+ char buf[100];
+
+ inet_ntop( AF_INET, &sin_addr, buf, sizeof(buf) );
+
+
+ /* Create the client socket. */
+ fd = socket( AF_INET, SOCK_STREAM, 0 );
+ if (fd < 0) {
+ D_PERROR( "Voodoo/Player: Could not create the socket via socket( %d )!\n", AF_INET );
+ return;
+ }
+
+ struct sockaddr_in sock_addr;
+
+ sock_addr.sin_family = AF_INET;
+ sock_addr.sin_port = htons( 2323 );
+ sock_addr.sin_addr = sin_addr;
+
+ /* Connect to the server. */
+ err = connect( fd, (struct sockaddr*) &sock_addr, sizeof(sock_addr) );
+ if (err) {
+ D_PERROR( "Voodoo/Player: No Voodoo at '%s:2323'", buf );
+ close( fd );
+ return;
+ }
+
+ D_INFO( "Voodoo/Player: Found Voodoo at '%s'!\n", buf );
+
+
+ VoodooPlayMessage msg;
+
+
+ ret = send_discover_and_receive_info( fd, &msg.version, &msg.info );
+ if (ret) {
+ /* Fill version struct */
+ msg.version.v[0] = VPVF_LITTLE_ENDIAN | VPVF_32BIT_SERIALS;
+ msg.version.v[1] = DIRECTFB_MAJOR_VERSION;
+ msg.version.v[2] = DIRECTFB_MINOR_VERSION;
+ msg.version.v[3] = DIRECTFB_MICRO_VERSION;
+
+ msg.type = VPMT_SENDINFO;
+
+ /* Fill info struct */
+ direct_snputs( msg.info.name, "Unknown", VOODOO_PLAYER_NAME_LENGTH );
+ direct_snputs( msg.info.vendor, "Unknown", VOODOO_PLAYER_VENDOR_LENGTH );
+ direct_snputs( msg.info.model, "Unknown", VOODOO_PLAYER_MODEL_LENGTH );
+ generate_uuid( msg.info.uuid );
+ }
+
+
+ close( fd );
+
+
+ pthread_mutex_lock( &player->lock );
+
+ player_save_info( player, &msg, buf );
+
+ pthread_mutex_unlock( &player->lock );
+}
+
+typedef struct {
+ VoodooPlayer *player;
+ u32 addr;
+} PlayerTryContext;
+
+static void *
+player_try_thread( void *arg )
+{
+ PlayerTryContext *context = arg;
+
+ player_try_connect( context->player, context->addr );
+
+ D_FREE( context );
+
+ return NULL;
+}
+
+static void *
+player_main_loop( DirectThread *thread, void *arg )
+{
+ VoodooPlayer *player = arg;
+ int ret;
+ int i;
+ struct ifreq req[16];
+ struct ifconf conf;
+
+ D_MAGIC_ASSERT( player, VoodooPlayer );
+
+// while (!player->quit) {
+ conf.ifc_buf = (char*) req;
+ conf.ifc_len = sizeof(req);
+
+ ret = ioctl( player->fd, SIOCGIFCONF, &conf );
+ if (ret) {
+ D_PERROR( "Voodoo/Player: ioctl( SIOCGIFCONF ) failed!\n" );
+ return NULL;
+ }
+
+ D_INFO( "Voodoo/Player: Detected %d interfaces\n", conf.ifc_len/sizeof(req[0]) );
+
+ for (i=0; i<conf.ifc_len/sizeof(req[0]); i++) {
+ struct sockaddr_in *addr = (struct sockaddr_in*) &req[i].ifr_broadaddr;
+ char buf[100];
+
+ ret = ioctl( player->fd, SIOCGIFBRDADDR, &req[i] );
+ if (ret) {
+ D_PERROR( "Voodoo/Player: ioctl( SIOCGIFBRDADDR ) failed!\n" );
+ continue;
+ }
+
+ if (addr->sin_addr.s_addr) {
+ inet_ntop( AF_INET, &addr->sin_addr, buf, sizeof(buf) );
+
+ D_INFO( "Voodoo/Player: %-16s (%s) [0x%08x]\n", req[i].ifr_name, buf, addr->sin_addr.s_addr );
+
+ u32 _addr = htonl( addr->sin_addr.s_addr );
+ u32 a;
+
+ for (a = (_addr & ~0xff) + 1; a < (_addr | 0xff); a++) {
+ if (a == _addr)
+ continue;
+
+ PlayerTryContext *context = D_CALLOC( 1, sizeof(PlayerTryContext) );
+
+ context->player = player;
+ context->addr = ntohl(a);
+
+
+ pthread_t t;
+
+ pthread_create( &t, NULL, player_try_thread, context );
+ }
+ }
+ else {
+ ret = ioctl( player->fd, SIOCGIFDSTADDR, &req[i] );
+ if (ret) {
+ D_PERROR( "Voodoo/Player: ioctl( SIOCGIFDSTADDR ) failed!\n" );
+ continue;
+ }
+
+ inet_ntop( AF_INET, &addr->sin_addr, buf, sizeof(buf) );
+
+ D_INFO( "Voodoo/Player: %-16s (%s) (P-t-P)\n", req[i].ifr_name, buf );
+ }
+ }
+// }
+
+ return DR_OK;
+}
+#endif
+