Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 85 additions & 0 deletions examples/api/socket/http_example.c
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;
}
44 changes: 44 additions & 0 deletions examples/api/socket/rzpipe_example.c
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;
}
87 changes: 87 additions & 0 deletions examples/api/socket/tcp_example.c
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"
Copy link
Contributor

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.

#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);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add comments where the input and output would need sanitation.
You don't need to implement it, but at least a comment would be nice.
E.g. here printing just the raw buffer is somewhat meh.

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;
}
15 changes: 15 additions & 0 deletions examples/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,19 @@ if get_option('enable_examples')
dependencies: [rz_sign_dep, rz_util_dep],
install: false
)
executable('http_example', 'api/socket/http_example.c',
include_directories: [platform_inc],
dependencies: [rz_socket_dep, rz_util_dep, th],
install: false
)
executable('rzpipe_example', 'api/socket/rzpipe_example.c',
include_directories: [platform_inc],
dependencies: [rz_socket_dep, rz_util_dep],
install: false
)
executable('tcp_example', 'api/socket/tcp_example.c',
include_directories: [platform_inc],
dependencies: [rz_socket_dep, rz_util_dep, th],
install: false
)
endif
111 changes: 111 additions & 0 deletions librz/socket/README.md
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.
Copy link
Member

@Rot127 Rot127 Jan 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please correct me if I am wrong, but doesn't RzPipe only supports commands as input and returns the output?

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.
E.g. when should I use what? etc.

- `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));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At least check the returned len here and print a message like received X bytes answer or something.

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.
Loading