Welcome to the PtokaX Wiki!


This wiki is devoted to let users share information on the great hubsoft PtokaX. However, it is not limited to PtokaX, it is destined to share and discuss information on different parts of the LUA programming language, but the site is NOT intended to be a replacement for the primary LUA Board aka the PtokaX Portal, nor the secondary LUA Board or the PtokaX resources.

If you’re not familiar with wikis then in short: they are user-contributed sites: pages can be edited by (almost) anyone. As such, there is always kind of up-to-date and (hopefully) proper content. They are better than forums, since relevant pieces of information are on the same page. Do not hesitate to share your knowledge, and we all hope you can learn and teach a lot here! — bastya_elvtars



The PtokaX WSA library

This library is obsolete, use luasocket instead.

About

PtokaX WSA lib is a lua extension. You can only use it with Ptokax dchub. However if someone need it for another build of lua i'll maybe consider compileing for that build also. The lib purpose is to provide ptokax lua scripts with a tcp client. To allow simple operations like downloading a version file from a web server to check for script updates, or maybe you want a +whois on your hub. Or maybe you just need to look up hostnames, convert ip addresses to and from dotted format (usefull for ip-ranges). Thesae things are now posible to script in ptokax. In the downloaded package, there is the pxwsa.dll and some sample lua scripts.

Copyright & License

Copyright

  • px_console.exe → Copyright © 2005 Morten Larsen, aka bluebear.
  • pxwsa.dll → Copyright © 2005 Morten Larsen, aka bluebear.
  • manual and sample scripts → Copyright © 2005 Morten Larsen, aka bluebear.
  • Lua → Copyright © 1994-2004 Tecgraf, PUC-Rio.
  • PtokaX DC Hub → Copyright © 2002-2003 Ptaczek, Frontline3k and aMutex.
  • PtokaX DC Hub → Copyright © 2004-2005 Ptaczek and PPK.

License

This license applies to all version of pxwsa.dll, as well as the sample lua scripts and this document.

pxwsa.dll, sample scripts and its documentation is provided as-is, without warranty of any kind, and you're using it at your own risk. I can not be held liable to any party for direct, indirect, special, incidental, or consequential damages arising out of the use of this package and its documentation. I have no obligation to provide maintenance, support, updates, enhancements, or modifications.

You may:

  • use pxwsa.dll and sample scripts for whatever non-profit/non-commercial project.

If you redistribute pxwsa you must credit me and link to my homepage, and you must always have the newest versions available, and not just older versions. And if you discontinue to redistribute the packages, you must clearly state on the page holding the pxwsa.dll package, that you do not keep updates anymore. And advise users to check for newest version on any site that has it's pxwsa archive fully updated. Or you can redirect you discontinued page to http://www.thewildplace.dk/

You may not use pxwsa.dll in any kind of commercial or profit based environment (including religious organizations and educational institutions such as schools and universities) without prior permission from me. If you need such premission, you must find a way to contact me. The best way for that is via email or my site.

System requirements

You must have PtokaX DC Hub >= 0.3.3.21 in order to make the library work. You should put it to the sripts\lib folder. If there is no such folder, create one. :-P

The API

Loading the library

Before you can use the lib you must load it:

libinit = loadlib("pxwsa.dll", "_libinit")
libinit()

Common functions

These functions are independent of the socket type you are planning to use.

WSA.Version()

Returns a string containing the PxWSA.dll version.

WSA.Init()

The function initilaizes WS2_32.DLL. You must call this before calling any other function in the pxwsa.dll lib. Usually this can be done in Main()

Function returns 2 nil if there are no errors. Else it returns an error code and an error string.

Usage
errorCode, errorStr = WSA.Init()
if errorCode then
  -- Could not init
else
   -- Init was a success
end

WSA.Dispose()

The WSA.Dispose() function terminates use of the WS2_32.DLL. You must call this function when you don't want the usage of sockets any more. Usually this can be done in OnExit(). Usage and return values are the same as in WSA.Init. FIXME Is it supposed to deallocate everything?

WSA.NewSocket([socketType [, LingerOpt]])

Creates a new socket.

Function returns 3 variables; 2x error and socket. If there are no errors, the error variables will be returned as nil, and the socket variable will be the socket ID. If there is an error, it will return an errorcode and a string, and the socket variable will be nil.

Socket ID is used for connecting, sending, receiving and disconnecting. Socket IDs allow you to use multiple sockets, each haveing a unique handle.

Arguments
  • SocketType: Specifies the socket type: TCP or UDP. Enter 0 for TCP, any non-zero value for UDP.
  • LingerOpt: FIXME Not coded yet and can not be used

:!: In version 0.0.2 you could only use TCP sockets. Now you can use both TCP and UDP. This changes the WSA.NewSocket function: you now need to specify which protocol you want to use. To ensure backwards compatibility, and not make older scripts broken with this change, the function is overloaded. Meaning you can call it with more than one combination of arguments; without arguments you will get a tcp socket, with one argument you will select the protocol, with 2 arguments you specify the socket type, and the linger option.

Usage
errorCode, errorStr, sock = WSA.NewSocket(0)  -- TCP Socket
  if errorCode then
    -- Could not get a new socket..
  else
    -- New socket was a success
  end

WSA.Close(socketID)

Closes/disconnects an existing socket, you can not use the socket any longer, therefore you will have to create a new one, as WSA.Close causes the socket handle to become deallocated so that the application can no longer reference or use the socket in any manner. In next version you can expect, settings for how to close the socket (Gracefully or Abortive). This will be done when allocateing a new socket with the WSA.NewSocket() function.

The function returns 2 variables. If there were no errors 2 nil is returned, else an error code and a string.

Arguments

* socketID: must be an existant socket created with WSA.NewSocket.

Usage
errorCode, errorStr = WSA.Close(sock)
  if errorCode then
    -- Some error
  else
    -- Socket deallocated :)
  end
end

DNS/IP-related functions

These functions are utilities that make your life easier whaen it comes to hostname lookup or DNS management.

WSA.IPtoDEC(IP)

Converts an IPv4 address to decimal format (i. e. if IP is a.b.c.d then it returns a*16777216+b*65536+c*256+d). Returns nil on failure.

WSA.DECtoIP(DEC)

Converts DEC (an integer number) to an IPv4 address. Returns nil on failure.

WSA.GetHostByName(hostname)

Returns the IP address for a hostname by using a DNS lookup. Ex.: WSA.GetHostByName(“localhost”) returns 127.0.0.1. Returns nil on failure.

WSA.GetHostByAddr()

Gets the hostname belonging to an IP address by doing a reverse DNS lookup. Returns nil on failure.

Synchronous socket functions

These sockets are easier to use in a script, but at the cost of blocking anything else in the hub until the socket operation is finished, so for this time users cannot search/initiate downloads/chat, so it is generally worth the time to use asynchronous sockets (see below) instead.

WSA.Connect(socketID, addr, port)

The WSA.Connect() function establishes a connection using a specified (and existant) socket.

The function returns 2 variables. If there were no errors, 2 nil is returned otherwise it returns an errorcode and string.

Arguments:
  • socketID: an existant socket created with WSA.NewSocket
  • addr: remote IP/hostname
  • port: remote port
Usage
errorCode, errorStr = WSA.Connect(sock, "google.com", 80)
if errorCode then
  -- Could not connect
else
  -- We're connected :)
end

WSA.Send(socketID, stringDataToSend)

Sends data to a connected socket (see WSA.Connect above.) It sends raw data, so you gotta have a good knowledge on the protocol you are trying to use. Returns 3 variables. If there were no errors, 2 nil is returned, otherwise it an errorcode and a string. The third variable returns amount of bytes sent and nil on error.

Notes

This function can only be used when you created socketID for TCP communications.

Arguments
  • socketID: an existant socket created with WSA.NewSocket and connected to with WSA.Connect.
  • stringDataToSend: a string value that is sent to the remote host's specified port
Usage
sData = "I want to transmit this text over a socket"
errorCode, errorStr, bytesSent = WSA.Send(sock, sData)
if errorCode then
  -- Send faild
else
  -- Send completed :)
end

WSA.SendTo(socketID, stringDataToSend, addr, port)

Sends data to a specific destination. Returns 3 variables. If there were no errors, 2 nil is returned otherwise it a errorcode and string. The third variable returns amount of bytes sent and nil on error.

Notes

This is normally used for UDP protocol only. Since UDP is a stateless protocol, the actual state of a socket is unknown. Therefore if you want to send data to a host listening on an UDP port (e. g. DNS query or NETBIOS-DGM service) you have to re-specify the hostname/IP and the port, as the UDP socket is not handled as connected, even if a WSA.Connect has been previously done. For UDP, it is still good to call WSA.Connect in order to determine whether the communication is possible at all, i. e. to 'test' the connection.

For TCP, the last 2 arguments are ignored, but it's mandatory that the socket is connected, therefore this function becomes the same as WSA.Send.

Arguments
  • socketID: see the above notes
  • stringDataToSend: see WSA.Send
  • addr: must be specified, but used by UDP only, remote IP/hostname
  • port: must be specified, but used by UDP only, remote port
Usage
sdata = "I want to transmit this text over a socket"
errorCode, errorStr, bytesSent = WSA.SendTo(sock, sdata, "192.168.1.54", 1024)
if errorCode then
  -- Send was an failure
else
  -- Send completed :)
end

WSA.Receive(socketID)

Receives data from a connected socket. Returns 4 variables, if there were no errors nil is returned to the error variables and the data to the data variable. If there was errors, the error variables will return the errorcode and string, and the data variable will return nil.

Notes

For connectionless sockets, data is extracted from the first enqueued datagram (message) from the destination address specified by the WSA.BeginConnect (see below) / WSA.Connect function. If the datagram or message is larger than the buffer (32K) specified in the pxwsa C code, the buffer is filled with the first part of the datagram, and WSA.BeginReceive (see below) / WSA.Receive generates the error 10040. For unreliable protocols (UDP) the excess data is lost; for reliable protocols (TCP), the data is retained by the service provider until it is successfully read by calling WSA.BeginReceive (see below) / WSA.Receive multiple times. This can easily be achieved by using a while loop (see below).

Arguments
  • socketID: an existant socket created with WSA.NewSocket and (if TCP) connected to with WSA.Connect
Usage

This is one way of usage:

-- by bluebear
errorCode, errorStr, sdata, bytesRead = WSA.Receive(sock)
if errorCode then
  -- Receive was an failure
 if errorCode == 0 then
  -- the connection has been gracefully closed by remotehost.
 else
  -- Receive done - but there can still be data on the socket
 
  -- you need to read.
 end
end

A Complete Example

This is something that gives a better understanding of the functions described above.

ghost="www.thewildplace.dk"
gport=80
gprot=0 -- 0 for TCP, 1 for UDP (mostly it's TCP)
gfile="/lua/wsa/index.html"
 
Msg="" -- an internal 'receive buffer'
_,_,sock=WSA.NewSocket(gprot) -- creating a socket, according to what we have above
errorCode,errorString=WSA.Connect(sock,ghost,gport)
if errorCode then
  -- connection failed
  WSA.Close(sock)
  return 1 
end -- if we cannot connect, no bothering
-- HTTP-specific commend sending
CMD="GET "..gfile.." HTTP/1.1\r\nHost: "..ghost.."\r\nUser-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)\r\n"..string.char(13,10)
WSA.SendTo(sock,CMD,ghost,gport) -- universal for tcp and udp
-- do until receiving finishes or there is too big data (futile for UDP, that's why there is a gprot)
while errorCode==nil or (gprot==0 and errorCode==10040) do
  errorCode, errorStr, sdata, bytesRead = WSA.Receive(sock) -- starting to receive now
  Msg=Msg..sdata -- merge the received data into the internal recv buffer
end
WSA.Close(sock)
 
-- Msg should be used NOW.

Asynchronous socket functions

Allows you to create async calls from your lua script. They work different than the blocking socket methods. An event (luascript function) will be fired when there is for example data ready on a socket. They do not block the code, when something happens, then you are 'ringed back', so you do not have to 'hold on the phone'.

WSA.BeginConnect(socketID, addr, port)

Begins to asynchronously connect a socket to a remote endpoint..

Arguments
  • socketID: an existant socket created with WSA.NewSocket
  • addr: remote IP/hostname
  • port: remote port

If the connection succeeds or fails, it fires the following function:

OnWsaConnected ( errorCode, errorStr, socket )

If there are no errors, the error variables will be returned as nil.

Usage

OnWsaConnected = function ( errorCode, errorStr, socket )
  if errorCode then
      -- Could not connect
  else
      -- We're connected :)
  end
end
WSA.BeginConnect(socket, "localhost", 411) -- we connect to an *existant* socket.

WSA.BeginSend(socketID,data)

The WSA.BeginSend() begins to asynchronously transmit data on a connected socket..

Arguments
  • socketID: an existant socket created with WSA.NewSocket and connected with
  • data: a string value that is sent to the remote host's specified port
OnWsaSendComplete ( errorCode, errorStr, socket, bytesSent )

If there are no errors, the error variables will be returned as nil. And socket, bytesSent will be returned with their respective values. If there is errors only error and socket variables will return useful data. bytesSent will be returned as nil.

Usage
OnWsaSendComplete = function ( errorCode, errorStr, socket, bytesSent )
    if errorCode then
       -- Sending failed
    else
       -- Sent
    end
    return 0
end
 
data = "Transmit this string"
WSA.BeginSend(socket, data)

WSA.BeginReceive(soketID)

Begins to asynchronously receive data from a connected socket.

Notes:

For connectionless sockets, data is extracted from the first enqueued datagram (message) from the destination address specified by the WSA.BeginConnect() / WSA.Connect() function.

For connectionless sockets, data is extracted from the first enqueued datagram (message) from the destination address specified by the WSA.BeginConnect function. If the datagram or message is larger than the buffer (32K) specified in the pxwsa C code, the buffer is filled with the first part of the datagram, and WSA.BeginReceive generates the error 10040. For unreliable protocols (UDP) the excess data is lost; for reliable protocols (TCP), the data is retained by the service provider until it is successfully read by returning 0.

Arguments
  • socketID: an existant socket created with WSA.NewSocket
OnWsaDataArrival ( errorCode, errorStr, socket, sData, bytesRead )

If there are no errors, the error variables will be returned as nil. And socket, sdata, length will be returned with their respective values. If there is errors only error and socket variables will return usefull data, sdata and length will be returned as nil.

Important

Your function must return 0 or 1. If you return 1 (or just any number > 0) the socket will continue to asynchronously receive data. If you return ''0' the socket will not continue receiving data.

OnWsaDataArrival = function ( errorCode, errorStr, socket, sdata, bytesRead )
  local retVal = 0
  if errorCode then
      -- Receive was an failure
    if errorCode == 0 then
      -- the connection has been gracefully closed by remotehost.
      -- You should call the close method now
    else
      -- Error while reading data from socket.
    end
  else
    -- Receive done - but there can still be data on the socket you need to read.
    retVal = 1
  end
  return retVal
end
 
WSA.BeginReceive(socket)

A Complete Example

Many things above sound mysterious, so maybe this example will help you.

ghost="www.thewildplace.dk"
gport=80
gprot=0 -- 0 for TCP, 1 for UDP (mostly it's TCP)
gfile="/lua/wsa/index.html"
 
function OnWsaConnected ( errorCode, errorStr, sock ) -- connection attempt to host finished
  if errorCode then
    -- connection failed
    WSA.Close(sock)
  else -- we are connected.
    local CMD="GET "..gfile.." HTTP/1.1\r\nHost: "..ghost.."\r\nUser-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)\r\n"..string.char(13,10)
    WSA.BeginSend(sock,CMD) -- Sending a request
  end
end
 
function OnWsaSendComplete ( errorCode, errorStr, sock, bytesSent ) -- send attempt finished
  if errorCode then
    -- Sending failed
      WSA.Close(sock)
  else
    -- Sent
    WSA.BeginReceive(sock) -- let's wait for response to request
  end
end
 
function OnWsaDataArrival ( errorCode, errorStr, sock, sdata, bytesRead ) -- response
  -- proper response orjust partial data
  if not errorCode or (errorCode==10040 and prot==0) then
    DataRecv=DataRecv..sdata -- merging to the receive buffer
    return 1 -- telling the thread to continue to receive
  else
    -- do something to the data, as you will not get more. :-)
    DataRecv="" -- empty the internal 'receive buffer'
    return 0 -- tell the lib not to try any longer
  end
end
 
-- empty string, works as the receive buffer
-- it must be global, as if itis created as local OnWsaDataArrival
-- it is flushed every time a new data arrives
DataRecv=""
 
_,_,sock=WSA.NewSocket(gprot) -- creating a socket, according to what we have above
WSA.BeginConnect(sock,ghost,gport) -- try a connection to host

This is all about the WSA lib now, hope we could make you understand it. If not, feel free to initiate some inline discussion as described here.

bluebear & bastya_elvtars


Personal Tools