Phidget22 Network Protocol: Difference between revisions

From Phidgets Support
(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...")
 
 
(4 intermediate revisions by the same user not shown)
Line 58: Line 58:
     | {{Code|SMSG_AUTHS1}} || 10 || Challenge Response reply
     | {{Code|SMSG_AUTHS1}} || 10 || Challenge Response reply
     |-
     |-
     | {{Code|SMSG_DGRAMSTART}} 20 || Data Gram event negotiation
     | {{Code|SMSG_DGRAMSTART}} || 20 || Data Gram event negotiation
     |-
     |-
     | {{Code|SMSG_DGRAMSTARTOK}} || 21 || Data Gram event negotiation reply
     | {{Code|SMSG_DGRAMSTARTOK}} || 21 || Data Gram event negotiation reply
Line 86: Line 86:
   |}
   |}
|}
|}
 
==Connection==
==Connection==
A connection begins with the client opening a TCP/IP connection to the server and sending the initial packet.
A connection begins with the client opening a TCP/IP connection to the server and sending the initial packet.
Line 107: Line 107:


   HDR(REQUEST, MSG_CONNECT, MSG_HANDSHAKEC0) {
   HDR(REQUEST, MSG_CONNECT, MSG_HANDSHAKEC0) {
     type: '[www],clienttype',
     type: '[www,]clienttype',
     pmajor: 2,
     pmajor: 2,
     pminor: 1,
     pminor: 1,
Line 115: Line 115:


===HandShakeS0===
===HandShakeS0===
In response, the server will reply with MSG_CONNECT; SMSG_HANDSHAKES0.  The payload will contain at
The server will reply to {{Code|MSG_CONNECT}}.{{Code|SMSG_HANDSHAKEC0}} with {{Code|MSG_CONNECT}}.{{Code|SMSG_HANDSHAKES0}}.  The payload must contain at least ''type'', ''pmajor'', ''pminor'' and ''result''.
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
  | type || string || identifies the server type
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
| pmajor || int || the major protocol version supported by the server
  the request, and the socket will be closed.
  |-
  | pminor || int || the minor protocol version supported by the server
  |-
| result || int || result code from the {{Code|SMSG_HANDSHAKEC0}} request
|}


  HDR(request, MSG_CONNECT, MSG_HANDSHAKES0) {
''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 have been closed.
 
  HDR(REQUEST, MSG_CONNECT, MSG_HANDSHAKES0) {
     type: PHIDGET_NET_PROTOCOL, // phid22device
     type: PHIDGET_NET_PROTOCOL, // phid22device
     pmajor: 2,
     pmajor: 2,
Line 129: Line 135:
  }
  }


Once the handshake has completed successfully, authentication begins.  The clients begins by sending
===AuthC0===
  MSG_CONNECT; SMSG_AUTHC0 with a payload containing 'ident' and 'nonceC'.  Ident must be the string
Once the handshake has completed, authentication begins.  The client begins by sending  {{Code|MSG_CONNECT}}.{{Code|SMSG_AUTHC0}} with a payload containing ''ident'' and ''nonceC''.
'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.
{|
  | ident || string || must be '''phidgetclient'''
|-
| nonceC || string(15) || random client nonce
|}
 
''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) {
  HDR(REQUEST, MSG_CONNECT, MSG_AUTHC0) {
     ident: 'phidgetclient',
     ident: 'phidgetclient',
     nonceC: '0123456789abcde'
     nonceC: '0123456789abcde'
  }
  }


The server will validate the 'ident', and then send a MSG_CONNECT; SMSG_AUTHS0 command.  The payload
===AuthS0===
will contain 'srvname', 'nonceC', 'nonceS', 'salt', 'count', and 'result'.  'srvname' is the name of
The server handles a {{Code|SMSG_AUTHC0}} request by validating the 'ident', and then sending a {{Code|MSG_CONNECT}}.{{Code|SMSG_AUTHS0}} command.  The payload will contain ''srvname'', ''nonceC'', ''nonceS'', ''salt'', ''count'', and ''result''.
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 || string || the name of the server
|-
| nonceC || string(15) || the nonce send to the server by the client
|-
| nonceS || string(15) || random server nonce
|-
| salt || string(15) || random server generated salt
|-
| count || int || the number of sha256 rounds (currently 1)
|-
| result || int || the result code for the {{Code|SMSG_AUTHC0}} request
|}
 
If the server failed to handle the clients {{Code|SMSG_AUTHC0}} request, no response will be sent, and the
server will close the connection.
 
  HDR(REQUEST, MSG_CONNECT, MSG_AUTHS0) {
     srvname: 'srvname',
     srvname: 'srvname',
     nonceC: '0123456789abcde',
     nonceC: '0123456789abcde',
Line 158: Line 180:
  }
  }


The client handles the SMSG_AUTHS0 request by first validating that the 'nonceC' value in the playload
===AuthC1===
matches the 'nonceC' value send in the SMSG_AUTHC0 request, and the the 'result' value is zero.
The client handles the {{Code|SMSG_AUTHS0}} reply by first validating that the ''nonceC'' value in the playload matches the ''nonceC'' value that was sent, and that the ''result'' value is zero. If validation is not successful, the client must close the connection.
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,
A challenge response is calculated on the client by building a string containing the protocol ident, any password, ''nonceC'', ''nonceS'' and ''salt''.
any password, 'nonceC', 'nonceS' and 'salt'.


  challenge = ('phidgetclient' + <passwd> + <nonceC> + <nonceS> + <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
The resulting challenge string must be SHA256 hashed count times, and base64 encoded.
'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
The client sends a {{Code|MSG_CONNECT}}.{{Code|SMSG_AUTHC1}} request with the playload ''nonceC'', ''nonceS'', and ''proof''.  ''nonceC'' must be the ''nonceC'' value from the original {{Code|SMSG_AUTHC0}} request, and ''nonceS'' must be the ''nonceS'' value received in the {{Code|SMSG_AUTHS0}} request.  ''proof'' is the full length base64 encoded challenge string.
string.


  HDR(request, MSG_CONNECT, MSG_AUTHC1) {
  HDR(REQUEST, MSG_CONNECT, MSG_AUTHC1) {
     nonceC: '0123456789abcde',
     nonceC: '0123456789abcde',
     nonceS: 'edcba9876543210',
     nonceS: 'edcba9876543210',
Line 179: Line 197:
  }
  }


The server handles the SMSG_AUTHC1 request by first validating the 'nonceC' and 'nonceS' values, and
===AuthS1===
then by validating the challenge response.  If validation is successful, a reply packet is sent with
The server handles the {{Code|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 validation is not successful, a reply packet is sent with a result code of {{Code|EPHIDGET_ACCESS}}.
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
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.
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) {
  HDR(REPLY, MSG_COMMAND, SMSG_REPLY) {
     E: <result code>
     E: <result code>
  }
  }


Once authentication is complete, the server will begin delivering events to the client, and the client
===Completion===
may begin sending commands to the server.
Once authentication is complete, the server will begin delivering events to the client, and the client may begin sending commands to the server.

Latest revision as of 16:03, 26 July 2017

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

The server will reply to MSG_CONNECT.SMSG_HANDSHAKEC0 with MSG_CONNECT.SMSG_HANDSHAKES0. The payload must contain at least type, pmajor, pminor and result.

type string identifies the server type
pmajor int the major protocol version supported by the server
pminor int the minor protocol version supported by the server
result int result code from the SMSG_HANDSHAKEC0 request

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 have been closed.

HDR(REQUEST, MSG_CONNECT, MSG_HANDSHAKES0) {
   type: PHIDGET_NET_PROTOCOL, // phid22device
   pmajor: 2,
   pminor: 1,
   result: 0
}

AuthC0

Once the handshake has completed, authentication begins. The client begins by sending MSG_CONNECT.SMSG_AUTHC0 with a payload containing ident and nonceC.

ident string must be phidgetclient
nonceC string(15) random client nonce

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'
}

AuthS0

The server handles a SMSG_AUTHC0 request by validating the 'ident', and then sending a MSG_CONNECT.SMSG_AUTHS0 command. The payload will contain srvname, nonceC, nonceS, salt, count, and result.

srvname string the name of the server
nonceC string(15) the nonce send to the server by the client
nonceS string(15) random server nonce
salt string(15) random server generated salt
count int the number of sha256 rounds (currently 1)
result int the result code for the SMSG_AUTHC0 request

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
}

AuthC1

The client handles the SMSG_AUTHS0 reply by first validating that the nonceC value in the playload matches the nonceC value that was sent, and that 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 count times, and base64 encoded.

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 be the nonceS value received in the SMSG_AUTHS0 request. proof is the full length base64 encoded challenge string.

HDR(REQUEST, MSG_CONNECT, MSG_AUTHC1) {
   nonceC: '0123456789abcde',
   nonceS: 'edcba9876543210',
   proof: '<base64 challenge response>'
}

AuthS1

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 validation 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>
}

Completion

Once authentication is complete, the server will begin delivering events to the client, and the client may begin sending commands to the server.