shithub: scripts

ref: 2ebee720a8af84e6f1a4d4e390f723526553b5e0
dir: /lib/lua/net.lua/

View raw version
---
-- plan9 network utilities
---

---
-- dial(2)
---
DialAux = {
  new = function(self, proto)
    local o = {}
    setmetatable(o, self)
    self.__index = self
    if proto == nil then
      o.proto = "tcp"
    else
      o.proto = proto
    end
    return o
  end,

  -- connect (compat method)
  connect = function(self, host, port)
    raddr = self.proto.."!"..host.."!"..port

  end,

  -- dial (needs more checks)
  dial = function(self, raddr)
    local cs_fd, clone_fd, data_fd, ctl_fd, proto
    local data_fid, conn_param, clone_path, addr

    if not(self.clone_path) and not(self.addr) then
      cs_fd = io.open("/net/cs", "r+")

      if not(cs_fd) then
        return false, "unable to open cs file"
      end

      cs_fd:write(raddr)
      cs_fd:seek("set")
      conn_param = cs_fd:read("a")
      cs_fd:close()

      self.clone_path = string.sub(conn_param, 0, string.find(conn_param, " ") - 1)
      self.addr = string.sub(conn_param, string.find(conn_param, " ") + 1)
    end

    clone_path = self.clone_path
    addr = self.addr

    clone_fd = io.open(clone_path, "r+")
    if not(cs_fd) then
      return false, "unable to open clone file"
    end

    data_fid = clone_fd:read()
    clone_fd:seek("set")
    local n = clone_fd:write("connect "..addr.."\n")
    clone_fd:flush()

    data_fdin = io.open("/net/"..proto.."/"..data_fid.."/data", "r+")
    data_fdout = io.open("/net/"..proto.."/"..data_fid.."/data", "a+")

    if not(data_fdin) then
      return false, "unable to open data"
    end

    self.data_fdin = data_fdin
    self.data_fdout = data_fdout
    self.clone_fd = clone_fd

    return true, nil
  end,

  -- close connection and file descriptors
  close = function(self)
    self.data_fdin:close()
    self.data_fdout:close()
    self.clone_fd:write("close\n")
	self.clone_fd:close()

    self.data_fdin = nil
    self.data_fdout = nil
    self.clone_fd = nil
  end,

  -- dummy compat function
  set_timeout = function(self, t)
    self.timeout = t
  end,

  -- send data
  send = function(self, d)
--    self.data_fdout:seek("set")
    local fd = self.data_fdout:write(d)
    self.data_fdout:flush()
    if fd == nil then
      return false, "connection dropped"
    end
    return true, d
  end,

  -- receive data
  receive_bytes = function(self, sz)
    if sz == nil then
      sz = SOCKET_MAXSZ
    end
    local data = self.data_fdin:read(sz)
    if not(data) then
      return false, "eof"
    end
    return true, data
  end,

  -- receive all
  receive_all = function(self)
    local data = self.data_fdin:read("a")
    if not(data) then
      return false, "eof"
    end
    return true, data
  end,
}

---
-- webfs(4) client
---
WebfsRequest = {
  new = function(self, mtpt)
    local o = {}
    setmetatable(o, self)
    self.__index = self
    if mtpt == nil then
      o.mtpt = "/mnt/web"
    else
      o.mtpt = mtpt
    end
    return o
  end,

  open = function(self)
    local clone_fd
    local web_fid, clone_path

    clone_path=self.mtpt.."/clone"
    clone_fd = io.open(clone_path, "r+")
    if not(clone_fd) then
      return false, "unable to clone"
    end

    web_fid = clone_fd:read()
    clone_fd:seek("set")

    self.clone_fd = clone_fd
    self.web_fid = web_fid

    return true, nil
  end,

  set_param = function(self, paramname, paramval)
--    self.clone_fd:seek("set")
    self.clone_fd:write(paramname.." "..paramval.."\n")
    self.clone_fd:flush()
  end,

  read_body = function(self)
    local body_fd, status, buf

    body_fd = io.open(self.mtpt.."/"..self.web_fid.."/body", "r")
    if not(body_fd) then
       return false, "body cannot be opened"
    end

    status, buf = body_fd:read("a")
    body_fd:close()

    return status, buf
  end,

  post_body = function(self, body)
    local body_fd, status, buf

    body_fd = io.open(self.mtpt.."/"..self.web_fid.."/postbody", "w")
    if not(body_fd) then
       return false, "body cannot be opened"
    end

    status, buf = body_fd:write("a")
    body_fd:close()

    return status, buf
  end,

  close = function(self)
    self.clone_fd:close()
  end,

}

Webfs = {
  new = function(self, mtpt)
    local o = {}
    setmetatable(o, self)
    self.__index = self
    if mtpt == nil then
      o.mtpt = "/mnt/web"
    else
      o.mtpt = mtpt
    end
    return o
  end,

  get = function(self, url, headers)
    local request, status, data
    if not(headers) then
      headers = {}
    end

    request = WebfsRequest:new(self.mtpt)
    status, data = request:open()
    if not(status) then
      return status, data
    end

    request:set_param("url", url)
    for hdrname,hdrval in pairs(headers) do
      request:set_param("headers", string.format("%s: %s", hdrname, hdrval))
    end

    status, data = request:read_body()
    request:close()
    return status, data
  end,

  post = function(self, url, body, contenttype, headers)
    local request, status, data
    if not(headers) then
      headers = {}
    end

    request = WebfsRequest:new(self.mtpt)
    status, data = request:open()
    if not(status) then
      return status, data
    end

    request:set_param("url", url)
    request:set_param("request", "POST")
    for k,header in pairs(headers) do
      request:set_param("headers", header)
    end
    if contenttype then
      request:set_param("contenttype", contenttype)
    end

    status, data = request:post_body(body)
    if not(status) then
      request:close()
      return status, data
    end

    status, data = request:read_body()
    request:close()
    return status, data
  end,
}

local net = {
  DialAux = DialAux,
  Socket = DialAux,		-- nmap/unix compat (someday)
  WebfsRequest = WebfsRequest,
  Webfs = Webfs,
}

return net