Introduction
The Phidget22 Network Protocol is primarily JSON based with a binary header that describes the contents of the JSON.
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.
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.