From 7fe60435bce6595a9c58a9bfd8244d74b5320e96 Mon Sep 17 00:00:00 2001 From: Benjamin Franzke Date: Tue, 15 Jan 2013 08:46:13 +0100 Subject: Import DirectFB141_2k11R3_beta5 --- Source/DirectFB/lib/voodoo/unix/interfaces_unix.c | 237 +++++++++ Source/DirectFB/lib/voodoo/unix/link_unix.c | 567 +++++++++++++++++++++ .../DirectFB/lib/voodoo/unix/link_unix_1408limit.c | 422 +++++++++++++++ 3 files changed, 1226 insertions(+) create mode 100755 Source/DirectFB/lib/voodoo/unix/interfaces_unix.c create mode 100755 Source/DirectFB/lib/voodoo/unix/link_unix.c create mode 100755 Source/DirectFB/lib/voodoo/unix/link_unix_1408limit.c (limited to 'Source/DirectFB/lib/voodoo/unix') diff --git a/Source/DirectFB/lib/voodoo/unix/interfaces_unix.c b/Source/DirectFB/lib/voodoo/unix/interfaces_unix.c new file mode 100755 index 0000000..5c3b1f8 --- /dev/null +++ b/Source/DirectFB/lib/voodoo/unix/interfaces_unix.c @@ -0,0 +1,237 @@ +/* + (c) Copyright 2001-2011 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 , + Andreas Hundt , + Sven Neumann , + Ville Syrjälä and + Claudio Ciccani . + + 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 + +#include + +#include + +#include + +#include +#include +#include +#include + +#include + + + +DirectResult +voodoo_play_get_broadcast( VoodooPlayAddress **ret_addr, + size_t *ret_num ) +{ + size_t num = 0; + size_t i = 0; + VoodooPlayAddress *addr; + + int ret; + int fd; + char *ptr, lastname[IFNAMSIZ]; + struct ifreq req[16]; + struct ifconf conf; + + D_ASSERT( ret_addr != NULL ); + D_ASSERT( ret_num != NULL ); + + conf.ifc_buf = (char*) req; + conf.ifc_len = sizeof(req); + + fd = socket( AF_INET, SOCK_DGRAM, 0 ); + if (fd < 0) { + D_PERROR( "Voodoo/Unix: socket( AF_INET, SOCK_DGRAM, 0 ) failed!\n" ); + return DR_FAILURE; + } + + ret = ioctl( fd, SIOCGIFCONF, &conf ); + if (ret) { + D_PERROR( "Voodoo/Player: ioctl( SIOCGIFCONF ) failed!\n" ); + close( fd ); + return DR_FAILURE; + } + + lastname[0] = 0; + + for (ptr = conf.ifc_buf; ptr < conf.ifc_buf + conf.ifc_len; ) { + struct ifreq ifrcopy, *ifr = (struct ifreq *)ptr; + struct sockaddr_in *saddr = (struct sockaddr_in*) &ifr->ifr_broadaddr; + +#ifdef MACOS + ptr += sizeof(ifr->ifr_name) + MAX(sizeof(struct sockaddr), ifr->ifr_addr.sa_len); // for next one in buffer +#else + ptr += sizeof(req[0]); +#endif + + if (strncmp(lastname, ifr->ifr_name, IFNAMSIZ) == 0) { + continue; /* already processed this interface */ + } + + memcpy(lastname, ifr->ifr_name, IFNAMSIZ); + + ifrcopy = *ifr; + ioctl( fd, SIOCGIFFLAGS, &ifrcopy); + if ((ifrcopy.ifr_flags & IFF_UP) == 0) + continue; // ignore if interface not up + + ret = ioctl( fd, SIOCGIFBRDADDR, ifr ); + if (ret) + continue; + + if (!saddr->sin_addr.s_addr) { + ret = ioctl( fd, SIOCGIFDSTADDR, ifr ); + if (ret) + continue; + } + + num++; + } + + + addr = D_CALLOC( num, sizeof(VoodooPlayAddress) ); + if (!addr) { + close( fd ); + return D_OOM(); + } + + + for (ptr = conf.ifc_buf; ptr < conf.ifc_buf + conf.ifc_len; ) { + char buf[100]; + struct ifreq ifrcopy, *ifr = (struct ifreq *)ptr; + struct sockaddr_in *saddr = (struct sockaddr_in*) &ifr->ifr_broadaddr; + +#ifdef MACOS + ptr += sizeof(ifr->ifr_name) + MAX(sizeof(struct sockaddr), ifr->ifr_addr.sa_len); // for next one in buffer +#else + ptr += sizeof(req[0]); +#endif + + if (strncmp(lastname, ifr->ifr_name, IFNAMSIZ) == 0) { + continue; /* already processed this interface */ + } + + memcpy(lastname, ifr->ifr_name, IFNAMSIZ); + + ifrcopy = *ifr; + ioctl( fd, SIOCGIFFLAGS, &ifrcopy); + if ((ifrcopy.ifr_flags & IFF_UP) == 0) { + D_INFO( "Voodoo/Player: %-16s is not up.\n", ifrcopy.ifr_name ); + continue; // ignore if interface not up + } + + ret = ioctl( fd, SIOCGIFBRDADDR, ifr ); + if (ret) { + D_PERROR( "Voodoo/Player: ioctl( SIOCGIFBRDADDR ) %-16s failed!\n", ifr->ifr_name ); + continue; + } + + if (saddr->sin_addr.s_addr) { + inet_ntop( AF_INET, &saddr->sin_addr, buf, sizeof(buf) ); + + D_INFO( "Voodoo/Player: %-16s (%s)\n", ifr->ifr_name, buf ); + } + else { + ret = ioctl( fd, SIOCGIFDSTADDR, ifr ); + if (ret) { + D_PERROR( "Voodoo/Player: ioctl( SIOCGIFDSTADDR ) failed!\n" ); + continue; + } + + inet_ntop( AF_INET, &saddr->sin_addr, buf, sizeof(buf) ); + + D_INFO( "Voodoo/Player: %-16s (%s) (P-t-P)\n", ifr->ifr_name, buf ); + } + + voodoo_play_from_inet_addr( &addr[i++], saddr->sin_addr.s_addr ); + } + + close( fd ); + + *ret_addr = addr; + *ret_num = num; + + return DR_OK; +} + + + +#if 0 + +DirectResult +voodoo_play_get_broadcast( VoodooPlayAddress **ret_addr, + size_t *ret_num ) +{ + DirectResult ret = DR_OK; + VoodooPlayAddress *addr; + + // Get local host name + char szHostName[128] = ""; + + if (gethostname(szHostName, sizeof(szHostName))) { + ret = errno2result( errno ); + D_PERROR( "Voodoo/Win32: gethostname() failed!\n" ); + return ret; + } + + // Get local IP addresses + struct hostent *pHost = 0; + + pHost = gethostbyname(szHostName); + if (!pHost) { + ret = errno2result( errno ); + D_PERROR( "Voodoo/Win32: gethostbyname('%s') failed!\n", szHostName ); + return ret; + } + + + size_t iCnt, iTotal = 0; + + for (iCnt = 0; pHost->h_addr_list[iCnt]; ++iCnt) + iTotal++; + + + addr = D_CALLOC( iTotal, sizeof(VoodooPlayAddress) ); + if (!addr) + return D_OOM(); + + for (iCnt = 0; pHost->h_addr_list[iCnt]; ++iCnt) { + struct sockaddr_in SocketAddress; + + memcpy(&SocketAddress.sin_addr, pHost->h_addr_list[iCnt], pHost->h_length); + + voodoo_play_from_inet_addr( &addr[iCnt], SocketAddress.sin_addr.s_addr ); + } + + *ret_addr = addr; + *ret_num = iTotal; + + return DR_OK; +} + +#endif + diff --git a/Source/DirectFB/lib/voodoo/unix/link_unix.c b/Source/DirectFB/lib/voodoo/unix/link_unix.c new file mode 100755 index 0000000..1b6690c --- /dev/null +++ b/Source/DirectFB/lib/voodoo/unix/link_unix.c @@ -0,0 +1,567 @@ +/* + (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 , + Andreas Hundt , + Sven Neumann , + Ville Syrjälä and + Claudio Ciccani . + + 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. +*/ + +//#define DIRECT_ENABLE_DEBUG + +#include + +//#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + + +#define UNIX_PATH_MAX 108 + + +D_DEBUG_DOMAIN( Voodoo_Link, "Voodoo/Link", "Voodoo Link" ); + +/**********************************************************************************************************************/ + +#if !VOODOO_BUILD_NO_SETSOCKOPT +static const int one = 1; +static const int tos = IPTOS_LOWDELAY; +#endif + +/**********************************************************************************************************************/ + +#define DUMP_SOCKET_OPTION(fd,o) \ +do { \ + int val = 0; \ + unsigned int len = 4; \ + \ + if (getsockopt( fd, SOL_SOCKET, o, &val, &len )) \ + D_PERROR( "Voodoo/Manager: getsockopt() for " #o " failed!\n" ); \ + else \ + D_DEBUG( "Voodoo/Manager: " #o " is %d\n", val ); \ +} while (0) + +/**********************************************************************************************************************/ + +typedef struct { + int fd[2]; + int wakeup_fds[2]; +} Link; + +static void +Close( VoodooLink *link ) +{ + Link *l = link->priv; + + D_INFO( "Voodoo/Link: Closing connection.\n" ); + + close( l->fd[0] ); + + if (l->fd[1] != l->fd[0]) + close( l->fd[1] ); + + close( l->wakeup_fds[0] ); + close( l->wakeup_fds[1] ); + + D_FREE( link->priv ); + link->priv = NULL; +} + +static ssize_t +Read( VoodooLink *link, + void *buffer, + size_t count ) +{ + Link *l = link->priv; + + return recv( l->fd[0], buffer, count, 0 ); +} + +static ssize_t +Write( VoodooLink *link, + const void *buffer, + size_t count ) +{ + Link *l = link->priv; + + return send( l->fd[1], buffer, count, 0 ); +} + + +// FIXME: refactor, optionally using lio_listio +static DirectResult +SendReceive( VoodooLink *link, + VoodooChunk *sends, + size_t num_send, + VoodooChunk *recvs, + size_t num_recv ) +{ + Link *l = link->priv; + size_t i; + ssize_t ret; + int select_result; + + D_DEBUG_AT( Voodoo_Link, "%s( link %p, sends %p, num_send %zu, recvs %p, num_recv %zu )\n", + __func__, link, sends, num_send, recvs, num_recv ); + + while (true) { + fd_set fds_read; + fd_set fds_write; + struct timeval tv; + + FD_ZERO( &fds_read ); + FD_ZERO( &fds_write ); + + if (num_recv) + FD_SET( l->fd[0], &fds_read ); + + if (num_send) + FD_SET( l->fd[1], &fds_write ); + + FD_SET( l->wakeup_fds[0], &fds_read ); + + tv.tv_sec = 1; + tv.tv_usec = 0; + + D_DEBUG_AT( Voodoo_Link, " -> select( %s%s )...\n", num_recv ? "R" : " ", num_send ? "W" : " " ); + select_result = select( MAX(MAX(l->wakeup_fds[0],l->fd[0]),l->fd[1])+1, &fds_read, &fds_write, NULL, &tv ); + switch (select_result) { + default: + if (FD_ISSET( l->fd[1], &fds_write )) { + D_DEBUG_AT( Voodoo_Link, " => WRITE\n" ); + + for (i=0; ifd[1], sends[i].ptr, sends[i].length, MSG_DONTWAIT ); + if (ret < 0) { + D_PERROR( "Voodoo/Link: Failed to send() data!\n" ); + return DR_IO; + } + else { + sends[i].done += ret; +/* + if (sends[i].done != sends[i].length) + D_WARN( "partial send of %d/%d bytes", ret, sends[i].length ); + else + D_WARN( "full send of %d bytes", ret, sends[i].length ); +*/ + return DR_OK; + } +#else + struct aiocb cb; + + memset( &cb, 0, sizeof(struct aiocb) ); + + cb.aio_fildes = l->fd[1]; + cb.aio_buf = sends[i].ptr; + cb.aio_nbytes = sends[i].length; + cb.aio_offset = (intptr_t)-1; + cb.aio_sigevent.sigev_notify = SIGEV_NONE; + + + ret = aio_write( &cb ); + if (ret < 0) { + D_PERROR( "Voodoo/Link: aio_write() failed!\n" ); + return DR_IO; + } + else { + do { + const struct aiocb *cbs[] = { &cb }; + + ret = aio_suspend( cbs, 1, NULL ); + if (ret < 0) { + D_PERROR( "Voodoo/Link: aio_suspend() failed!\n" ); + return DR_IO; + } + + ret = aio_error( &cb ); + } while (ret == EINPROGRESS); + + switch (ret) { + case 0: + ret = aio_return( &cb ); + if (ret < 0) { + D_ERROR( "Voodoo/Link: aio_return() failed!\n -> %s\n", strerror(ret) ); + return DR_IO; + } + break; + + default: + D_ERROR( "Voodoo/Link: aio_error() failed!\n -> %s\n", strerror(ret) ); + return DR_IO; + } + + sends[i].done += ret; +/* + if (sends[i].done != sends[i].length) + D_WARN( "partial send of %d/%d bytes", ret, sends[i].length ); + else + D_WARN( "full send of %d bytes", ret, sends[i].length ); +*/ + return DR_OK; + } +#endif + } + } + } + + if (FD_ISSET( l->fd[0], &fds_read )) { + D_DEBUG_AT( Voodoo_Link, " => READ\n" ); + + for (i=0; ifd[0], recvs[i].ptr, recvs[i].length, MSG_DONTWAIT ); + if (ret < 0) { + if (errno == EAGAIN) { + break; + } + D_PERROR( "Voodoo/Link: Failed to recv() data!\n" ); + return DR_FAILURE; + } + + if (!ret) + return DR_IO; + + + recvs[i].done = ret; + + if (recvs[i].done < recvs[i].length) + break; + } + } + + if (FD_ISSET( l->wakeup_fds[0], &fds_read )) { + D_DEBUG_AT( Voodoo_Link, " => WAKE UP\n" ); + + static char buf[1000]; + read( l->wakeup_fds[0], buf, sizeof(buf) ); + if (!FD_ISSET( l->fd[0], &fds_read ) && !FD_ISSET( l->fd[0], &fds_write )) + return DR_INTERRUPTED; + } + + return DR_OK; + + case 0: + D_DEBUG_AT( Voodoo_Link, " => TIMEOUT\n" ); + return DR_TIMEOUT; + + case -1: + D_ERROR( "Voodoo/Link: select() failed!\n" ); + return DR_FAILURE; + } + } + + return DR_OK; +} + +static DirectResult +WakeUp( VoodooLink *link ) +{ + Link *l = link->priv; + char c = 0; + + write( l->wakeup_fds[1], &c, 1 ); + + return DR_OK; +} + +/**********************************************************************************************************************/ + +DirectResult +voodoo_link_init_connect( VoodooLink *link, + const char *hostname, + int port, + bool raw ) +{ + DirectResult ret; + int err; + struct addrinfo hints; + struct addrinfo *addr; + char portstr[10]; + Link *l; + + + memset( &hints, 0, sizeof(hints) ); + hints.ai_flags = AI_CANONNAME; + hints.ai_socktype = SOCK_STREAM; + hints.ai_family = PF_UNSPEC; + + D_INFO( "Voodoo/Link: Looking up host '%s'...\n", hostname ); + + snprintf( portstr, sizeof(portstr), "%d", port ); + + err = getaddrinfo( hostname, portstr, &hints, &addr ); + if (err) { + switch (err) { + case EAI_FAMILY: + D_ERROR( "Direct/Log: Unsupported address family!\n" ); + return DR_UNSUPPORTED; + + case EAI_SOCKTYPE: + D_ERROR( "Direct/Log: Unsupported socket type!\n" ); + return DR_UNSUPPORTED; + + case EAI_NONAME: + D_ERROR( "Direct/Log: Host not found!\n" ); + return DR_FAILURE; + + case EAI_SERVICE: + D_ERROR( "Direct/Log: Service is unreachable!\n" ); + return DR_FAILURE; + +#ifdef EAI_ADDRFAMILY + case EAI_ADDRFAMILY: +#endif + case EAI_NODATA: + D_ERROR( "Direct/Log: Host found, but has no address!\n" ); + return DR_FAILURE; + + case EAI_MEMORY: + return D_OOM(); + + case EAI_FAIL: + D_ERROR( "Direct/Log: A non-recoverable name server error occurred!\n" ); + return DR_FAILURE; + + case EAI_AGAIN: + D_ERROR( "Direct/Log: Temporary error, try again!\n" ); + return DR_TEMPUNAVAIL; + + default: + D_ERROR( "Direct/Log: Unknown error occured!?\n" ); + return DR_FAILURE; + } + } + + + l = D_CALLOC( 1, sizeof(Link) ); + if (!l) + return D_OOM(); + + /* Create the client socket. */ + l->fd[0] = socket( addr->ai_family, SOCK_STREAM, 0 ); + if (l->fd[0] < 0) { + ret = errno2result( errno ); + D_PERROR( "Voodoo/Link: Socket creation failed!\n" ); + freeaddrinfo( addr ); + D_FREE( l ); + return ret; + } + l->fd[1] = l->fd[0]; + +#if !VOODOO_BUILD_NO_SETSOCKOPT +// if (setsockopt( l->fd[0], SOL_IP, IP_TOS, &tos, sizeof(tos) ) < 0) +// D_PERROR( "Voodoo/Manager: Could not set IP_TOS!\n" ); + + if (setsockopt( l->fd[0], SOL_TCP, TCP_NODELAY, &one, sizeof(one) ) < 0) + D_PERROR( "Voodoo/Manager: Could not set TCP_NODELAY!\n" ); +#endif + + D_INFO( "Voodoo/Link: Connecting to '%s:%d'...\n", addr->ai_canonname, port ); + + /* Connect to the server. */ + err = connect( l->fd[0], addr->ai_addr, addr->ai_addrlen ); + freeaddrinfo( addr ); + + if (err) { + ret = errno2result( errno ); + D_PERROR( "Voodoo/Link: Socket connect failed!\n" ); + close( l->fd[0] ); + D_FREE( l ); + return ret; + } + + D_INFO( "Voodoo/Link: Connected.\n" ); + + DUMP_SOCKET_OPTION( l->fd[0], SO_SNDLOWAT ); + DUMP_SOCKET_OPTION( l->fd[0], SO_RCVLOWAT ); + DUMP_SOCKET_OPTION( l->fd[0], SO_SNDBUF ); + DUMP_SOCKET_OPTION( l->fd[0], SO_RCVBUF ); + + if (!raw) { + link->code = 0x80008676; + + if (write( l->fd[1], &link->code, sizeof(link->code) ) != 4) { + D_ERROR( "Voodoo/Link: Coult not write initial four bytes!\n" ); + close( l->fd[0] ); + D_FREE( l ); + return DR_IO; + } + } + D_INFO( "Voodoo/Link: Sent link code (%s).\n", raw ? "raw" : "packet" ); + + pipe( l->wakeup_fds ); + + + link->priv = l; + link->Close = Close; + link->Read = Read; + link->Write = Write; + link->SendReceive = SendReceive; + link->WakeUp = WakeUp; + + return DR_OK; +} + +DirectResult +voodoo_link_init_local( VoodooLink *link, + const char *path, + bool raw ) +{ + DirectResult ret; + int err; + struct sockaddr_un addr; + Link *l; + + D_ASSERT( link != NULL ); + D_ASSERT( path != NULL ); + + l = D_CALLOC( 1, sizeof(Link) ); + if (!l) + return D_OOM(); + + /* Create the client socket. */ + l->fd[0] = socket( AF_LOCAL, SOCK_STREAM, 0 ); + if (l->fd[0] < 0) { + ret = errno2result( errno ); + D_PERROR( "Voodoo/Link: Socket creation failed!\n" ); + D_FREE( l ); + return ret; + } + l->fd[1] = l->fd[0]; + +#if !VOODOO_BUILD_NO_SETSOCKOPT +// if (setsockopt( l->fd[0], SOL_IP, IP_TOS, &tos, sizeof(tos) ) < 0) +// D_PERROR( "Voodoo/Manager: Could not set IP_TOS!\n" ); + + if (setsockopt( l->fd[0], SOL_TCP, TCP_NODELAY, &one, sizeof(one) ) < 0) + D_PERROR( "Voodoo/Manager: Could not set TCP_NODELAY!\n" ); +#endif + + D_INFO( "Voodoo/Link: Connecting to '%s'...\n", path ); + + + memset( &addr, 0, sizeof(addr) ); + + /* Bind the socket to the local port. */ + addr.sun_family = AF_UNIX; + + snprintf( addr.sun_path + 1, UNIX_PATH_MAX - 1, "%s", path ); + + /* Connect to the server. */ + err = connect( l->fd[0], (struct sockaddr*) &addr, strlen(addr.sun_path+1)+1 + sizeof(addr.sun_family) ); + if (err) { + ret = errno2result( errno ); + D_PERROR( "Voodoo/Link: Socket connect failed!\n" ); + close( l->fd[0] ); + D_FREE( l ); + return ret; + } + + D_INFO( "Voodoo/Link: Connected.\n" ); + + DUMP_SOCKET_OPTION( l->fd[0], SO_SNDLOWAT ); + DUMP_SOCKET_OPTION( l->fd[0], SO_RCVLOWAT ); + DUMP_SOCKET_OPTION( l->fd[0], SO_SNDBUF ); + DUMP_SOCKET_OPTION( l->fd[0], SO_RCVBUF ); + + if (!raw) { + link->code = 0x80008676; + + if (write( l->fd[1], &link->code, sizeof(link->code) ) != 4) { + D_ERROR( "Voodoo/Link: Coult not write initial four bytes!\n" ); + close( l->fd[0] ); + D_FREE( l ); + return DR_IO; + } + } + D_INFO( "Voodoo/Link: Sent link code (%s).\n", raw ? "raw" : "packet" ); + + pipe( l->wakeup_fds ); + + + link->priv = l; + link->Close = Close; + link->Read = Read; + link->Write = Write; + link->SendReceive = SendReceive; + link->WakeUp = WakeUp; + + return DR_OK; +} + +DirectResult +voodoo_link_init_fd( VoodooLink *link, + int fd[2] ) +{ + Link *l; + + if (read( fd[0], &link->code, sizeof(link->code) ) != 4) { + D_ERROR( "Voodoo/Link: Coult not read initial four bytes!\n" ); + return DR_IO; + } + + l = D_CALLOC( 1, sizeof(Link) ); + if (!l) + return D_OOM(); + + l->fd[0] = fd[0]; + l->fd[1] = fd[1]; + + pipe( l->wakeup_fds ); + + link->priv = l; + link->Close = Close; + link->Read = Read; + link->Write = Write; + link->SendReceive = SendReceive; + link->WakeUp = WakeUp; + + return DR_OK; +} + diff --git a/Source/DirectFB/lib/voodoo/unix/link_unix_1408limit.c b/Source/DirectFB/lib/voodoo/unix/link_unix_1408limit.c new file mode 100755 index 0000000..790aa99 --- /dev/null +++ b/Source/DirectFB/lib/voodoo/unix/link_unix_1408limit.c @@ -0,0 +1,422 @@ +/* + (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 , + Andreas Hundt , + Sven Neumann , + Ville Syrjälä and + Claudio Ciccani . + + 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. +*/ + +//#define DIRECT_ENABLE_DEBUG + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + + +D_DEBUG_DOMAIN( Voodoo_Link, "Voodoo/Link", "Voodoo Link" ); + +/**********************************************************************************************************************/ + +#if !VOODOO_BUILD_NO_SETSOCKOPT +static const int one = 1; +static const int tos = IPTOS_LOWDELAY; +#endif + +/**********************************************************************************************************************/ + +#define DUMP_SOCKET_OPTION(fd,o) \ +do { \ + int val = 0; \ + unsigned int len = 4; \ + \ + if (getsockopt( fd, SOL_SOCKET, o, &val, &len )) \ + D_PERROR( "Voodoo/Manager: getsockopt() for " #o " failed!\n" ); \ + else \ + D_DEBUG( "Voodoo/Manager: " #o " is %d\n", val ); \ +} while (0) + +/**********************************************************************************************************************/ + +typedef struct { + int fd[2]; + int wakeup_fds[2]; +} Link; + +static void +Close( VoodooLink *link ) +{ + Link *l = link->priv; + + D_INFO( "Voodoo/Link: Closing connection.\n" ); + + close( l->fd[0] ); + + if (l->fd[1] != l->fd[0]) + close( l->fd[1] ); + + D_FREE( link->priv ); + link->priv = NULL; +} + +static ssize_t +Read( VoodooLink *link, + void *buffer, + size_t count ) +{ + Link *l = link->priv; + + return recv( l->fd[0], buffer, count, 0 ); +} + +static ssize_t +Write( VoodooLink *link, + const void *buffer, + size_t count ) +{ + Link *l = link->priv; + + return send( l->fd[1], buffer, count, 0 ); +} + + +// FIXME: refactor, optionally using lio_listio +static DirectResult +SendReceive( VoodooLink *link, + VoodooChunk *sends, + size_t num_send, + VoodooChunk *recvs, + size_t num_recv ) +{ + Link *l = link->priv; + size_t i; + ssize_t ret; + int select_result; + + D_DEBUG_AT( Voodoo_Link, "%s( link %p, sends %p, num_send %zu, recvs %p, num_recv %zu )\n", + __func__, link, sends, num_send, recvs, num_recv ); + + while (true) { + fd_set fds_read; + fd_set fds_write; + struct timeval tv; + + FD_ZERO( &fds_read ); + FD_ZERO( &fds_write ); + + if (num_recv) + FD_SET( l->fd[0], &fds_read ); + + if (num_send) + FD_SET( l->fd[1], &fds_write ); + + FD_SET( l->wakeup_fds[0], &fds_read ); + + tv.tv_sec = 1; + tv.tv_usec = 0; + + D_DEBUG_AT( Voodoo_Link, " -> select( %s%s )...\n", num_recv ? "R" : " ", num_send ? "W" : " " ); + select_result = select( MAX(MAX(l->wakeup_fds[0],l->fd[0]),l->fd[1])+1, &fds_read, &fds_write, NULL, &tv ); + switch (select_result) { + default: + if (FD_ISSET( l->fd[1], &fds_write )) { + D_DEBUG_AT( Voodoo_Link, " => WRITE\n" ); + + for (i=0; ifd[1], sends[i].ptr, sends[i].length, MSG_DONTWAIT ); + if (ret < 0) { + //if (errno == EAGAIN) { + // break; + //} + D_PERROR( "Voodoo/Link: Failed to send() data!\n" ); + return DR_FAILURE; + } + else { + sends[i].done += ret; +/* + if (sends[i].done != sends[i].length) + D_WARN( "partial send of %d/%d bytes", ret, sends[i].length ); + else + D_WARN( "full send of %d bytes", ret, sends[i].length ); +*/ +// return DR_OK; + break; + } + } + } + } + + if (FD_ISSET( l->fd[0], &fds_read )) { + D_DEBUG_AT( Voodoo_Link, " => READ\n" ); + + for (i=0; ifd[0], recvs[i].ptr, recvs[i].length, MSG_DONTWAIT ); + if (ret < 0) { + if (errno == EAGAIN) { + break; + } + D_PERROR( "Voodoo/Link: Failed to recv() data!\n" ); + return DR_FAILURE; + } + + if (!ret) + return DR_IO; + + + recvs[i].done = ret; + + if (recvs[i].done < recvs[i].length) + break; + } + } + + if (FD_ISSET( l->wakeup_fds[0], &fds_read )) { + D_DEBUG_AT( Voodoo_Link, " => WAKE UP\n" ); + + static char buf[1000]; + read( l->wakeup_fds[0], buf, sizeof(buf) ); + if (!FD_ISSET( l->fd[0], &fds_read ) && !FD_ISSET( l->fd[0], &fds_write )) + return DR_INTERRUPTED; + } + + return DR_OK; + + case 0: + D_DEBUG_AT( Voodoo_Link, " => TIMEOUT\n" ); + return DR_TIMEOUT; + + case -1: + D_ERROR( "Voodoo/Link: select() failed!\n" ); + return DR_FAILURE; + } + } + + return DR_OK; +} + +static DirectResult +WakeUp( VoodooLink *link ) +{ + Link *l = link->priv; + char c = 0; + + write( l->wakeup_fds[1], &c, 1 ); + + return DR_OK; +} + +/**********************************************************************************************************************/ + +DirectResult +voodoo_link_init_connect( VoodooLink *link, + const char *hostname, + int port, + bool raw ) +{ + DirectResult ret; + int err; + struct addrinfo hints; + struct addrinfo *addr; + char portstr[10]; + Link *l; + + + memset( &hints, 0, sizeof(hints) ); + hints.ai_flags = AI_CANONNAME; + hints.ai_socktype = SOCK_STREAM; + hints.ai_family = PF_UNSPEC; + + D_INFO( "Voodoo/Link: Looking up host '%s'...\n", hostname ); + + snprintf( portstr, sizeof(portstr), "%d", port ); + + err = getaddrinfo( hostname, portstr, &hints, &addr ); + if (err) { + switch (err) { + case EAI_FAMILY: + D_ERROR( "Direct/Log: Unsupported address family!\n" ); + return DR_UNSUPPORTED; + + case EAI_SOCKTYPE: + D_ERROR( "Direct/Log: Unsupported socket type!\n" ); + return DR_UNSUPPORTED; + + case EAI_NONAME: + D_ERROR( "Direct/Log: Host not found!\n" ); + return DR_FAILURE; + + case EAI_SERVICE: + D_ERROR( "Direct/Log: Service is unreachable!\n" ); + return DR_FAILURE; + +#ifdef EAI_ADDRFAMILY + case EAI_ADDRFAMILY: +#endif + case EAI_NODATA: + D_ERROR( "Direct/Log: Host found, but has no address!\n" ); + return DR_FAILURE; + + case EAI_MEMORY: + return D_OOM(); + + case EAI_FAIL: + D_ERROR( "Direct/Log: A non-recoverable name server error occurred!\n" ); + return DR_FAILURE; + + case EAI_AGAIN: + D_ERROR( "Direct/Log: Temporary error, try again!\n" ); + return DR_TEMPUNAVAIL; + + default: + D_ERROR( "Direct/Log: Unknown error occured!?\n" ); + return DR_FAILURE; + } + } + + + l = D_CALLOC( 1, sizeof(Link) ); + if (!l) + return D_OOM(); + + /* Create the client socket. */ + l->fd[0] = socket( addr->ai_family, SOCK_STREAM, 0 ); + if (l->fd[0] < 0) { + ret = errno2result( errno ); + D_PERROR( "Voodoo/Link: Socket creation failed!\n" ); + freeaddrinfo( addr ); + D_FREE( l ); + return ret; + } + l->fd[1] = l->fd[0]; + +#if !VOODOO_BUILD_NO_SETSOCKOPT + if (setsockopt( l->fd[0], SOL_IP, IP_TOS, &tos, sizeof(tos) ) < 0) + D_PERROR( "Voodoo/Manager: Could not set IP_TOS!\n" ); + + if (setsockopt( l->fd[0], SOL_TCP, TCP_NODELAY, &one, sizeof(one) ) < 0) + D_PERROR( "Voodoo/Manager: Could not set TCP_NODELAY!\n" ); +#endif + + D_INFO( "Voodoo/Link: Connecting to '%s:%d'...\n", addr->ai_canonname, port ); + + /* Connect to the server. */ + err = connect( l->fd[0], addr->ai_addr, addr->ai_addrlen ); + freeaddrinfo( addr ); + + if (err) { + ret = errno2result( errno ); + D_PERROR( "Voodoo/Link: Socket connect failed!\n" ); + close( l->fd[0] ); + D_FREE( l ); + return ret; + } + + D_INFO( "Voodoo/Link: Connected.\n" ); + + DUMP_SOCKET_OPTION( l->fd[0], SO_SNDLOWAT ); + DUMP_SOCKET_OPTION( l->fd[0], SO_RCVLOWAT ); + DUMP_SOCKET_OPTION( l->fd[0], SO_SNDBUF ); + DUMP_SOCKET_OPTION( l->fd[0], SO_RCVBUF ); + + if (!raw) { + link->code = 0x80008676; + + if (write( l->fd[1], &link->code, sizeof(link->code) ) != 4) { + D_ERROR( "Voodoo/Link: Coult not write initial four bytes!\n" ); + close( l->fd[0] ); + D_FREE( l ); + return DR_IO; + } + } + D_INFO( "Voodoo/Link: Sent link code (%s).\n", raw ? "raw" : "packet" ); + + pipe( l->wakeup_fds ); + + + link->priv = l; + link->Close = Close; + link->Read = Read; + link->Write = Write; + link->SendReceive = SendReceive; + link->WakeUp = WakeUp; + + return DR_OK; +} + +DirectResult +voodoo_link_init_fd( VoodooLink *link, + int fd[2] ) +{ + Link *l; + + if (read( fd[0], &link->code, sizeof(link->code) ) != 4) { + D_ERROR( "Voodoo/Link: Coult not read initial four bytes!\n" ); + return DR_IO; + } + + l = D_CALLOC( 1, sizeof(Link) ); + if (!l) + return D_OOM(); + + l->fd[0] = fd[0]; + l->fd[1] = fd[1]; + + pipe( l->wakeup_fds ); + + link->priv = l; + link->Close = Close; + link->Read = Read; + link->Write = Write; + link->SendReceive = SendReceive; + link->WakeUp = WakeUp; + + return DR_OK; +} + -- cgit