-
-
Notifications
You must be signed in to change notification settings - Fork 499
doc(socket): improve README and add examples #5135 #5633
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: dev
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,85 @@ | ||
| // SPDX-FileCopyrightText: 2025 Maijin <[email protected]> | ||
| // SPDX-License-Identifier: LGPL-3.0-only | ||
|
|
||
| /** | ||
| * Example: Self-contained HTTP Server and Client using RzSocket | ||
| * | ||
| * This example demonstrates: | ||
| * 1. Spawning a thread for a simple HTTP server. | ||
| * 2. Using the RzSocket HTTP API to fetch content from the local server. | ||
| * 3. Handling the HTTP request and response. | ||
| */ | ||
|
|
||
| #include <rz_socket.h> | ||
| #include <rz_util.h> | ||
| #include <rz_th.h> | ||
| #include <stdio.h> | ||
| #include <stdlib.h> | ||
| #include <string.h> | ||
|
|
||
| #define ADDR "127.0.0.1" | ||
| #define PORT "8080" | ||
|
|
||
| static void *http_server_thread(void *user) { | ||
| RzSocket *s = rz_socket_new(false); | ||
| if (!rz_socket_listen(s, PORT, NULL)) { | ||
| fprintf(stderr, "Server: Cannot listen on port %s\n", PORT); | ||
| rz_socket_free(s); | ||
| return NULL; | ||
| } | ||
|
|
||
| printf("Server: Listening on %s:%s\n", ADDR, PORT); | ||
|
|
||
| RzSocketHTTPOptions so = { .accept_timeout = true, .timeout = 1 }; // timeout in seconds | ||
| RzSocketHTTPRequest *hr = NULL; | ||
|
|
||
| while(1) { | ||
| hr = rz_socket_http_accept(s, &so); | ||
|
|
||
| // fail ? | ||
| if (!hr) continue; | ||
|
|
||
| // handle the request. | ||
| printf("Server: Received %s request for %s\n", hr->method, hr->path); | ||
| const char *response_body = "<html><body><h1>Hello from Rizin!</h1></body></html>"; | ||
| rz_socket_http_response(hr, 200, response_body, strlen(response_body), NULL); | ||
| rz_socket_http_close(hr); | ||
| } | ||
|
|
||
| rz_socket_free(s); | ||
| return NULL; | ||
| } | ||
|
|
||
| int main(int argc, char **argv) { | ||
| // 1. Start the server thread | ||
| RzThread *th = rz_th_new(http_server_thread, NULL); | ||
| if (!th) { | ||
| fprintf(stderr, "Failed to create server thread\n"); | ||
| return 1; | ||
| } | ||
|
|
||
| // Give the server a moment to start | ||
| rz_sys_sleep(1); | ||
|
|
||
| // 2. Client request | ||
| const char *url = "http://" ADDR ":" PORT "/index.html"; | ||
| int code, rlen; | ||
|
|
||
| printf("Client: Fetching URL: %s\n", url); | ||
| char *response = rz_socket_http_get(url, &code, &rlen); | ||
|
|
||
| if (response) { | ||
| printf("Client: HTTP Status: %d\n", code); | ||
| printf("Client: Response Length: %d\n", rlen); | ||
| printf("Client: Response Content:\n%s\n", response); | ||
| free(response); | ||
| } else { | ||
| fprintf(stderr, "Client: Failed to fetch URL.\n"); | ||
| } | ||
|
|
||
| // 3. Cleanup | ||
| rz_th_wait(th); | ||
| rz_th_free(th); | ||
|
|
||
| return 0; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,44 @@ | ||
| // SPDX-FileCopyrightText: 2025 Maijin <[email protected]> | ||
| // SPDX-License-Identifier: LGPL-3.0-only | ||
|
|
||
| /** | ||
| * Example: Communication with Rizin using RzPipe | ||
| * | ||
| * This example demonstrates how to spawn a Rizin utility (rz-asm) | ||
| * and communicate with it using the RzPipe IPC mechanism. | ||
| */ | ||
|
|
||
| #include <rz_socket.h> | ||
| #include <rz_util.h> | ||
| #include <stdio.h> | ||
| #include <stdlib.h> | ||
|
|
||
| int main(int argc, char **argv) { | ||
| // RzPipe expects the child to write a synchronization byte (0x00) | ||
| // when it's ready. For a non-interactive utility like rz-asm, | ||
| // we can simulate this by prepending a printf. | ||
| const char *cmd = "printf '\\0'; ./build/binrz/rz-asm/rz-asm -a x86 -b 32 'push eax'"; | ||
|
|
||
| printf("Opening pipe to: %s\n", cmd); | ||
|
|
||
| // rzpipe_open spawns the command and sets up pipes for communication. | ||
| RzPipe *p = rzpipe_open(cmd); | ||
| if (!p) { | ||
| fprintf(stderr, "Failed to open rzpipe. Make sure 'rz-asm' is in your PATH.\n"); | ||
| return 1; | ||
| } | ||
|
|
||
| // rzpipe_read reads the output from the spawned process. | ||
| char *res = rzpipe_read(p); | ||
| if (res) { | ||
| printf("Result from rz-asm: %s", res); | ||
| free(res); | ||
| } else { | ||
| fprintf(stderr, "Failed to read from rzpipe.\n"); | ||
| } | ||
|
|
||
| // Close the pipe and clean up. | ||
| rzpipe_close(p); | ||
|
|
||
| return 0; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,87 @@ | ||
| // SPDX-FileCopyrightText: 2025 Maijin <[email protected]> | ||
| // SPDX-License-Identifier: LGPL-3.0-only | ||
|
|
||
| /** | ||
| * Example: Self-contained TCP Server and Client using RzSocket | ||
| * | ||
| * This example demonstrates: | ||
| * 1. Listening for TCP connections on 127.0.0.1. | ||
| * 2. Connecting to the local server. | ||
| * 3. Bidirectional communication. | ||
| */ | ||
|
|
||
| #include <rz_socket.h> | ||
| #include <rz_util.h> | ||
| #include <rz_th.h> | ||
| #include <stdio.h> | ||
| #include <stdlib.h> | ||
| #include <string.h> | ||
|
|
||
| #define ADDR "127.0.0.1" | ||
| #define PORT "9999" | ||
|
|
||
| static void *tcp_server_thread(void *user) { | ||
| RzSocket *ls = rz_socket_new(false); | ||
| if (!rz_socket_listen(ls, PORT, NULL)) { | ||
| fprintf(stderr, "Server: Cannot listen on port %s\n", PORT); | ||
| rz_socket_free(ls); | ||
| return NULL; | ||
| } | ||
|
|
||
| printf("Server: Listening on %s:%s\n", ADDR, PORT); | ||
|
|
||
| // Accept a connection | ||
| RzSocket *s = rz_socket_accept(ls); | ||
| if (s) { | ||
| printf("Server: Accepted connection\n"); | ||
| char buf[1024]; | ||
| int len = rz_socket_read(s, (ut8 *)buf, sizeof(buf) - 1); | ||
| if (len > 0) { | ||
| buf[len] = 0; | ||
| printf("Server: Received: %s\n", buf); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please add comments where the input and output would need sanitation. |
||
| rz_socket_printf(s, "Hello Client! I got your message: %s", buf); | ||
| } | ||
| rz_socket_free(s); | ||
| } | ||
|
|
||
| rz_socket_free(ls); | ||
| return NULL; | ||
| } | ||
|
|
||
| int main(int argc, char **argv) { | ||
| // 1. Start the server thread | ||
| RzThread *th = rz_th_new(tcp_server_thread, NULL); | ||
| if (!th) { | ||
| fprintf(stderr, "Failed to create server thread\n"); | ||
| return 1; | ||
| } | ||
|
|
||
| // Give the server a moment to start | ||
| rz_sys_sleep(1); | ||
|
|
||
| // 2. Client connection | ||
| RzSocket *s = rz_socket_new(false); | ||
| printf("Client: Connecting to %s:%s\n", ADDR, PORT); | ||
| if (rz_socket_connect_tcp(s, ADDR, PORT, 0)) { | ||
| const char *msg = "Hello from TCP client!"; | ||
| printf("Client: Sending: %s\n", msg); | ||
| rz_socket_write(s, (void *)msg, strlen(msg)); | ||
|
|
||
| char buf[1024]; | ||
| int len = rz_socket_read(s, (ut8 *)buf, sizeof(buf) - 1); | ||
| if (len > 0) { | ||
| buf[len] = 0; | ||
| printf("Client: Received from server: %s\n", buf); | ||
| } | ||
| rz_socket_close(s); | ||
| } else { | ||
| fprintf(stderr, "Client: Failed to connect to %s:%s\n", ADDR, PORT); | ||
| } | ||
| rz_socket_free(s); | ||
|
|
||
| // 3. Cleanup | ||
| rz_th_wait(th); | ||
| rz_th_free(th); | ||
|
|
||
| return 0; | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,111 @@ | ||
| # RzSocket | ||
|
|
||
| `RzSocket` provides a portable abstraction for network sockets, process pipes, and serial communication. It is used across Rizin for IPC, remote analysis, and communication with external tools. | ||
|
|
||
| ## Architecture | ||
|
|
||
| The module is divided into several components: | ||
|
|
||
| - **Core Socket**: Basic TCP, UDP, and Unix socket support (client and server). | ||
| - **HTTP**: Client (GET/POST) and Server implementation. | ||
| - **IPC/Process**: | ||
| - `RzSocketProc`: Spawning processes with redirected STDIN/STDOUT. | ||
| - `RzPipe`: Higher-level IPC for talking to Rizin instances or libraries. | ||
| - **Serial**: Support for RS232 serial communication. | ||
|
|
||
| ## Key Structures | ||
|
|
||
| - `RzSocket`: Main structure for network and serial connections. Supports SSL. | ||
| - `RzPipe`: Used for communicating with Rizin processes or linked libraries. | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please correct me if I am wrong, but doesn't The sentence (and the other text) here is a little too much high level I'd say. It is not "actionable" (for the lag of a better term) for the user. |
||
| - `RzSocketProc`: Low-level process spawning and IO management. | ||
| - `RzRunProfile`: Configuration for spawning processes (environment, IDs, priorities). | ||
|
|
||
| ## API Usage | ||
|
|
||
| ### Network Client (TCP) | ||
|
|
||
| ```c | ||
| RzSocket *s = rz_socket_new(false); | ||
| if (rz_socket_connect_tcp(s, "localhost", "9090", 0)) { | ||
| rz_socket_printf(s, "hello\n"); | ||
| char buf[1024]; | ||
| rz_socket_read(s, (ut8 *)buf, sizeof(buf)); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. At least check the returned |
||
| rz_socket_close(s); | ||
| } | ||
| rz_socket_free(s); | ||
| ``` | ||
|
|
||
| ### HTTP Client | ||
|
|
||
| ```c | ||
| int code, rlen; | ||
| char *response = rz_socket_http_get("http://127.0.0.1:8080/index.html", &code, &rlen); | ||
| if (response) { | ||
| printf("Status: %d, Length: %d\n", code, rlen); | ||
| free(response); | ||
| } | ||
| ``` | ||
|
|
||
| ### IPC / RzPipe (IPC) | ||
|
|
||
| `RzPipe` allows you to execute commands in a Rizin instance and read the results. | ||
|
|
||
| ```c | ||
| RzPipe *p = rzpipe_open("rz-asm -a x86 -b 32 'push eax'"); | ||
| char *res = rzpipe_read(p); | ||
| if (res) { | ||
| printf("Result: %s\n", res); | ||
| free(res); | ||
| } | ||
| rzpipe_close(p); | ||
| ``` | ||
|
|
||
| ### Process Management (SocketProc) | ||
|
|
||
| `RzSocket` provides a way to interact with external processes using pipes. | ||
|
|
||
| ```c | ||
| char *argv[] = { "ls", "-l", NULL }; | ||
| RzSocketProc *sp = rz_socket_proc_open(argv); | ||
| if (sp) { | ||
| char buf[1024]; | ||
| int len = rz_socket_proc_read(sp, (ut8 *)buf, sizeof(buf) - 1); | ||
| if (len > 0) { | ||
| buf[len] = 0; | ||
| printf("Output:\n%s\n", buf); | ||
| } | ||
| rz_socket_proc_close(sp); | ||
| } | ||
| ``` | ||
|
|
||
| ### Serial Communication | ||
|
|
||
| `RzSocket` can also be used to communicate with serial devices. | ||
|
|
||
| ```c | ||
| RzSocket *s = rz_socket_new(false); | ||
| int fd = rz_socket_connect_serial(s, "/dev/ttyUSB0", 115200, 0); | ||
| if (fd != -1) { | ||
| char buf[128]; | ||
| int len = rz_socket_read(s, (ut8 *)buf, sizeof(buf)); | ||
| if (len > 0) { | ||
| printf("Received: %.*s\n", len, buf); | ||
| } | ||
| rz_socket_close(s); | ||
| } | ||
| rz_socket_free(s); | ||
| ``` | ||
|
|
||
| ## RzPipe Ecosystem | ||
|
|
||
| The RzPipe protocol is implemented in many programming languages, allowing you to interact with Rizin from almost anywhere. | ||
|
|
||
| Supported languages include: | ||
| - [Python](https://github.com/rizinorg/rz-pipe/tree/master/python) | ||
| - [Rust](https://github.com/rizinorg/rz-pipe/tree/master/rust) | ||
| - [Go](https://github.com/rizinorg/rz-pipe/tree/master/go) | ||
| - [Haskell](https://github.com/rizinorg/rz-pipe/tree/master/haskell) | ||
| - [OCaml](https://github.com/rizinorg/rz-pipe/tree/master/ocaml) | ||
| - [Ruby](https://github.com/rizinorg/rz-pipe/tree/master/ruby) | ||
|
|
||
| For a complete list of implementations, visit the [rz-pipe](https://github.com/rizinorg/rz-pipe) repository. | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's 2026, I think we need to support both IPv4 and IPv6 actually.