Phidget22 Network Protocol

From Phidgets Support
Revision as of 15:43, 26 July 2017 by Chad (talk | contribs) (Created page with " =Introduction= The Phidget22 Network Protocol is primarily JSON based with a binary header that describes the contents of the JSON. ==Header== The network request header is...")
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

Introduction

The Phidget22 Network Protocol is primarily JSON based with a binary header that describes the contents of the JSON.

Header

The network request header is a union of a NR_HEADERLEN byte array and the members of the netreq structure. The values are not marshalled in C (except on big endian), and must be handled correctly by light clients.

The header contains a four byte magic, four byte length, two byte flags, two byte request sequence number, two byte reply sequence number, one byte type and a one byte sub-type.

Header Members

Member Size Description
magic 4 used to identify the header and to ensure stream alignment 0x50484930
len 4 indicates the payload length NR_MAXDATALEN
flags 2 flags
NRF_REQUEST 0x0001 The payload is a request
NRF_REPLY 0x0002 The payload is a reply
NRF_EVENT 0x0004 The payload is an event
NRF_USERMASK 0x0F00 Bits reserved for applications
0xF0F8 - Reserved and must not be set
reqseq 2 Request sequence number. Ignored for replies and events.
repseq 2 Reply sequence number (the reqseq the reply is for). Used to route replies to async requests.
type 1 Indicates the packet type, and what the payload should contain
stype 1 Packet sub-type. Further describes the type.

Packet Types

MSG_CONNECT 10 Connection control packet SMSG_AUTHC0 || 10 || Begin authentication request
SMSG_CLOSECONN 1 Close the connection
SMSG_HANDSHAKEC0 10 Connection establishment request
SMSG_HANDSHAKES0 10 Connection establishment reply
SMSG_AUTHS0 10 Begin authentication reply
SMSG_AUTHC1 10 Challenge Response
SMSG_AUTHS1 10 Challenge Response reply
SMSG_DGRAMSTART 20 Data Gram event negotiation
SMSG_DGRAMSTARTOK 21 Data Gram event negotiation reply
MSG_COMMAND 20 Command packet
SMSG_REPLY 40 Request reply
SMSG_KEEPALIVE 41 Keep-alive request
MSG_DEVICE 30 Device or Channel packet
SMSG_DEVATTACH 50 Device was added
SMSG_DEVDETACH 55 Device was removed
SMSG_DEVOPEN 60 Open Device
SMSG_DEVCLOSE 65 Close Device
SMSG_DEVBRIDGEPKT 70 Device specific packet
SMSG_DEVCHANNEL 80 Device channel information (for www clients)

Connection

A connection begins with the client opening a TCP/IP connection to the server and sending the initial packet.

HandShakeC0

The identification packet is MSG_CONNECT.SMSG_HANDSHAKEC0. The playload contains at least the keys type, pmajor, and pminor.

type string the type of the server
pmajor int the major protocol version supported by the client
pminor int the minor protocol version supported by the client
dgram bool Optional if 1 datagram is supported by the client
port int Optional if dgram is true, the UDP port the client is listening on

If type begins with "www", the server will send SMSG_DEVCHANNEL messages to the client; otherwise, the server assumes the client is aware of channels belonging to specific devices.

 HDR(REQUEST, MSG_CONNECT, MSG_HANDSHAKEC0) {
   type: '[www],clienttype',
   pmajor: 2,
   pminor: 1,
   dgram: 1,
   port: <UDP port number>
 }

HandShakeS0

In response, the server will reply with MSG_CONNECT; SMSG_HANDSHAKES0.  The payload will contain at
least 'type', 'pmajor', 'pminor' and 'result'.  The type is a string indicating protocol type of the
server and should only be used for identication on the client. 'pmajor' and 'pminor' indicate the
protocol version supported by the server.  'result' indicates success or failure of the client
handshake request, and will be zero if successful.  If 'result' is not zero, the server has rejected
the request, and the socket will be closed.
HDR(request, MSG_CONNECT, MSG_HANDSHAKES0) {
   type: PHIDGET_NET_PROTOCOL, // phid22device
   pmajor: 2,
   pminor: 1,
   result: 0
}
Once the handshake has completed successfully, authentication begins.  The clients begins by sending
MSG_CONNECT; SMSG_AUTHC0 with a payload containing 'ident' and 'nonceC'.  Ident must be the string
'phidgetclient', and 'nonceC' is a 15 byte random value.  Typical implementations generate a random
array of bytes, calculate the base64 of those bytes and send the first 15 bytes of the base64.
HDR(request, MSG_CONNECT, MSG_AUTHC0) {
   ident: 'phidgetclient',
   nonceC: '0123456789abcde'
}
The server will validate the 'ident', and then send a MSG_CONNECT; SMSG_AUTHS0 command.  The payload
will contain 'srvname', 'nonceC', 'nonceS', 'salt', 'count', and 'result'.  'srvname' is the name of
the server and can be used for informational purposes on the client.  'nonceC' must be 'nonceC' value
sent in the client SMSG_AUTHC0 request.  'nonceS' is a 15 byte random value, and 'salt' is another
15 byte random value.  Both 'nonceS' and 'salt' are typically random numbers base64 encoded and truncated
to 15 bytes.  'count' is always 1, and 'result' indicates the result code of the previous SMSG_AUTHC0
request, and must be zero.
If the server failed to handle the clients SMSG_AUTHC0 request, no response will be sent, and the
server will close the connection.
HDR(request, MSG_CONNECT, MSG_AUTHS0) {
   srvname: 'srvname',
   nonceC: '0123456789abcde',
   nonceS: 'edcba9876543210',
   salt: 'randomsalt00000',
   count: 1,
   result: 0
}
The client handles the SMSG_AUTHS0 request by first validating that the 'nonceC' value in the playload
matches the 'nonceC' value send in the SMSG_AUTHC0 request, and the the 'result' value is zero.
If validation is not successful, the client must close the connection.
A challenge response is calculated on the client by building a string containing the protocol ident,
any password, 'nonceC', 'nonceS' and 'salt'.
challenge = ('phidgetclient' + <passwd> + <nonceC> + <nonceS> + <salt>)
The resulting challenge string must be SHA256 hashed, and base64 encoded.
Finally, the client sends a MSG_CONNECT; SMSG_AUTHC1 request with the playload 'nonceC', 'nonceS', and
'proof'.  'nonceC' must be the 'nonceC' value from the original 'SMSG_AUTHC0 request, and 'nonceS' must
by the 'nonceS' value received in the SMSG_AUTHS0 request.  'proof' is the full length encoded challenge
string.
HDR(request, MSG_CONNECT, MSG_AUTHC1) {
   nonceC: '0123456789abcde',
   nonceS: 'edcba9876543210',
   proof: '<base64 challenge response>'
}
The server handles the SMSG_AUTHC1 request by first validating the 'nonceC' and 'nonceS' values, and
then by validating the challenge response.  If validation is successful, a reply packet is sent with
a result of zero.  If validate is not successful, a reply packet is sent with a result code of
EPHIDGET_ACCESS.
Note that the password used to calculate the challange and response is never transferred, and must be
previously known by both the client and the server.  If no password is required, it must be a zero
length string.
HDR(reply, MSG_COMMAND, SMSG_REPLY) {
   E: <result code>
}
Once authentication is complete, the server will begin delivering events to the client, and the client
may begin sending commands to the server.