]> git.sesse.net Git - vlc/blobdiff - share/lua/intf/modules/host.lua
*.lua: handle recv() returning nil
[vlc] / share / lua / intf / modules / host.lua
index 4601b253c8d4dd9540f13317fc450b03035c3fb1..8b52e0bf08508efca86d6f588edff54255c8cae7 100644 (file)
@@ -52,6 +52,7 @@ Example use:
         -- handle clients in read mode
         for _, client in pairs(read) do
             local str = client:recv(1000)
+            if not str then break end
             str = string.gsub(str,"\r?\n$","")
             client.buffer = "Got `"..str.."'.\r\n"
             client:switch_status( host.status.write )
@@ -64,7 +65,11 @@ For complete examples see existing VLC Lua interface modules (ie telnet.lua)
 module("host",package.seeall)
 
 status = { init = 0, read = 1, write = 2, password = 3 }
-client_type = { net = 1, stdio = 2, fifo = 3 }
+client_type = { net = 1, stdio = 2, fifo = 3, telnet = 4 }
+
+function is_flag_set(val, flag)
+    return (((val - (val % flag)) / flag) % 2 ~= 0)
+end
 
 function host()
     -- private data
@@ -116,7 +121,8 @@ function host()
         end
         for i, c in pairs(clients) do
             if c == client then
-                if client.type == client_type.net then
+                if client.type == client_type.net
+                or client.type == client_type.telnet then
                     if client.wfd ~= client.rfd then
                         vlc.net.close( client.rfd )
                     end
@@ -128,7 +134,7 @@ function host()
         end
         vlc.msg.err("couldn't find client to remove.")
     end
-    
+
     local function switch_status( client, s )
         if client.status == s then return end
         client.status = s
@@ -145,7 +151,7 @@ function host()
     local function new_client( h, fd, wfd, t )
         if fd < 0 then return end
         local w, r
-        if t == client_type.net then
+        if t == client_type.net or t == client_type.telnet then
             w = send
             r = recv
         else if t == client_type.stdio or t == client_type.fifo then
@@ -175,7 +181,7 @@ function host()
     end
 
     -- public methods
-    local function _listen_tcp( h, host, port )
+    local function _listen_tcp( h, host, port, telnet )
         if listeners.tcp and listeners.tcp[host]
                          and listeners.tcp[host][port] then
             error("Already listening on tcp host `"..host..":"..tostring(port).."'")
@@ -186,19 +192,19 @@ function host()
         if not listeners.tcp[host] then
             listeners.tcp[host] = {}
         end
-        local listener = vlc.net.listen_tcp( host, port )
-        listeners.tcp[host][port] = listener
+        listeners.tcp[host][port] = true
         if not listeners.tcp.list then
             -- FIXME: if host == "list" we'll have a problem
             listeners.tcp.list = {}
-            local m = { __mode = "v" } -- week values
-            setmetatable( listeners.tcp.list, m )
         end
-        table.insert( listeners.tcp.list, listener )
+        local listener = vlc.net.listen_tcp( host, port )
+        local type = telnet and client_type.telnet or client_type.net;
+        table.insert( listeners.tcp.list, { data = listener,
+                                            type = type,
+                                          } )
     end
 
     local function _listen_stdio( h )
-        
         if listeners.stdio then
             error("Already listening on stdio")
         end
@@ -217,7 +223,7 @@ function host()
                 h:listen_stdio()
             else
                 u = vlc.net.url_parse( url )
-                h:listen_tcp( u.host, u.port )
+                h:listen_tcp( u.host, u.port, (u.protocol == "telnet") )
             end
         end
     end
@@ -237,7 +243,7 @@ function host()
         filter_client( pollfds, status.write, vlc.net.POLLOUT )
         if listeners.tcp then
             for _, listener in pairs(listeners.tcp.list) do
-                for _, fd in pairs({listener:fds()}) do
+                for _, fd in pairs({listener.data:fds()}) do
                     pollfds[fd] = vlc.net.POLLIN
                 end
             end
@@ -248,19 +254,22 @@ function host()
         local rclients = {}
         if ret > 0 then
             for _, client in pairs(clients) do
-                if pollfds[client:fd()] == vlc.net.POLLOUT then
+                if is_flag_set(pollfds[client:fd()], vlc.net.POLLERR)
+                or is_flag_set(pollfds[client:fd()], vlc.net.POLLHUP)
+                or is_flag_set(pollfds[client:fd()], vlc.net.POLLNVAL) then
+                    del_client(client)
+                elseif is_flag_set(pollfds[client:fd()], vlc.net.POLLOUT) then
                     table.insert(wclients,client)
-                end
-                if pollfds[client:fd()] == vlc.net.POLLIN then
+                elseif is_flag_set(pollfds[client:fd()], vlc.net.POLLIN) then
                     table.insert(rclients,client)
                 end
             end
             if listeners.tcp then
                 for _, listener in pairs(listeners.tcp.list) do
-                    for _, fd in pairs({listener:fds()}) do
-                        if pollfds[fd] == vlc.net.POLLIN then
-                            local afd = listener:accept()
-                            new_client( h, afd, afd, client_type.net )
+                    for _, fd in pairs({listener.data:fds()}) do
+                        if is_flag_set(pollfds[fd], vlc.net.POLLIN) then
+                            local afd = listener.data:accept()
+                            new_client( h, afd, afd, listener.type )
                             break
                         end
                     end
@@ -271,11 +280,13 @@ function host()
         return wclients, rclients
     end
 
+    -- FIXME: this is never called, client sockets are leaked
     local function destructor( h )
         print "destructor"
         for _,client in pairs(clients) do
-            client:send("Shutting down.")
-            if client.type == client_type.tcp then
+            --client:send("Shutting down.")
+            if client.type == client_type.net
+            or client.type == client_type.telnet then
                 if client.wfd ~= client.rfd then
                     vlc.net.close(client.rfd)
                 end
@@ -301,14 +312,5 @@ function host()
                 broadcast = _broadcast,
               }
 
-    -- the metatable
-    local m = { -- data
-                __metatable = "Nothing to see here. Move along.",
-                -- methods
-                __gc = destructor,
-              }
-
-    setmetatable( h, m )
-
     return h
 end