Skip to content

Commit e6eb958

Browse files
authored
Add support for r2pipe client apis over http-post ##http
1 parent 96ada68 commit e6eb958

4 files changed

Lines changed: 86 additions & 68 deletions

File tree

libr/core/task.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* radare - LGPL - Copyright 2014-2025 - pancake, thestr4ng3r */
1+
/* radare - LGPL - Copyright 2014-2025 - pancake */
22

33
#include <r_core.h>
44

@@ -7,7 +7,7 @@ static R_TH_LOCAL RCoreTask *task_tls_current = NULL;
77

88
R_API void r_core_task_scheduler_init(RCoreTaskScheduler *tasks, RCore *core) {
99
tasks->task_id_next = 0;
10-
tasks->tasks = r_list_newf ((RListFree)r_core_task_decref);
10+
tasks->tasks = r_list_newf ( (RListFree)r_core_task_decref);
1111
tasks->tasks_queue = r_list_new ();
1212
tasks->oneshot_queue = r_list_newf (free);
1313
tasks->oneshots_enqueued = 0;
@@ -105,7 +105,7 @@ R_API void r_core_task_print(RCore *core, RCoreTask *task, PJ *pj, int mode) {
105105
}
106106
r_cons_printf (core->cons, "%3d %3s %12s %s\n",
107107
task->id,
108-
task->transient ? "(t)" : "",
108+
task->transient ? " (t)" : "",
109109
r_core_task_status (task),
110110
r_str_get (info));
111111
}
@@ -355,7 +355,7 @@ R_API void r_core_task_schedule(RCoreTask *current, RTaskState next_state) {
355355
// oneshots always have priority.
356356
// if there are any queued, run them immediately.
357357
OneShot *oneshot;
358-
while ((oneshot = r_list_pop_head (scheduler->oneshot_queue))) {
358+
while ( (oneshot = r_list_pop_head (scheduler->oneshot_queue))) {
359359
scheduler->oneshots_enqueued--;
360360
scheduler->oneshot_running = true;
361361
oneshot->func (oneshot->user);
@@ -585,13 +585,13 @@ R_API void r_core_task_sync_begin(RCoreTaskScheduler *scheduler) {
585585
}
586586
}
587587

588-
/* end running stuff synchronously, initially started with r_core_task_sync_begin() */
588+
/* end running stuff synchronously, initially started with r_core_task_sync_begin () */
589589
R_API void r_core_task_sync_end(RCoreTaskScheduler *scheduler) {
590590
R_RETURN_IF_FAIL (scheduler);
591591
task_end (scheduler->main_task);
592592
}
593593

594-
/* To be called from within a task. Begin sleeping and schedule other tasks until r_core_task_sleep_end() is called. */
594+
/* To be called from within a task. Begin sleeping and schedule other tasks until r_core_task_sleep_end () is called. */
595595
R_API void r_core_task_sleep_begin(RCoreTask *task) {
596596
R_RETURN_IF_FAIL (task);
597597
r_core_task_schedule (task, R_CORE_TASK_STATE_SLEEPING);

libr/include/r_socket.h

Lines changed: 25 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ extern "C" {
99
#include "r_bind.h"
1010
#include "r_list.h"
1111

12-
R_LIB_VERSION_HEADER (r_socket);
12+
R_LIB_VERSION_HEADER(r_socket);
1313

1414
#if R2__UNIX__
1515
#include <netinet/in.h>
@@ -37,9 +37,9 @@ R_LIB_VERSION_HEADER (r_socket);
3737
#define MSG_DONTWAIT 0
3838
#endif
3939
#ifndef SD_BOTH
40-
#define SD_RECEIVE 0
41-
#define SD_SEND 1
42-
#define SD_BOTH 2
40+
#define SD_RECEIVE 0
41+
#define SD_SEND 1
42+
#define SD_BOTH 2
4343
#endif
4444

4545
#if _MSC_VER
@@ -58,6 +58,12 @@ typedef struct {
5858
int output[2];
5959
#endif
6060
RCoreBind coreb;
61+
/* HTTP/r2web support: when is_http is true, http_url contains
62+
* the base endpoint where commands are POSTed using the
63+
* r_socket_http_post API and r2pipe_cmd will return the
64+
* HTTP response instead of using fork+pipe. */
65+
char *http_url;
66+
bool is_http;
6167
} R2Pipe;
6268

6369
typedef struct r_socket_t {
@@ -68,7 +74,7 @@ typedef struct r_socket_t {
6874
#endif
6975
bool is_ssl;
7076
int proto;
71-
int local; // TODO: merge ssl with local -> flags/options
77+
int local; // TODO: merge ssl with local -> flags/options
7278
int port;
7379
struct sockaddr_in sa;
7480
#if HAVE_LIB_SSL
@@ -85,17 +91,17 @@ typedef struct r_socket_http_options {
8591
bool httpauth;
8692
} RSocketHTTPOptions;
8793

88-
#define R_SOCKET_PROTO_TCP IPPROTO_TCP
89-
#define R_SOCKET_PROTO_UDP IPPROTO_UDP
90-
#define R_SOCKET_PROTO_CAN 0xc42b05
91-
#define R_SOCKET_PROTO_SERIAL 0x534147
92-
#define R_SOCKET_PROTO_UNIX 0x1337
93-
#define R_SOCKET_PROTO_NONE 0
94+
#define R_SOCKET_PROTO_TCP IPPROTO_TCP
95+
#define R_SOCKET_PROTO_UDP IPPROTO_UDP
96+
#define R_SOCKET_PROTO_CAN 0xc42b05
97+
#define R_SOCKET_PROTO_SERIAL 0x534147
98+
#define R_SOCKET_PROTO_UNIX 0x1337
99+
#define R_SOCKET_PROTO_NONE 0
94100
#define R_SOCKET_PROTO_DEFAULT R_SOCKET_PROTO_TCP
95101

96102
// backward compat for yara-r2
97-
#define r2p_cmd r2pipe_cmd
98-
#define r2p_open r2pipe_open
103+
#define r2p_cmd r2pipe_cmd
104+
#define r2p_open r2pipe_open
99105
#define r2p_close r2pipe_close
100106

101107
#ifdef R_API
@@ -104,10 +110,10 @@ R_API RSocket *r_socket_new(bool is_ssl);
104110
R_API bool r_socket_spawn(RSocket *s, const char *cmd, unsigned int timeout);
105111
R_API bool r_socket_connect(RSocket *s, const char *host, const char *port, int proto, unsigned int timeout);
106112
R_API int r_socket_connect_serial(RSocket *sock, const char *path, int speed, int parity);
107-
#define r_socket_connect_tcp(a, b, c, d) r_socket_connect (a, b, c, R_SOCKET_PROTO_TCP, d)
108-
#define r_socket_connect_udp(a, b, c, d) r_socket_connect (a, b, c, R_SOCKET_PROTO_UDP, d)
113+
#define r_socket_connect_tcp(a, b, c, d) r_socket_connect(a, b, c, R_SOCKET_PROTO_TCP, d)
114+
#define r_socket_connect_udp(a, b, c, d) r_socket_connect(a, b, c, R_SOCKET_PROTO_UDP, d)
109115
#if R2__UNIX__
110-
#define r_socket_connect_unix(a, b) r_socket_connect (a, b, b, R_SOCKET_PROTO_UNIX, 0)
116+
#define r_socket_connect_unix(a, b) r_socket_connect(a, b, b, R_SOCKET_PROTO_UNIX, 0)
111117
#else
112118
#define r_socket_connect_unix(a, b) (false)
113119
#endif
@@ -191,15 +197,15 @@ enum {
191197
typedef struct r_socket_rap_server_t {
192198
RSocket *fd;
193199
char *port;
194-
ut8 buf[RAP_PACKET_MAX + 32]; // This should be used as a static buffer for everything done by the server
200+
ut8 buf[RAP_PACKET_MAX + 32]; // This should be used as a static buffer for everything done by the server
195201
rap_server_open open;
196202
rap_server_seek seek;
197203
rap_server_read read;
198204
rap_server_write write;
199205
rap_server_cmd system;
200206
rap_server_cmd cmd;
201207
rap_server_close close;
202-
void *user; // Always first arg for callbacks
208+
void *user; // Always first arg for callbacks
203209
} RSocketRapServer;
204210

205211
R_API RSocketRapServer *r_socket_rap_server_new(bool is_ssl, const char *port);
@@ -262,7 +268,7 @@ typedef struct r_run_profile_t {
262268
bool _noprogram;
263269
} RRunProfile;
264270

265-
R_API RRunProfile *r_run_new(const char * R_NULLABLE str);
271+
R_API RRunProfile *r_run_new(const char *R_NULLABLE str);
266272
R_API bool r_run_parse(RRunProfile *pf, const char *profile);
267273
R_API void r_run_free(RRunProfile *r);
268274
R_API bool r_run_parseline(RRunProfile *p, const char *b);

libr/socket/r2pipe.c

Lines changed: 49 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,13 @@
11
/* radare - LGPL - Copyright 2015-2025 - pancake */
2-
/*
3-
Usage Example:
4-
5-
#include <r_core.h>
6-
int main() {
7-
RCoreBind rcb;
8-
RCore *core = r_core_new ();
9-
r_core_bind (core, &rcb);
10-
r2pipe_open_corebind (&rcb);
11-
char *clippy = r2pipe_cmd ("?E hello");
12-
eprintf ("%s\n", clippy);
13-
free (clippy);
14-
r2pipe_close (r2pipe);
15-
r_core_free (core);
16-
}
17-
*/
182

193
#include <r_util.h>
204
#include <r_lib.h>
215
#include <r_socket.h>
226
#include <errno.h>
237

24-
#define R2P_PID(x) (((R2Pipe*)(x)->data)->pid)
25-
#define R2P_INPUT(x) (((R2Pipe*)(x)->data)->input[0])
26-
#define R2P_OUTPUT(x) (((R2Pipe*)(x)->data)->output[1])
8+
#define R2P_PID (x) ( ( (R2Pipe *) (x)->data)->pid)
9+
#define R2P_INPUT (x) ( ( (R2Pipe *) (x)->data)->input[0])
10+
#define R2P_OUTPUT (x) ( ( (R2Pipe *) (x)->data)->output[1])
2711

2812
#define USE_WIP_READ 0
2913
#if R2__WINDOWS__
@@ -32,7 +16,7 @@ Usage Example:
3216
#define NO_CHILD -1
3317
#endif
3418

35-
#if defined(__wasi__) && __wasi__
19+
#if defined (__wasi__) && __wasi__
3620
#define HAVE_R2PIPE 0
3721
#else
3822
#define HAVE_R2PIPE 1
@@ -61,11 +45,11 @@ R_API int r2pipe_write(R2Pipe *r2pipe, const char *str) {
6145
cmd[n + 1] = '\0';
6246
#if R2__WINDOWS__
6347
DWORD dwWritten = 0;
64-
WriteFile (r2pipe->pipe, cmd, (DWORD)(len - 1), &dwWritten, NULL);
65-
int ret = (dwWritten == (DWORD)(len - 1));
48+
WriteFile (r2pipe->pipe, cmd, (DWORD) (len - 1), &dwWritten, NULL);
49+
int ret = (dwWritten == (DWORD) (len - 1));
6650
#else
67-
ssize_t wrote = write (r2pipe->input[1], cmd, (ssize_t)(len - 1));
68-
int ret = (wrote == (ssize_t)(len - 1));
51+
ssize_t wrote = write (r2pipe->input[1], cmd, (ssize_t) (len - 1));
52+
int ret = (wrote == (ssize_t) (len - 1));
6953
#endif
7054
free (cmd);
7155
return ret;
@@ -79,7 +63,7 @@ R_API char *r2pipe_read(R2Pipe *r2pipe) {
7963
R_RETURN_VAL_IF_FAIL (r2pipe, NULL);
8064
char *buf = NULL;
8165
#if HAVE_R2PIPE
82-
# /* Read all available data from the pipe into a dynamically
66+
#/* Read all available data from the pipe into a dynamically
8367
# * growing buffer and return a NUL-terminated string. */
8468
/* r2pipe already validated above */
8569
int bufsz = 4096;
@@ -91,7 +75,7 @@ R_API char *r2pipe_read(R2Pipe *r2pipe) {
9175
BOOL bSuccess = FALSE;
9276
DWORD dwRead = 0;
9377
// Read up to bufsz-1 bytes and NUL-terminate.
94-
DWORD toRead = (DWORD)(bufsz - 1);
78+
DWORD toRead = (DWORD) (bufsz - 1);
9579
bSuccess = ReadFile (r2pipe->pipe, buf, toRead, &dwRead, NULL);
9680
if (!bSuccess || dwRead == 0) {
9781
free (buf);
@@ -121,7 +105,7 @@ R_API char *r2pipe_read(R2Pipe *r2pipe) {
121105
}
122106
}
123107
if (buf) {
124-
int zpos = (i < bufsz)? i: i - 1;
108+
int zpos = (i < bufsz) ? i : i - 1;
125109
buf[zpos] = 0;
126110
}
127111
#endif
@@ -130,14 +114,12 @@ R_API char *r2pipe_read(R2Pipe *r2pipe) {
130114
}
131115

132116
R_API int r2pipe_close(R2Pipe *r2pipe) {
133-
#if HAVE_R2PIPE
134117
/* r2pipe may be NULL on non-r2pipe builds */
135118
R_RETURN_VAL_IF_FAIL (r2pipe, 0);
136-
#endif
137119
#if HAVE_R2PIPE
138120
/*
139121
if (r2pipe->coreb.core && !r2pipe->coreb.puts) {
140-
void (*rfre)(void *c) = r_lib_dl_sym (libr, "r_core_free");
122+
void (*rfre) (void *c) = r_lib_dl_sym (libr, "r_core_free");
141123
if (rfre) {
142124
rfre (r2pipe->coreb.core);
143125
}
@@ -166,11 +148,16 @@ R_API int r2pipe_close(R2Pipe *r2pipe) {
166148
r2pipe->output[1] = -1;
167149
}
168150
if (r2pipe->child != NO_CHILD) {
169-
kill (r2pipe->child, SIGTERM);
170-
waitpid (r2pipe->child, NULL, 0);
151+
r_sandbox_kill (r2pipe->child, SIGTERM);
171152
r2pipe->child = NO_CHILD;
172153
}
173154
#endif
155+
/* free http resources if used */
156+
if (r2pipe->is_http && r2pipe->http_url) {
157+
free (r2pipe->http_url);
158+
r2pipe->http_url = NULL;
159+
r2pipe->is_http = false;
160+
}
174161
#endif
175162
free (r2pipe);
176163
return 0;
@@ -180,9 +167,7 @@ R_API int r2pipe_close(R2Pipe *r2pipe) {
180167
static int w32_createPipe(R2Pipe *r2pipe, const char *cmd) {
181168
CHAR buf[1024];
182169
r2pipe->pipe = CreateNamedPipe (TEXT ("\\\\.\\pipe\\R2PIPE_IN"),
183-
PIPE_ACCESS_DUPLEX,PIPE_TYPE_MESSAGE | \
184-
PIPE_READMODE_MESSAGE | \
185-
PIPE_WAIT, PIPE_UNLIMITED_INSTANCES,
170+
PIPE_ACCESS_DUPLEX, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, PIPE_UNLIMITED_INSTANCES,
186171
sizeof (buf), sizeof (buf), 0, NULL);
187172
if (r_sys_create_child_proc_w32 (cmd, NULL, NULL, NULL)) {
188173
if (ConnectNamedPipe (r2pipe->pipe, NULL)) {
@@ -194,9 +179,9 @@ static int w32_createPipe(R2Pipe *r2pipe, const char *cmd) {
194179
#endif
195180

196181
#if HAVE_R2PIPE
197-
static R2Pipe* r2p_open_pipes(R2Pipe* r2p) {
182+
static R2Pipe *r2p_open_pipes(R2Pipe *r2p) {
198183
R_RETURN_VAL_IF_FAIL (r2p, NULL);
199-
#if R2__UNIX__ || defined(__CYGWIN__)
184+
#if R2__UNIX__ || defined (__CYGWIN__)
200185
char *out = r_sys_getenv ("R2PIPE_IN");
201186
char *in = r_sys_getenv ("R2PIPE_OUT");
202187
int done = false;
@@ -217,7 +202,7 @@ static R2Pipe* r2p_open_pipes(R2Pipe* r2p) {
217202
free (out);
218203
return r2p;
219204
#else
220-
R_LOG_ERROR ("r2pipe_open(NULL) not supported on this platform");
205+
R_LOG_ERROR ("r2pipe_open (NULL) not supported on this platform");
221206
return NULL;
222207
#endif
223208
}
@@ -230,6 +215,9 @@ static R2Pipe *r2pipe_new(void) {
230215
r2pipe->output[0] = r2pipe->output[1] = -1;
231216
#endif
232217
r2pipe->child = NO_CHILD;
218+
/* init http support fields */
219+
r2pipe->http_url = NULL;
220+
r2pipe->is_http = false;
233221
return r2pipe;
234222
}
235223

@@ -244,8 +232,8 @@ R_API R2Pipe *r2pipe_open_dl(const char *libr_path) {
244232
#if HAVE_R2PIPE
245233
R_RETURN_VAL_IF_FAIL (libr_path, NULL);
246234
void *libr = r_lib_dl_open (libr_path, false);
247-
void* (*rnew)() = r_lib_dl_sym (libr, "r_core_new");
248-
char* (*rcmd)(void *c, const char *cmd) = r_lib_dl_sym (libr, "r_core_cmd_str");
235+
void * (*rnew) () = r_lib_dl_sym (libr, "r_core_new");
236+
char * (*rcmd) (void *c, const char *cmd) = r_lib_dl_sym (libr, "r_core_cmd_str");
249237

250238
if (rnew && rcmd) {
251239
R2Pipe *r2pipe = r2pipe_new ();
@@ -261,12 +249,26 @@ R_API R2Pipe *r2pipe_open_dl(const char *libr_path) {
261249
return NULL;
262250
}
263251

264-
R_API R2Pipe *r2pipe_open(const char * R_NULLABLE cmd) {
252+
R_API R2Pipe *r2pipe_open(const char *R_NULLABLE cmd) {
265253
#if HAVE_R2PIPE
266254
R2Pipe *r2p = r2pipe_new ();
267255
if (!r2p) {
268256
return NULL;
269257
}
258+
/* HTTP/r2web mode: if the command is a http (s):// or r2web:// URL,
259+
* store it in the r2pipe and use HTTP POST for commands. */
260+
if (cmd && (r_str_startswith (cmd, "http://") || r_str_startswith (cmd, "https://") || r_str_startswith (cmd, "r2web://"))) {
261+
char *u = NULL;
262+
if (r_str_startswith (cmd, "r2web://")) {
263+
u = r_str_newf ("http://%s", cmd + sizeof ("r2web://") - 1);
264+
} else {
265+
u = strdup (cmd);
266+
}
267+
r2p->http_url = u;
268+
r2p->is_http = true;
269+
r2p->child = NO_CHILD;
270+
return r2p;
271+
}
270272
if (R_STR_ISEMPTY (cmd)) {
271273
r2p->child = NO_CHILD;
272274
return r2p_open_pipes (r2p);
@@ -351,6 +353,11 @@ R_API R2Pipe *r2pipe_open(const char * R_NULLABLE cmd) {
351353
R_API char *r2pipe_cmd(R2Pipe *r2p, const char *str) {
352354
#if HAVE_R2PIPE
353355
R_RETURN_VAL_IF_FAIL (r2p && str, NULL);
356+
/* HTTP mode: POST the command to the configured endpoint and return the response */
357+
if (r2p->is_http) {
358+
int len = 0;
359+
return r_socket_http_post (r2p->http_url, NULL, str, NULL, &len);
360+
}
354361
if (!*str || !r2pipe_write (r2p, str)) {
355362
r_sys_perror ("r2pipe_write");
356363
return NULL;
@@ -391,7 +398,7 @@ R_API char *r2pipe_cmdf(R2Pipe *r2p, const char *fmt, ...) {
391398
}
392399
va_end (ap2);
393400
va_end (ap);
394-
return (char*)fmt;
401+
return (char *)fmt;
395402
#else
396403
return NULL;
397404
#endif

libr/util/sandbox.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -516,7 +516,12 @@ R_API int r_sandbox_kill(int pid, int sig) {
516516
return -1;
517517
}
518518
#if HAVE_SYSTEM && R2__UNIX__
519-
return kill (pid, sig);
519+
int ret = kill (pid, sig);
520+
const bool sync_kill = false;
521+
if (sync_kill) {
522+
waitpid (pid, NULL, 0);
523+
}
524+
return ret;
520525
#endif
521526
return -1;
522527
}

0 commit comments

Comments
 (0)