# include "config.h"
#endif
+#include <assert.h>
#include <errno.h>
-#ifdef WIN32
+#ifdef _WIN32
#include <io.h>
#endif
#ifdef HAVE_POLL
#include "../vlc.h"
#include "../libs.h"
+#include "misc.h"
+
+static vlclua_dtable_t *vlclua_get_dtable( lua_State *L )
+{
+ return vlclua_get_object( L, vlclua_get_dtable );
+}
+
+/** Maps an OS file descriptor to a VLC Lua file descriptor */
+static int vlclua_fd_map( lua_State *L, int fd )
+{
+ vlclua_dtable_t *dt = vlclua_get_dtable( L );
+
+ if( (unsigned)fd < 3u )
+ return -1;
+
+#ifndef NDEBUG
+ for( unsigned i = 0; i < dt->fdc; i++ )
+ assert( dt->fdv[i] != fd );
+#endif
+
+ if( dt->fdc >= 64 )
+ return -1;
+
+ int *fdv = realloc( dt->fdv, (dt->fdc + 1) * sizeof (dt->fdv[0]) );
+ if( unlikely(fdv == NULL) )
+ return -1;
+
+ dt->fdv = fdv;
+ dt->fdv[dt->fdc] = fd;
+ fd = 3 + dt->fdc;
+ dt->fdc++;
+ return fd;
+}
+
+static int vlclua_fd_map_safe( lua_State *L, int fd )
+{
+ int luafd = vlclua_fd_map( L, fd );
+ if( luafd == -1 )
+ net_Close( fd );
+ return luafd;
+}
+
+/** Gets the OS file descriptor mapped to a VLC Lua file descriptor */
+static int vlclua_fd_get( lua_State *L, unsigned idx )
+{
+ vlclua_dtable_t *dt = vlclua_get_dtable( L );
+
+ if( idx < 3u )
+ return idx;
+ idx -= 3;
+ return (idx < dt->fdc) ? dt->fdv[idx] : -1;
+}
+
+/** Gets the VLC Lua file descriptor mapped from an OS file descriptor */
+static int vlclua_fd_get_lua( lua_State *L, int fd )
+{
+ vlclua_dtable_t *dt = vlclua_get_dtable( L );
+
+ if( (unsigned)fd < 3u )
+ return fd;
+ for( unsigned i = 0; i < dt->fdc; i++ )
+ if( dt->fdv[i] == fd )
+ return 3 + i;
+ return -1;
+}
+
+/** Unmaps an OS file descriptor from VLC Lua */
+static void vlclua_fd_unmap( lua_State *L, unsigned idx )
+{
+ vlclua_dtable_t *dt = vlclua_get_dtable( L );
+ int fd = -1;
+
+ if( idx < 3u )
+ return; /* Never close stdin/stdout/stderr. */
+
+ idx -= 3;
+ if( idx >= dt->fdc )
+ return;
+
+ fd = dt->fdv[idx];
+ dt->fdc--;
+ memmove( dt->fdv + idx, dt->fdv + idx + 1,
+ (dt->fdc - idx) * sizeof (dt->fdv[0]) );
+ /* realloc() not really needed */
+#ifndef NDEBUG
+ for( unsigned i = 0; i < dt->fdc; i++ )
+ assert( dt->fdv[i] != fd );
+#endif
+}
+
+static void vlclua_fd_unmap_safe( lua_State *L, unsigned idx )
+{
+ int fd = vlclua_fd_get( L, idx );
+
+ vlclua_fd_unmap( L, idx );
+ if( fd != -1 )
+ net_Close( fd );
+}
/*****************************************************************************
*
if( pi_fd == NULL )
return luaL_error( L, "Cannot listen on %s:%d", psz_host, i_port );
+ for( unsigned i = 0; pi_fd[i] != -1; i++ )
+ if( vlclua_fd_map( L, pi_fd[i] ) == -1 )
+ {
+ while( i > 0 )
+ vlclua_fd_unmap( L, vlclua_fd_get_lua( L, pi_fd[--i] ) );
+
+ net_ListenClose( pi_fd );
+ return luaL_error( L, "Cannot listen on %s:%d", psz_host, i_port );
+ }
+
int **ppi_fd = lua_newuserdata( L, sizeof( int * ) );
*ppi_fd = pi_fd;
static int vlclua_net_listen_close( lua_State *L )
{
int **ppi_fd = (int**)luaL_checkudata( L, 1, "net_listen" );
- net_ListenClose( *ppi_fd );
+ int *pi_fd = *ppi_fd;
+
+ for( unsigned i = 0; pi_fd[i] != -1; i++ )
+ vlclua_fd_unmap( L, vlclua_fd_get_lua( L, pi_fd[i] ) );
+
+ net_ListenClose( pi_fd );
return 0;
}
int i_count = 0;
while( pi_fd[i_count] != -1 )
- lua_pushinteger( L, pi_fd[i_count++] );
+ lua_pushinteger( L, vlclua_fd_get_lua( L, pi_fd[i_count++] ) );
return i_count;
}
int **ppi_fd = (int**)luaL_checkudata( L, 1, "net_listen" );
int i_fd = net_Accept( p_this, *ppi_fd );
- lua_pushinteger( L, i_fd );
+ lua_pushinteger( L, vlclua_fd_map_safe( L, i_fd ) );
return 1;
}
const char *psz_host = luaL_checkstring( L, 1 );
int i_port = luaL_checkint( L, 2 );
int i_fd = net_Connect( p_this, psz_host, i_port, SOCK_STREAM, IPPROTO_TCP );
- lua_pushinteger( L, i_fd );
+ lua_pushinteger( L, vlclua_fd_map_safe( L, i_fd ) );
return 1;
}
static int vlclua_net_close( lua_State *L )
{
int i_fd = luaL_checkint( L, 1 );
- net_Close( i_fd );
+ vlclua_fd_unmap_safe( L, i_fd );
return 0;
}
size_t i_len;
const char *psz_buffer = luaL_checklstring( L, 2, &i_len );
i_len = luaL_optint( L, 3, i_len );
- i_len = send( i_fd, psz_buffer, i_len, 0 );
+ i_len = send( vlclua_fd_get( L, i_fd ), psz_buffer, i_len, 0 );
lua_pushinteger( L, i_len );
return 1;
}
int i_fd = luaL_checkint( L, 1 );
size_t i_len = luaL_optint( L, 2, 1 );
char psz_buffer[i_len];
- ssize_t i_ret = recv( i_fd, psz_buffer, i_len, 0 );
+ ssize_t i_ret = recv( vlclua_fd_get( L, i_fd ), psz_buffer, i_len, 0 );
if( i_ret > 0 )
lua_pushlstring( L, psz_buffer, i_ret );
else
return 1;
}
+#ifndef _WIN32
/*****************************************************************************
*
*****************************************************************************/
/* Takes a { fd : events } table as first arg and modifies it to { fd : revents } */
static int vlclua_net_poll( lua_State *L )
{
+ vlclua_dtable_t *dt = vlclua_get_dtable( L );
+
luaL_checktype( L, 1, LUA_TTABLE );
- int i_fds = 0;
+ int i_fds = 1;
lua_pushnil( L );
while( lua_next( L, 1 ) )
{
i_fds++;
lua_pop( L, 1 );
}
- struct pollfd *p_fds = malloc( i_fds * sizeof( struct pollfd ) );
- vlc_cleanup_push( free, p_fds );
+
+ struct pollfd *p_fds = xmalloc( i_fds * sizeof( *p_fds ) );
+ int *luafds = xmalloc( i_fds * sizeof( *luafds ) );
+
lua_pushnil( L );
- int i = 0;
+ int i = 1;
+ p_fds[0].fd = dt->fd[0];
+ p_fds[0].events = POLLIN;
while( lua_next( L, 1 ) )
{
- p_fds[i].fd = luaL_checkinteger( L, -2 );
+ luafds[i] = luaL_checkinteger( L, -2 );
+ p_fds[i].fd = vlclua_fd_get( L, luafds[i] );
p_fds[i].events = luaL_checkinteger( L, -1 );
- p_fds[i].revents = 0;
+ p_fds[i].events &= POLLIN | POLLOUT | POLLPRI;
lua_pop( L, 1 );
i++;
}
int i_ret;
do
i_ret = poll( p_fds, i_fds, -1 );
- while( i_ret == -1 );
+ while( i_ret == -1 && errno == EINTR );
- for( i = 0; i < i_fds; i++ )
+ for( i = 1; i < i_fds; i++ )
{
- lua_pushinteger( L, p_fds[i].fd );
+ lua_pushinteger( L, luafds[i] );
lua_pushinteger( L, p_fds[i].revents );
lua_settable( L, 1 );
}
lua_pushinteger( L, i_ret );
- vlc_cleanup_run();
- return 1;
+
+ if( p_fds[0].revents )
+ i_ret = luaL_error( L, "Interrupted." );
+ else
+ i_ret = 1;
+ free( luafds );
+ free( p_fds );
+
+ return i_ret;
}
/*****************************************************************************
ssize_t i_ret;
const char *psz_buffer = luaL_checklstring( L, 2, &i_len );
i_len = luaL_optint( L, 3, i_len );
- i_ret = write( i_fd, psz_buffer, i_len );
+ i_ret = write( vlclua_fd_get( L, i_fd ), psz_buffer, i_len );
lua_pushinteger( L, i_ret );
return 1;
}
int i_fd = luaL_checkint( L, 1 );
size_t i_len = luaL_optint( L, 2, 1 );
char psz_buffer[i_len];
- ssize_t i_ret = read( i_fd, psz_buffer, i_len );
+ ssize_t i_ret = read( vlclua_fd_get( L, i_fd ), psz_buffer, i_len );
if( i_ret > 0 )
lua_pushlstring( L, psz_buffer, i_ret );
else
lua_pushnil( L );
return 1;
}
+#endif
/*****************************************************************************
*
lua_newtable( L );
for( ;; )
{
- char *psz_filename = vlc_readdir( p_dir );
+ const char *psz_filename = vlc_readdir( p_dir );
if( !psz_filename ) break;
i++;
lua_pushstring( L, psz_filename );
lua_rawseti( L, -2, i );
- free( psz_filename );
}
closedir( p_dir );
return 1;
/*****************************************************************************
*
*****************************************************************************/
-static const luaL_Reg vlclua_net_reg[] = {
- { "url_parse", vlclua_url_parse },
+static const luaL_Reg vlclua_net_intf_reg[] = {
{ "listen_tcp", vlclua_net_listen_tcp },
{ "connect_tcp", vlclua_net_connect_tcp },
{ "close", vlclua_net_close },
{ "send", vlclua_net_send },
{ "recv", vlclua_net_recv },
+#ifndef _WIN32
{ "poll", vlclua_net_poll },
{ "read", vlclua_fd_read },
{ "write", vlclua_fd_write },
+#endif
+ /* The following functions do not depend on intf_thread_t and do not really
+ * belong in net.* but are left here for backward compatibility: */
+ { "url_parse", vlclua_url_parse },
+ { "stat", vlclua_stat }, /* Not really "net" */
+ { "opendir", vlclua_opendir }, /* Not really "net" */
+ { NULL, NULL }
+};
+
+static void luaopen_net_intf( lua_State *L )
+{
+ lua_newtable( L );
+ luaL_register( L, NULL, vlclua_net_intf_reg );
+#define ADD_CONSTANT( value ) \
+ lua_pushinteger( L, POLL##value ); \
+ lua_setfield( L, -2, "POLL"#value );
+ ADD_CONSTANT( IN )
+ ADD_CONSTANT( PRI )
+ ADD_CONSTANT( OUT )
+ ADD_CONSTANT( ERR )
+ ADD_CONSTANT( HUP )
+ ADD_CONSTANT( NVAL )
+ lua_setfield( L, -2, "net" );
+}
+
+int vlclua_fd_init( lua_State *L, vlclua_dtable_t *dt )
+{
+#ifndef _WIN32
+ if( vlc_pipe( dt->fd ) )
+ return -1;
+#endif
+ dt->fdv = NULL;
+ dt->fdc = 0;
+ vlclua_set_object( L, vlclua_get_dtable, dt );
+ luaopen_net_intf( L );
+ return 0;
+}
+
+void vlclua_fd_interrupt( vlclua_dtable_t *dt )
+{
+#ifndef _WIN32
+ close( dt->fd[1] );
+ dt->fd[1] = -1;
+#endif
+}
+
+/** Releases all (leaked) VLC Lua file descriptors. */
+void vlclua_fd_cleanup( vlclua_dtable_t *dt )
+{
+ for( unsigned i = 0; i < dt->fdc; i++ )
+ net_Close( dt->fdv[i] );
+ free( dt->fdv );
+#ifndef _WIN32
+ if( dt->fd[1] != -1 )
+ close( dt->fd[1] );
+ close( dt->fd[0] );
+#endif
+}
+
+static const luaL_Reg vlclua_net_generic_reg[] = {
+ { "url_parse", vlclua_url_parse },
{ "stat", vlclua_stat }, /* Not really "net" */
{ "opendir", vlclua_opendir }, /* Not really "net" */
{ NULL, NULL }
};
-void luaopen_net( lua_State *L )
+void luaopen_net_generic( lua_State *L )
{
lua_newtable( L );
- luaL_register( L, NULL, vlclua_net_reg );
-#define ADD_CONSTANT( name, value ) \
- lua_pushinteger( L, value ); \
- lua_setfield( L, -2, name );
- ADD_CONSTANT( "POLLIN", POLLIN )
- ADD_CONSTANT( "POLLPRI", POLLPRI )
- ADD_CONSTANT( "POLLOUT", POLLOUT )
- ADD_CONSTANT( "POLLERR", POLLERR )
- ADD_CONSTANT( "POLLHUP", POLLHUP )
- ADD_CONSTANT( "POLLNVAL", POLLNVAL )
+ luaL_register( L, NULL, vlclua_net_generic_reg );
lua_setfield( L, -2, "net" );
}