PureBasic
PureBasic
WebSocket through SSH Tunnel
See more WebSocket Examples
This example shows how to establish a WebSocket connection through an SSH tunnel. The WebSocket protocol communications will be encapsulated within an SSH tunnel.Chilkat PureBasic Downloads
IncludeFile "CkSocket.pb"
IncludeFile "CkRest.pb"
IncludeFile "CkWebSocket.pb"
Procedure ChilkatExample()
success.i = 0
; This example requires the Chilkat API to have been previously unlocked.
; See Global Unlock Sample for sample code.
; --------------------------------------------------
; This example borrows the code from the REST through SSH Tunnel example.
; We first use the Chilkat Socket object to establish a connection to the WebSocket server through an SSH Tunnel.
; Next, the Rest object uses the Socket object for its connection.
; Finally, the WebSocket object uses the Rest object for its connection.
;
; Hopefully the flexibility of this architecture is easy to see. All of the HTTP functionality of the Rest object,
; such as HTTP authentication, custom headers, etc. is available to the WebSocket. Likewise, all of the advanced functionality
; of the Socket object is in turn available to the Rest object.
; The high-level steps for accomplishing the task of running the WebSocket protocol through an SSH accomplished as follows:
; 1) Create the SSH tunnel using Chilkat Socket.
; 2) Open a port-forwarding channel (to the WebSocket server) within the tunnel.
; 2) Tell Rest to use the Socket object.
; 3) Tell WebSocket to use the Rest object.
tunnel.i = CkSocket::ckCreate()
If tunnel.i = 0
Debug "Failed to create object."
ProcedureReturn
EndIf
sshHostname.s = "sftp.example.com"
sshPort.i = 22
; Connect to an SSH server and establish the SSH tunnel:
success = CkSocket::ckSshOpenTunnel(tunnel,sshHostname,sshPort)
If success = 0
Debug CkSocket::ckLastErrorText(tunnel)
CkSocket::ckDispose(tunnel)
ProcedureReturn
EndIf
; Authenticate with the SSH server via a login/password
; or with a public key.
; This example demonstrates SSH password authentication.
success = CkSocket::ckSshAuthenticatePw(tunnel,"mySshLogin","mySshPassword")
If success = 0
Debug CkSocket::ckLastErrorText(tunnel)
CkSocket::ckDispose(tunnel)
ProcedureReturn
EndIf
; OK, the SSH tunnel is setup. Now open a channel within the tunnel.
bTls.i = 1
port.i = 443
maxWaitMs.i = 5000
; This returns a socket object that is a single channel within the SSH tunnel.
; The SSH channel is our logical port-forwarded connection through the SSH tunnel.
; Note: This example establishes a TLS connection to the target WebSocket server.
; (The TLS protocol will run on the logical channel within the SSH tunnel.)
; Your application can just as easily make a non-TLS connection by changing the arguments
; passed to SshNewChannel.
channel.i = CkSocket::ckCreate()
If channel.i = 0
Debug "Failed to create object."
ProcedureReturn
EndIf
success = CkSocket::ckSshNewChannel(tunnel,"some-websocket-server.com",port,bTls,maxWaitMs,channel)
If success = 0
Debug CkSocket::ckLastErrorText(tunnel)
CkSocket::ckDispose(tunnel)
CkSocket::ckDispose(channel)
ProcedureReturn
EndIf
; Create a REST object and tell it to use the SSH channel.
; This connection is a TLS running on an SSH channel through an SSH tunnel.
; In other words, TLS is wrapped within the SSH tunnel.
rest.i = CkRest::ckCreate()
If rest.i = 0
Debug "Failed to create object."
ProcedureReturn
EndIf
success = CkRest::ckUseConnection(rest,channel,0)
If success = 0
Debug CkRest::ckLastErrorText(rest)
CkSocket::ckDispose(tunnel)
CkSocket::ckDispose(channel)
CkRest::ckDispose(rest)
ProcedureReturn
EndIf
; Finally, tell our WebSocket object to use the Rest object..
ws.i = CkWebSocket::ckCreate()
If ws.i = 0
Debug "Failed to create object."
ProcedureReturn
EndIf
; Tell the WebSocket to use this connection.
success = CkWebSocket::ckUseConnection(ws,rest)
If success = 0
Debug CkWebSocket::ckLastErrorText(ws)
CkSocket::ckDispose(tunnel)
CkSocket::ckDispose(channel)
CkRest::ckDispose(rest)
CkWebSocket::ckDispose(ws)
ProcedureReturn
EndIf
; Add the standard WebSocket open handshake headers that will be needed.
; (This adds the required HTTP request headers to the rest object.)
CkWebSocket::ckAddClientHeaders(ws)
; Add any additional headers that might be desired.
; Two common WebSocketSpecific headers are "Sec-WebSocket-Protocol" and "Origin".
CkRest::ckAddHeader(rest,"Sec-WebSocket-Protocol","x-some-websocket-subprotocol")
CkRest::ckAddHeader(rest,"Origin","http://some-websocket-server.com")
; Do the open handshake.
responseBody.s = CkRest::ckFullRequestNoBody(rest,"GET","/something")
If CkRest::ckLastMethodSuccess(rest) = 0
Debug CkRest::ckLastErrorText(rest)
CkSocket::ckDispose(tunnel)
CkSocket::ckDispose(channel)
CkRest::ckDispose(rest)
CkWebSocket::ckDispose(ws)
ProcedureReturn
EndIf
; If successful, the HTTP response status code should be 101,
; and the response body will be empty. (If it failed, we'll have a look
; at the response body..)
statusCode.i = CkRest::ckResponseStatusCode(rest)
Debug "Response status code: " + Str(statusCode)
If statusCode <> 101
Debug responseBody
Debug "-- Failed because of unexpected response status code."
CkSocket::ckDispose(tunnel)
CkSocket::ckDispose(channel)
CkRest::ckDispose(rest)
CkWebSocket::ckDispose(ws)
ProcedureReturn
EndIf
; We have the expected 101 response, so let's now validate the
; contents of the response, such as the value sent by the server in the
; Sec-WebSocket-Accept header.
success = CkWebSocket::ckValidateServerHandshake(ws)
If success = 0
Debug CkWebSocket::ckLastErrorText(ws)
CkSocket::ckDispose(tunnel)
CkSocket::ckDispose(channel)
CkRest::ckDispose(rest)
CkWebSocket::ckDispose(ws)
ProcedureReturn
EndIf
Debug "WebSocket connection successful."
; The application may now begin sending and receiving frames on the WebSocket connection.
; (At this point, we're done with the rest object...)
CkSocket::ckDispose(tunnel)
CkSocket::ckDispose(channel)
CkRest::ckDispose(rest)
CkWebSocket::ckDispose(ws)
ProcedureReturn
EndProcedure