docs » hs.socket

Talk to custom protocols using asynchronous TCP sockets

For UDP sockets see hs.socket.udp

hs.socket is implemented with CocoaAsyncSocket. CocoaAsyncSocket's tagging features provide a handy way to implement custom protocols.

For example, you can easily implement a basic HTTP client as follows (though using hs.http is recommended for the real world):

local TAG_HTTP_HEADER, TAG_HTTP_CONTENT = 1, 2
local body = ""
local function httpCallback(data, tag)
  if tag == TAG_HTTP_HEADER then
    print(tag, "TAG_HTTP_HEADER"); print(data)
    local contentLength = data:match("\r\nContent%-Length: (%d+)\r\n")
    client:read(tonumber(contentLength), TAG_HTTP_CONTENT)
  elseif tag == TAG_HTTP_CONTENT then
    print(tag, "TAG_HTTP_CONTENT"); print(data)
    body = data
  end
end

client = hs.socket.new(httpCallback):connect("google.com", 80)
client:write("GET /index.html HTTP/1.0\r\nHost: google.com\r\n\r\n")
client:read("\r\n\r\n", TAG_HTTP_HEADER)

Resulting in the following console output (adjust log verbosity with hs.socket.setLogLevel()) :

            LuaSkin: (secondary thread): TCP socket connected
            LuaSkin: (secondary thread): Data written to TCP socket
            LuaSkin: (secondary thread): Data read from TCP socket
1 TAG_HTTP_HEADER
HTTP/1.0 301 Moved Permanently
Location: http://www.google.com/index.html
Content-Type: text/html; charset=UTF-8
Date: Thu, 03 Mar 2016 08:38:02 GMT
Expires: Sat, 02 Apr 2016 08:38:02 GMT
Cache-Control: public, max-age=2592000
Server: gws
Content-Length: 229
X-XSS-Protection: 1; mode=block
X-Frame-Options: SAMEORIGIN

            LuaSkin: (secondary thread): Data read from TCP socket
2 TAG_HTTP_CONTENT
<HTML><HEAD><meta http-equiv="content-type" content="text/html;charset=utf-8">
<TITLE>301 Moved</TITLE></HEAD><BODY>
<H1>301 Moved</H1>
The document has moved
<A HREF="http://www.google.com/index.html">here</A>.
</BODY></HTML>
            LuaSkin: (secondary thread): TCP socket disconnected Socket closed by remote peer

API Overview

API Documentation

Variables

timeout
Signature hs.socket.timeout
Type Variable
Description

Timeout for the socket operations, in seconds. New hs.socket objects will be created with this timeout value, but can individually change it with the setTimeout method

If the timeout value is negative, the operations will not use a timeout. The default value is -1

Functions

parseAddress
Signature hs.socket.parseAddress(sockaddr) -> table or nil
Type Function
Description

Parses a binary socket address structure into a readable table

Parameters:

Returns:

  • A table describing the address with the following keys or nil:
    • host - A string containing the host IP
    • port - A number containing the port
    • addressFamily - A number containing the address family

Notes:

  • Some address family definitions from <sys/socket.h>:
address family number description
AF_UNSPEC 0 unspecified
AF_UNIX 1 local to host (pipes)
AF_LOCAL AF_UNIX backward compatibility
AF_INET 2 internetwork: UDP, TCP, etc.
AF_NS 6 XEROX NS protocols
AF_CCITT 10 CCITT protocols, X.25 etc
AF_APPLETALK 16 Apple Talk
AF_ROUTE 17 Internal Routing Protocol
AF_LINK 18 Link layer interface
AF_INET6 30 IPv6

Constructors

new
Signature hs.socket.new([fn]) -> hs.socket object
Type Constructor
Description

Creates an unconnected asynchronous TCP socket object

Parameters:

  • fn - An optional callback function for reading data from the socket, settable here for convenience

Returns:

server
Signature hs.socket.server(port|path[, fn]) -> hs.socket object
Type Constructor
Description

Creates and binds an hs.socket instance to a port or path (Unix domain socket) for listening

Parameters:

  • port - A port number [0-65535]. Ports [1-1023] are privileged. Port 0 allows the OS to select any available port
  • path - A string containing the path to the Unix domain socket
  • fn - An optional callback function for reading data from the socket, settable here for convenience

Returns:

Methods

connect
Signature hs.socket:connect({host, port}|path[, fn]) -> self or nil
Type Method
Description

Connects an unconnected hs.socket instance

Parameters:

  • host - A string containing the hostname or IP address
  • port - A port number [1-65535]
  • path - A string containing the path to the Unix domain socket
  • fn - An optional single-use callback function to execute after establishing the connection. Receives no parameters

Returns:

  • The hs.socket object or nil if an error occurred

Notes:

  • Either a host/port pair OR a Unix domain socket path must be supplied. If no port is passed, the first param is assumed to be a path to the socket file
connected
Signature hs.socket:connected() -> bool
Type Method
Description

Returns the connection status of the hs.socket instance

Parameters:

  • None

Returns:

  • true if connected, otherwise false
connections
Signature hs.socket:connections() -> number
Type Method
Description

Returns the number of connections to the socket, which is at most 1 for default (non-listening) sockets

Parameters:

  • None

Returns:

  • The number of connections to the socket
disconnect
Signature hs.socket:disconnect() -> self
Type Method
Description

Disconnects the hs.socket instance, freeing it for reuse

Parameters:

  • None

Returns:

Notes:

  • If called on a listening socket with multiple connections, each client is disconnected
info
Signature hs.socket:info() -> table
Type Method
Description

Returns information on the hs.socket instance

Parameters:

  • None

Returns:

  • A table containing the following keys:
    • connectedAddress - string (sockaddr struct)
    • connectedHost - string
    • connectedPort - number
    • connectedURL - string
    • connections - number
    • isConnected - boolean
    • isDisconnected - boolean
    • isIPv4 - boolean
    • isIPv4Enabled - boolean
    • isIPv4PreferredOverIPv6 - boolean
    • isIPv6 - boolean
    • isIPv6Enabled - boolean
    • isSecure - boolean
    • localAddress - string (sockaddr struct)
    • localHost - string
    • localPort - number
    • timeout - number
    • unixSocketPath - string
    • userData - string
listen
Signature hs.socket:listen(port|path) -> self or nil
Type Method
Description

Binds an unconnected hs.socket instance to a port or path (Unix domain socket) for listening

Parameters:

  • port - A port number [0-65535]. Ports [1-1023] are privileged. Port 0 allows the OS to select any available port
  • path - A string containing the path to the Unix domain socket

Returns:

  • The hs.socket object or nil if an error occurred
read
Signature hs.socket:read(delimiter[, tag]) -> self or nil
Type Method
Description

Read data from the socket. Results are passed to the callback function, which must be set to use this method

Parameters:

  • delimiter - Either a number of bytes to read, or a string delimiter such as "\n" or "\r\n". Data is read up to and including the delimiter
  • tag - An optional integer to assist with labeling reads. It is passed to the callback to assist with implementing state machines for processing complex protocols

Returns:

  • The hs.socket object or nil if an error occured

Notes:

  • If called on a listening socket with multiple connections, data is read from each of them
receive
Signature hs.socket:receive(delimiter[, tag]) -> self
Type Method
Description

Alias for hs.socket:read

send
Signature hs.socket:send(message[, tag]) -> self
Type Method
Description

Alias for hs.socket:write

setCallback
Signature hs.socket:setCallback([fn]) -> self
Type Method
Description

Sets the read callback for the hs.socket instance. Must be set to read data from the socket

The callback receives 2 parameters:

  • data - The data read from the socket as a string
  • tag - The integer tag associated with the read call, which defaults to -1

Parameters:

  • fn - An optional callback function to process data read from the socket. nil or no argument clears the callback

Returns:

setTimeout
Signature hs.socket:setTimeout(timeout) -> self
Type Method
Description

Sets the timeout for the socket operations. If the timeout value is negative, the operations will not use a timeout, which is the default

Parameters:

  • timeout - A number containing the timeout duration, in seconds

Returns:

startTLS
Signature hs.socket:startTLS([verify][, peerName]) -> self
Type Method
Description

Secures the socket with TLS. The socket will disconnect immediately if TLS negotiation fails

Parameters:

  • verify - An optional boolean that, if false, allows TLS handshaking with servers with self-signed certificates and does not evaluate the chain of trust. Defaults to true and omitted if peerName is supplied
  • peerName - An optional string containing the fully qualified domain name of the peer to validate against — for example, store.apple.com. It should match the name in the X.509 certificate given by the remote party. See notes below

Returns:

Notes:

  • IMPORTANT SECURITY NOTE: The default settings will check to make sure the remote party's certificate is signed by a trusted 3rd party certificate agency (e.g. verisign) and that the certificate is not expired. However it will not verify the name on the certificate unless you give it a name to verify against via peerName. The security implications of this are important to understand. Imagine you are attempting to create a secure connection to MySecureServer.com, but your socket gets directed to MaliciousServer.com because of a hacked DNS server. If you simply use the default settings, and MaliciousServer.com has a valid certificate, the default settings will not detect any problems since the certificate is valid. To properly secure your connection in this particular scenario you should set peerName to "MySecureServer.com".
write
Signature hs.socket:write(message[, tag][, fn]) -> self
Type Method
Description

Write data to the socket

Parameters:

  • message - A string containing data to be sent on the socket
  • tag - An optional integer to assist with labeling writes
  • fn - An optional single-use callback function to execute after writing data to the socket. Receives the tag parameter

Returns:

Notes:

  • If called on a listening socket with multiple connections, data is broadcasted to all connected sockets