Skip to content

Instantly share code, notes, and snippets.

@zed
Last active Jan 30, 2023
Embed
What would you like to do?
Native messaging "ping_pong" example in C
/*** Native messaging "ping_pong" example in C.
*
* It is reimplementation of the corresponding Python example from
* https://github.com/mdn/webextensions-examples/tree/master/native-messaging
*
* # Python 3.x version
* # Read a message from stdin and decode it.
* def getMessage():
* rawLength = sys.stdin.buffer.read(4)
* if len(rawLength) == 0:
* sys.exit(0)
* messageLength = struct.unpack('@I', rawLength)[0]
* message = sys.stdin.buffer.read(messageLength).decode('utf-8')
* return json.loads(message)
*
* # Encode a message for transmission,
* # given its content.
* def encodeMessage(messageContent):
* encodedContent = json.dumps(messageContent).encode('utf-8')
* encodedLength = struct.pack('@I', len(encodedContent))
* return {'length': encodedLength, 'content': encodedContent}
*
* # Send an encoded message to stdout
* def sendMessage(encodedMessage):
* sys.stdout.buffer.write(encodedMessage['length'])
* sys.stdout.buffer.write(encodedMessage['content'])
* sys.stdout.buffer.flush()
*
* while True:
* receivedMessage = getMessage()
* if receivedMessage == "ping":
* sendMessage(encodeMessage("pong3"))
*
*/
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
uint32_t message_length;
// read messages and send response
while (fread(&message_length, sizeof message_length, 1, stdin) == 1) {
// read message into buffer
char *buf = malloc(message_length);
if (!buf) {
perror("malloc");
return EXIT_FAILURE;
}
if (fread(buf, sizeof *buf, message_length, stdin) != message_length) {
perror("fread");
return EXIT_FAILURE;
}
// check we got the "ping" message (JSON string)
char expected[] = u8"\"ping\"";
const uint32_t expected_length = (sizeof expected) - 1; // - null byte
if (strncmp(buf, expected, expected_length)) {
fprintf(stderr, "error: expected '%s', got: '%.*s' instead\n", expected, message_length, buf);
return EXIT_FAILURE;
}
// write response (JSON prefixed with its utf-8 length)
char response[] = u8"\"pong\"";
const uint32_t response_length = (sizeof response) - 1; // - null byte
if (fwrite(&response_length, sizeof response_length, 1, stdout) != 1
|| fwrite(response, response_length, 1, stdout) != 1) {
perror("fwrite");
return EXIT_FAILURE;
}
fflush(stdout);
// cleanup
free(buf);
} // end while
if (ferror(stdin))
perror("can't read message length");
// return success on EOF
return ! feof(stdin);
}
@guest271314
Copy link

Echo input message

// Native Messaging host C
// https://stackoverflow.com/q/64400254
// https://gist.github.com/zed/4459378be67a4b37f53430e0703cb700
// guest271314, 2022
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

const char *getMessage() {
  uint32_t message_length;
  fread(&message_length, sizeof message_length, 1, stdin);
  char *message = malloc(message_length);
  fread(message, sizeof *message, message_length, stdin);
  return message;
}

void sendMessage(const char *response) {
  const uint32_t response_length = strlen(response);
  fwrite(&response_length, sizeof response_length, 1, stdout);
  fwrite(response, response_length, 1, stdout);
  fflush(stdout);
}

int main() {
  while (1) {
    const char *message = getMessage();
    sendMessage(message);
  }
}

@zed
Copy link
Author

zed commented Jun 24, 2022

It is not a good idea to ignore error in C. Switch to Python if you need an executable pseudo-code kind-of feel (at least Python would raise exceptions).

@guest271314
Copy link

If there are errors the Native Messaging host will either not send the message or exit. I wrote the same code in Python, C++, C, and JavaScript.

@guest271314
Copy link

It is not a good idea to ignore error in C. Switch to Python if you need an executable pseudo-code kind-of feel (at least Python would raise exceptions).

I don't think the errors from from C reach native_message_process_host.cc. E.g., on Chromium when passing a message from client to host that is greater than 1024*1024 (new Array(458*458)) chrome.runtime.lastError logs {message: 'Error when communicating with the native messaging host.'}. To get the error message in native_message_process_host.cc I had to use

--enable-logging \
--log-level=0 \
--vmodule=native_message_process_host=0 \
--v=0 

then search for

[...:ERROR:native_message_process_host.cc(300)] Native Messaging host tried sending a message that is 1048821 bytes long.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment