EIPC Developer Documentation v0.1.0
Inter-process communication protocol for EmbeddedOS components. Length-prefixed binary framing with JSON payloads, HMAC-SHA256 authentication, and transport over TCP or Unix sockets. C SDK header: <eipc.h>. Go server in eipc/server/.
📦 Wire Format
EIPC Frame Layout
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Frame Length (4 bytes) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Version | Type | Flags (2 bytes) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Sequence Number (4 bytes) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Header Length (2 bytes) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| JSON Header (variable) |
| ... |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Payload Length (4 bytes) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| JSON Payload (variable) |
| ... |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| HMAC-SHA256 (32 bytes, optional) |
| ... |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Field | Size | Description |
| Frame Length | 4 bytes | Total frame size (big-endian, excludes this field). |
| Version | 1 byte | Protocol version (currently 1). |
| Type | 1 byte | 0=Intent, 1=Ack, 2=ToolRequest, 3=ToolResult, 4=Heartbeat, 5=Error. |
| Flags | 2 bytes | Bit 0: HMAC present, Bit 1: compressed, Bit 2: encrypted. |
| Sequence | 4 bytes | Monotonic sequence number for ordering. |
| Header JSON | variable | JSON object: service_id, request_id, timestamp, source. |
| Payload JSON | variable | Message-type-specific JSON payload. |
| HMAC | 32 bytes | HMAC-SHA256 over version+type+flags+seq+header+payload (if flag set). |
📦 Frame Codec API
Encode/decode EIPC frames. Header: <eipc.h>
eipc_status_t eipc_frame_encode(const eipc_frame_t *frame, uint8_t *buf, size_t buf_size, size_t *out_len)Encode an EIPC frame into a byte buffer for transmission. Serializes header JSON, payload JSON, and optionally appends HMAC.
Parameters
frame | const eipc_frame_t * | Frame to encode. |
buf | uint8_t * | Output buffer. |
buf_size | size_t | Buffer capacity. |
out_len | size_t * | Actual encoded length written. |
Returns
EIPC_OK on success. EIPC_ERR_BUFFER if buffer too small. EIPC_ERR_INVALID on bad frame data.
eipc_status_t eipc_frame_decode(const uint8_t *buf, size_t buf_len, eipc_frame_t *frame)Decode a byte buffer into an EIPC frame. Parses header JSON, payload JSON, and validates HMAC if present.
Parameters
buf | const uint8_t * | Input buffer. |
buf_len | size_t | Buffer length. |
frame | eipc_frame_t * | Output frame. |
Returns
EIPC_OK on success. EIPC_ERR_PARSE on malformed data. EIPC_ERR_HMAC if HMAC verification fails.
🔒 HMAC Security
HMAC-SHA256 message authentication for frame integrity and authenticity.
void eipc_hmac_sign(const uint8_t *key, size_t key_len, const uint8_t *data, size_t data_len, uint8_t mac[32])Compute HMAC-SHA256 over the signable portion of a frame. The signable bytes include version, type, flags, sequence, header JSON, and payload JSON (excludes frame length and the MAC field itself).
Parameters
key | const uint8_t * | HMAC key (recommended: 32+ bytes). |
key_len | size_t | Key length in bytes. |
data | const uint8_t * | Data to sign (from eipc_frame_signable_bytes). |
data_len | size_t | Data length. |
mac | uint8_t[32] | Output: 32-byte HMAC. |
Example
const uint8_t key[] = "my-secret-hmac-key-at-least-32-bytes!!";
uint8_t signable[4096];
size_t sig_len = eipc_frame_signable_bytes(&frame, signable, sizeof(signable));
uint8_t mac[32];
eipc_hmac_sign(key, strlen((char*)key), signable, sig_len, mac);
memcpy(frame.hmac, mac, 32);
frame.flags |= EIPC_FLAG_HMAC;bool eipc_hmac_verify(const uint8_t *key, size_t key_len, const uint8_t *data, size_t data_len, const uint8_t mac[32])Verify HMAC-SHA256. Returns true if the computed MAC matches the provided MAC (constant-time comparison).
Parameters
key/key_len | uint8_t*/size_t | HMAC key. |
data/data_len | uint8_t*/size_t | Signed data. |
mac | uint8_t[32] | MAC to verify against. |
Returns
true if valid. false if mismatch.
🔌 Transport API
TCP and Unix socket transport with length-prefixed framing.
eipc_status_t eipc_transport_connect(eipc_socket_t *sock, const char *address)Connect to an EIPC server. Address format: "tcp://host:port" or "unix:///path/to/socket".
Parameters
sock | eipc_socket_t * | Output socket handle. |
address | const char * | Server address. |
Returns
EIPC_OK on success. EIPC_ERR_CONNECT on failure. EIPC_ERR_RESOLVE if hostname unresolvable.
eipc_status_t eipc_transport_listen(eipc_socket_t *sock, const char *address)Bind and listen on an address for incoming EIPC connections.
Parameters
sock | eipc_socket_t * | Output listening socket. |
address | const char * | Bind address (e.g., "tcp://0.0.0.0:8421"). |
Returns
EIPC_OK on success.
eipc_status_t eipc_transport_accept(eipc_socket_t listen_sock, eipc_socket_t *client_sock, char *remote_addr, size_t remote_addr_size)Accept a new client connection. Blocking call that returns when a client connects.
Parameters
listen_sock | eipc_socket_t | Listening socket from eipc_transport_listen. |
client_sock | eipc_socket_t * | Output client socket. |
remote_addr | char * | Output remote address string (can be NULL). |
remote_addr_size | size_t | Buffer size for remote_addr. |
Returns
EIPC_OK on success.
eipc_status_t eipc_transport_send_frame(eipc_socket_t sock, const eipc_frame_t *frame) / eipc_transport_recv_frame(eipc_socket_t sock, eipc_frame_t *frame)Send or receive a complete EIPC frame over a socket. Handles length-prefix framing automatically. recv_frame blocks until a complete frame is received.
Parameters
sock | eipc_socket_t | Connected socket. |
frame | eipc_frame_t * | Frame to send or output frame buffer. |
Returns
EIPC_OK on success. EIPC_ERR_IO on network error. EIPC_ERR_CLOSED if peer disconnected.
void eipc_transport_close(eipc_socket_t sock)Close a socket and free associated resources.
💻 Client API
High-level client for sending intents, tool requests, and heartbeats.
eipc_status_t eipc_client_init(eipc_client_t *c, const char *service_id)Initialize a client with a service identifier. The service_id is included in all message headers for routing.
Parameters
c | eipc_client_t * | Client to initialize. |
service_id | const char * | Service identifier (e.g., "eni-provider-1", "eai-agent"). |
Returns
EIPC_OK on success.
eipc_status_t eipc_client_connect(eipc_client_t *c, const char *address, const char *hmac_key)Connect to an EIPC server with optional HMAC authentication. If hmac_key is non-NULL, all subsequent messages are HMAC-signed.
Parameters
c | eipc_client_t * | Initialized client. |
address | const char * | Server address (e.g., "tcp://192.168.1.100:8421"). |
hmac_key | const char * | HMAC key (NULL to disable signing). |
Returns
EIPC_OK on success. EIPC_ERR_CONNECT on failure.
eipc_status_t eipc_client_send_intent(eipc_client_t *c, const char *intent, float confidence)Send a decoded intent event to the server. Used by ENI providers to forward neural intents.
Parameters
c | eipc_client_t * | Connected client. |
intent | const char * | Intent name. |
confidence | float | Confidence score 0.0-1.0. |
Returns
EIPC_OK on success.
eipc_status_t eipc_client_send_tool_request(eipc_client_t *c, const char *tool, const eipc_kv_t *args, int arg_count)Send a tool execution request to the server. The server routes to the appropriate tool handler.
Parameters
c | eipc_client_t * | Connected client. |
tool | const char * | Tool name. |
args | const eipc_kv_t * | Key-value argument pairs. |
arg_count | int | Number of arguments. |
Returns
EIPC_OK on success.
eipc_status_t eipc_client_send_heartbeat(eipc_client_t *c) / eipc_client_receive(eipc_client_t *c, eipc_message_t *msg) / eipc_client_close(eipc_client_t *c)send_heartbeat: Send keepalive. receive: Blocking receive of next message. close: Disconnect and free resources.
🌐 Server API
eipc_status_t eipc_server_init(eipc_server_t *s) / eipc_server_listen(eipc_server_t *s, const char *address, const char *hmac_key)Initialize and start listening for connections. HMAC key enables mandatory authentication for all clients.
eipc_status_t eipc_server_accept(eipc_server_t *s, eipc_conn_t *conn)Accept a client connection. Blocking call.
Parameters
s | eipc_server_t * | Listening server. |
conn | eipc_conn_t * | Output connection handle. |
Returns
EIPC_OK on success.
eipc_status_t eipc_server_receive(eipc_conn_t *conn, eipc_message_t *msg) / eipc_server_send_ack(eipc_conn_t *conn, const char *request_id, const char *status) / eipc_server_send_message(eipc_conn_t *conn, const eipc_message_t *msg)receive: Read next message from client. send_ack: Send acknowledgment with request_id and status. send_message: Send arbitrary message to client.
📄 JSON Helpers
eipc_status_t eipc_header_to_json/eipc_header_from_json / eipc_intent_to_json/eipc_intent_from_json / eipc_ack_to_json/eipc_ack_from_json / eipc_tool_request_to_json / eipc_heartbeat_to_jsonSerialize/deserialize EIPC header, intent, ack, tool request, and heartbeat structures to/from JSON strings. Minimal JSON implementation with no external dependencies.
Intent JSON Format
// eipc_intent_to_json output:
{
"intent": "move_cursor_left",
"confidence": 0.92,
"source": "neuralink_n1",
"timestamp": "2026-03-31T01:30:00Z"
}
// eipc_ack_to_json output:
{
"request_id": "req-abc123",
"status": "ok",
"timestamp": "2026-03-31T01:30:00Z"
}
// eipc_tool_request_to_json output:
{
"tool": "gpio_write",
"args": {"pin": "12", "value": "true"},
"request_id": "req-def456"
}💻 Go Server/Client Examples
Go Server
package main
import (
"fmt"
"github.com/embeddedos-org/eipc/server"
)
func main() {
srv := server.New(server.Config{
Address: "tcp://0.0.0.0:8421",
HMACKey: "my-secret-key-32-bytes-minimum!!",
})
srv.OnIntent(func(conn *server.Conn, intent string, confidence float64) {
fmt.Printf("[%s] Intent: %s (%.0f%%)\n", conn.ServiceID, intent, confidence*100)
conn.SendAck(conn.LastRequestID(), "ok")
})
srv.OnToolRequest(func(conn *server.Conn, tool string, args map[string]string) {
fmt.Printf("[%s] Tool: %s args=%v\n", conn.ServiceID, tool, args)
result := executeLocalTool(tool, args)
conn.SendMessage(server.ToolResult{
RequestID: conn.LastRequestID(),
Result: result,
})
})
fmt.Println("EIPC server listening on :8421")
srv.ListenAndServe()
}Go Client
package main
import (
"fmt"
"github.com/embeddedos-org/eipc/client"
)
func main() {
c := client.New("eni-neuralink-1")
err := c.Connect("tcp://192.168.1.100:8421", "my-secret-key-32-bytes-minimum!!")
if err != nil {
panic(err)
}
defer c.Close()
// Send decoded neural intent
c.SendIntent("move_cursor_left", 0.92)
// Send tool request and wait for result
result, err := c.SendToolRequest("gpio_write", map[string]string{
"pin": "12",
"value": "true",
})
fmt.Printf("Tool result: %s\n", result)
// Heartbeat loop
go func() {
for {
c.SendHeartbeat()
time.Sleep(5 * time.Second)
}
}()
}🔧 C SDK Example
// C SDK client - connects to EIPC server and sends intents
#include <eipc.h>
int main(void) {
eipc_client_t client;
eipc_client_init(&client, "eni-sensor-1");
eipc_status_t rc = eipc_client_connect(&client,
"tcp://192.168.1.100:8421",
"my-secret-key-32-bytes-minimum!!");
if (rc != EIPC_OK) {
fprintf(stderr, "Connect failed: %d\n", rc);
return 1;
}
// Send intent
eipc_client_send_intent(&client, "move_cursor_left", 0.92f);
// Send tool request
eipc_kv_t args[] = {
{"pin", "12"}, {"value", "true"}
};
eipc_client_send_tool_request(&client, "gpio_write", args, 2);
// Receive response
eipc_message_t msg;
if (eipc_client_receive(&client, &msg) == EIPC_OK) {
printf("Response type=%d\n", msg.type);
}
eipc_client_close(&client);
return 0;
}Thread Safety: Transport layer is NOT thread-safe per socket. Use one socket per thread. HMAC functions are stateless and thread-safe. Client/Server APIs are NOT thread-safe per instance.