1 /* radare - Copyright 2009-2020 - pancake, nibble */
2 
3 #include "r_core.h"
4 #include "r_socket.h"
5 #include "gdb/include/libgdbr.h"
6 #include "gdb/include/gdbserver/core.h"
7 
8 #if HAVE_LIBUV
9 #include <uv.h>
10 #endif
11 
12 #if 0
13 SECURITY IMPLICATIONS
14 =====================
15 - no ssl
16 - no auth
17 - commands can be executed by anyone
18 - default is to listen on localhost
19 - can access full filesystem
20 - follow symlinks
21 #endif
22 
23 #define rtr_n core->rtr_n
24 #define rtr_host core->rtr_host
25 
26 static RSocket *s = NULL;
27 static RThread *httpthread = NULL;
28 static RThread *rapthread = NULL;
29 static const char *listenport = NULL;
30 
31 typedef struct {
32 	const char *host;
33 	const char *port;
34 	const char *file;
35 } TextLog;
36 
37 typedef struct {
38 	RCore *core;
39 	int launch;
40 	int browse;
41 	char *path;
42 } HttpThread;
43 
44 typedef struct {
45 	RCore *core;
46 	char* input;
47 } RapThread;
48 
r_core_wait(RCore * core)49 R_API void r_core_wait(RCore *core) {
50 	r_cons_singleton ()->context->breaked = true;
51 	r_th_kill (httpthread, true);
52 	r_th_kill (rapthread, true);
53 	r_th_wait (httpthread);
54 	r_th_wait (rapthread);
55 }
56 
http_logf(RCore * core,const char * fmt,...)57 static void http_logf(RCore *core, const char *fmt, ...) {
58 	bool http_log_enabled = r_config_get_i (core->config, "http.log");
59 	va_list ap;
60 	va_start (ap, fmt);
61 	if (http_log_enabled) {
62 		const char *http_log_file = r_config_get (core->config, "http.logfile");
63 		if (http_log_file && *http_log_file) {
64 			char * msg = calloc (4096, 1);
65 			if (msg) {
66 				vsnprintf (msg, 4095, fmt, ap);
67 				r_file_dump (http_log_file, (const ut8*)msg, -1, true);
68 				free (msg);
69 			}
70 		} else {
71 			vfprintf (stderr, fmt, ap);
72 		}
73 	}
74 	va_end (ap);
75 }
76 
rtrcmd(TextLog T,const char * str)77 static char *rtrcmd (TextLog T, const char *str) {
78 	char *res, *ptr2;
79 	char *ptr = r_str_uri_encode (str);
80 	char *uri = r_str_newf ("http://%s:%s/%s%s", T.host, T.port, T.file, ptr? ptr: str);
81 	int len;
82 	free (ptr);
83 	ptr2 = r_socket_http_get (uri, NULL, &len);
84 	free (uri);
85 	if (ptr2) {
86 		ptr2[len] = 0;
87 		res = strstr (ptr2, "\n\n");
88 		if (res) {
89 			res = strstr (res + 1, "\n\n");
90 		}
91 		return res? res + 2: ptr2;
92 	}
93 	return NULL;
94 }
95 
showcursor(RCore * core,int x)96 static void showcursor(RCore *core, int x) {
97 	if (core && core->vmode) {
98 		r_cons_show_cursor (x);
99 		r_cons_enable_mouse (x? r_config_get_i (core->config, "scr.wheel"): false);
100 	} else {
101 		r_cons_enable_mouse (false);
102 	}
103 	r_cons_flush ();
104 }
105 
106 // TODO: rename /name to /nick or /so?
107 // clone of textlog_chat () using rtrcmd()
rtr_textlog_chat(RCore * core,TextLog T)108 static void rtr_textlog_chat (RCore *core, TextLog T) {
109 	char prompt[64];
110 	char buf[1024];
111 	int lastmsg = 0;
112 	const char *me = r_config_get (core->config, "cfg.user");
113 	char *ret, msg[1024];
114 
115 	eprintf ("Type '/help' for commands and ^D to quit:\n");
116 	char *oldprompt = strdup (r_line_singleton ()->prompt);
117 	snprintf (prompt, sizeof (prompt) - 1, "[%s]> ", me);
118 	r_line_set_prompt (prompt);
119 	ret = rtrcmd (T, msg);
120 	for (;;) {
121 		if (lastmsg >= 0) {
122 			snprintf (msg, sizeof (msg) - 1, "T %d", lastmsg);
123 		} else {
124 			strcpy (msg, "T");
125 		}
126 		ret = rtrcmd (T, msg);
127 		r_cons_println (ret);
128 		free (ret);
129 		ret = rtrcmd (T, "Tl");
130 		lastmsg = atoi (ret)-1;
131 		free (ret);
132 		if (r_cons_fgets (buf, sizeof (buf), 0, NULL) < 0) {
133 			goto beach;
134 		}
135 		if (!*buf) {
136 			continue;
137 		}
138 		if (!strcmp (buf, "/help")) {
139 			eprintf ("/quit           quit the chat (same as ^D)\n");
140 			eprintf ("/nick <nick>    set cfg.user nick name\n");
141 			eprintf ("/log            show full log\n");
142 			eprintf ("/clear          clear text log messages\n");
143 		} else if (!strncmp (buf, "/nick ", 6)) {
144 			snprintf (msg, sizeof (msg) - 1, "* '%s' is now known as '%s'", me, buf+6);
145 			r_cons_println (msg);
146 			r_core_log_add (core, msg);
147 			r_config_set (core->config, "cfg.user", buf+6);
148 			me = r_config_get (core->config, "cfg.user");
149 			snprintf (prompt, sizeof (prompt) - 1, "[%s]> ", me);
150 			r_line_set_prompt (prompt);
151 		} else if (!strcmp (buf, "/log")) {
152 			char *ret = rtrcmd (T, "T");
153 			if (ret) {
154 				r_cons_println (ret);
155 				free (ret);
156 			}
157 		} else if (!strcmp (buf, "/clear")) {
158 			//r_core_log_del (core, 0);
159 			free (rtrcmd (T, "T-"));
160 		} else if (!strcmp (buf, "/quit")) {
161 			goto beach;
162 		} else if (*buf=='/') {
163 			eprintf ("Unknown command: %s\n", buf);
164 		} else {
165 			char *cmd = r_str_newf ("T [%s] %s", me, buf);
166 			free (rtrcmd (T, cmd));
167 			free (cmd);
168 		}
169 	}
170 beach:
171 	r_line_set_prompt (oldprompt);
172 	free (oldprompt);
173 }
174 
r_core_rtr_http_stop(RCore * u)175 R_API int r_core_rtr_http_stop(RCore *u) {
176 	RCore *core = (RCore*)u;
177 	const int timeout = 1; // 1 second
178 	const char *port;
179 	RSocket* sock;
180 
181 #if __WINDOWS__
182 	r_socket_http_server_set_breaked (&r_cons_singleton ()->context->breaked);
183 #endif
184 	if (((size_t)u) > 0xff) {
185 		port = listenport? listenport: r_config_get (
186 			core->config, "http.port");
187 		sock = r_socket_new (0);
188 		(void)r_socket_connect (sock, "localhost",
189 			port, R_SOCKET_PROTO_TCP, timeout);
190 		r_socket_free (sock);
191 	}
192 	r_socket_free (s);
193 	s = NULL;
194 	return 0;
195 }
196 
rtr_dir_files(const char * path)197 static char *rtr_dir_files(const char *path) {
198 	char *ptr = strdup ("<html><body>\n");
199 	const char *file;
200 	RListIter *iter;
201 	// list files
202 	RList *files = r_sys_dir (path);
203 	eprintf ("Listing directory %s\n", path);
204 	r_list_foreach (files, iter, file) {
205 		if (file[0] == '.') {
206 			continue;
207 		}
208 		ptr = r_str_appendf (ptr, "<a href=\"%s%s\">%s</a><br />\n",
209 			path, file, file);
210 	}
211 	r_list_free (files);
212 	return r_str_append (ptr, "</body></html>\n");
213 }
214 
215 #if __UNIX__
dietime(int sig)216 static void dietime(int sig) {
217 	eprintf ("It's Die Time!\n");
218 	exit (0);
219 }
220 #endif
221 
activateDieTime(RCore * core)222 static void activateDieTime(RCore *core) {
223 	int dt = r_config_get_i (core->config, "http.dietime");
224 	if (dt > 0) {
225 #if __UNIX__
226 		r_sys_signal (SIGALRM, dietime);
227 		alarm (dt);
228 #else
229 		eprintf ("http.dietime only works on *nix systems\n");
230 #endif
231 	}
232 }
233 
234 #include "rtr_http.c"
235 #include "rtr_shell.c"
236 
write_reg_val(char * buf,ut64 sz,ut64 reg,int regsize,bool bigendian)237 static int write_reg_val(char *buf, ut64 sz, ut64 reg, int regsize, bool bigendian) {
238 	if (!bigendian) {
239 		switch (regsize) {
240 		case 2:
241 			reg = r_swap_ut16 (reg);
242 			break;
243 		case 4:
244 			reg = r_swap_ut32 (reg);
245 			break;
246 		case 8:
247 			reg = r_swap_ut64 (reg);
248 			break;
249 		default:
250 			eprintf ("%s: Unsupported reg size: %d\n",
251 				 __func__, regsize);
252 			return -1;
253 		}
254 	}
255 	return snprintf (buf, sz, regsize == 2 ? "%04"PFMT64x
256 			 : regsize == 4 ? "%08"PFMT64x : "%016"PFMT64x, reg);
257 }
258 
write_big_reg(char * buf,ut64 sz,const utX * val,int regsize,bool bigendian)259 static int write_big_reg(char *buf, ut64 sz, const utX *val, int regsize, bool bigendian) {
260 	switch (regsize) {
261 	case 10:
262 		if (bigendian) {
263 			return snprintf (buf, sz,
264 					 "%04x%016"PFMT64x, val->v80.High,
265 					 val->v80.Low);
266 		}
267 		return snprintf (buf, sz,
268 				 "%016"PFMT64x"%04x", r_swap_ut64 (val->v80.Low),
269 				 r_swap_ut16 (val->v80.High));
270 	case 12:
271 		if (bigendian) {
272 			return snprintf (buf, sz,
273 					 "%08"PFMT32x"%016"PFMT64x, val->v96.High,
274 					 val->v96.Low);
275 		}
276 		return snprintf (buf, sz,
277 				 "%016"PFMT64x"%08"PFMT32x, r_swap_ut64 (val->v96.Low),
278 				 r_swap_ut32 (val->v96.High));
279 	case 16:
280 		if (bigendian) {
281 			return snprintf (buf, sz,
282 					 "%016"PFMT64x"%016"PFMT64x, val->v128.High,
283 					 val->v128.Low);
284 		}
285 		return snprintf (buf, sz,
286 				 "%016"PFMT64x"%016"PFMT64x,
287 				 r_swap_ut64 (val->v128.Low),
288 				 r_swap_ut64 (val->v128.High));
289 	default:
290 		eprintf ("%s: big registers (%d byte(s)) not yet supported\n",
291 			 __func__, regsize);
292 		return -1;
293 	}
294 }
295 
swap_big_regs(char * dest,ut64 sz,const char * src,int regsz)296 static int swap_big_regs(char *dest, ut64 sz, const char *src, int regsz) {
297 	utX val;
298 	char sdup[128] = {0};
299 	if (!src || !src[0] || !src[1]) {
300 		return -1;
301 	}
302 	strncpy (sdup, src + 2, sizeof (sdup) - 1);
303 	int len = strlen (sdup);
304 	memset (&val, 0, sizeof (val));
305 	switch (regsz) {
306 	case 10:
307 		if (len <= 4) {
308 			val.v80.High = (ut16) strtoul (sdup, NULL, 16);
309 		} else {
310 			val.v80.High = (ut16) strtoul (sdup + (len - 4), NULL, 16);
311 			sdup[len - 4] = '\0';
312 			val.v80.Low = (ut64) strtoull (sdup, NULL, 16);
313 		}
314 		return snprintf (dest, sz, "0x%04x%016"PFMT64x,
315 				 val.v80.High, val.v80.Low);
316 	case 12:
317 		if (len <= 8) {
318 			val.v96.High = (ut32) strtoul (sdup, NULL, 16);
319 		} else {
320 			val.v96.High = (ut32) strtoul (sdup + (len - 8), NULL, 16);
321 			sdup[len - 8] = '\0';
322 			val.v96.Low = (ut64) strtoull (sdup, NULL, 16);
323 		}
324 		return snprintf (dest, sz, "0x%08x%016"PFMT64x,
325 				 val.v96.High, val.v96.Low);
326 	case 16:
327 		if (len <= 16) {
328 			val.v128.High = (ut64) strtoul (sdup, NULL, 16);
329 		} else {
330 			val.v128.High = (ut64) strtoul (sdup + (len - 16), NULL, 16);
331 			sdup[len - 16] = '\0';
332 			val.v128.Low = (ut64) strtoull (sdup, NULL, 16);
333 		}
334 		return snprintf (dest, sz, "0x%016"PFMT64x"%016"PFMT64x,
335 				 val.v128.High, val.v128.Low);
336 	default:
337 		eprintf ("%s: big registers (%d byte(s)) not yet supported\n",
338 			 __func__, regsz);
339 		return -1;
340 	}
341 }
342 
r_core_rtr_gdb_cb(libgdbr_t * g,void * core_ptr,const char * cmd,char * out_buf,size_t max_len)343 static int r_core_rtr_gdb_cb(libgdbr_t *g, void *core_ptr, const char *cmd,
344 			     char *out_buf, size_t max_len) {
345 	int ret;
346 	RList *list;
347 	RListIter *iter;
348 	gdb_reg_t *gdb_reg;
349 	RRegItem *r;
350 	utX val_big;
351 	ut64 m_off, reg_val;
352 	bool be;
353 	RDebugPid *dbgpid;
354 	if (!core_ptr || ! cmd) {
355 		return -1;
356 	}
357 	RCore *core = (RCore*) core_ptr;
358 	switch (cmd[0]) {
359 	case '?': // Stop reason
360 		if (!out_buf) {
361 			return -1;
362 		}
363 		// dbg->reason.signum and dbg->reason.tid are not correct for native
364 		// debugger. This is a hack
365 		switch (core->dbg->reason.type) {
366 		case R_DEBUG_REASON_BREAKPOINT:
367 		case R_DEBUG_REASON_STEP:
368 		case R_DEBUG_REASON_TRAP:
369 		default: // remove when possible
370 			return snprintf (out_buf, max_len - 1, "T05thread:%x;",
371 					 core->dbg->tid);
372 		}
373 		// Fallback for when it's fixed
374 		/*
375 		return snprintf (out_buf, max_len - 1, "T%02xthread:%x;",
376 				 core->dbg->reason.type, core->dbg->reason.tid);
377 		*/
378 	case 'd':
379 		switch (cmd[1]) {
380 		case 'm': // dm
381 			if (snprintf (out_buf, max_len - 1, "%"PFMT64x, r_debug_get_baddr (core->dbg, NULL)) < 0) {
382 				return -1;
383 			}
384 			return 0;
385 		case 'p': // dp
386 			switch (cmd[2]) {
387 			case '\0': // dp
388 				// TODO support multiprocess
389 				snprintf (out_buf, max_len - 1, "QC%x", core->dbg->tid);
390 				return 0;
391 			case 't':
392 				switch (cmd[3]) {
393 				case '\0': // dpt
394 					if (!core->dbg->h->threads) {
395 						return -1;
396 					}
397 					if (!(list = core->dbg->h->threads(core->dbg, core->dbg->pid))) {
398 						return -1;
399 					}
400 					memset (out_buf, 0, max_len);
401 					out_buf[0] = 'm';
402 					ret = 1;
403 					r_list_foreach (list, iter, dbgpid) {
404 						// Max length of a hex pid = 8?
405 						if (ret >= max_len - 9) {
406 							break;
407 						}
408 						snprintf (out_buf + ret, max_len - ret - 1, "%x,", dbgpid->pid);
409 						ret = strlen (out_buf);
410 					}
411 					if (ret > 1) {
412 						ret--;
413 						out_buf[ret] = '\0';
414 					}
415 					return 0;
416 				case 'r': // dptr -> return current tid as int
417 					return core->dbg->tid;
418 				default:
419 					return r_core_cmd (core, cmd, 0);
420 				}
421 			}
422 			break;
423 		case 'r': // dr
424 			r_debug_reg_sync (core->dbg, R_REG_TYPE_ALL, false);
425 			be = r_config_get_i (core->config, "cfg.bigendian");
426 			if (isspace ((ut8)cmd[2])) { // dr reg
427 				const char *name, *val_ptr;
428 				char new_cmd[128] = { 0 };
429 				int off = 0;
430 				name = cmd + 3;
431 				// Temporarily using new_cmd to store reg name
432 				if ((val_ptr = strchr (name, '='))) {
433 					strncpy (new_cmd, name, R_MIN (val_ptr - name, sizeof (new_cmd) - 1));
434 				} else {
435 					strncpy (new_cmd, name, sizeof (new_cmd) - 1);
436 				}
437 				if (!(r = r_reg_get (core->dbg->reg, new_cmd, -1))) {
438 					return -1;
439 				}
440 				if (val_ptr) { // dr reg=val
441 					val_ptr++;
442 					off = val_ptr - cmd;
443 					if (be) {
444 						// We don't need to swap
445 						r_core_cmd (core, cmd, 0);
446 					}
447 					// Previous contents are overwritten, since len(name) < off
448 					strncpy (new_cmd, cmd, off);
449 					if (r->size <= 64) {
450 						reg_val = strtoll (val_ptr, NULL, 16);
451 						if (write_reg_val (new_cmd + off, sizeof (new_cmd) - off - 1,
452 								   reg_val, r->size / 8, be) < 0) {
453 							return -1;
454 						}
455 						return r_core_cmd (core, new_cmd, 0);
456 					}
457 					// Big registers
458 					if (swap_big_regs (new_cmd + off, sizeof (new_cmd) - off - 1,
459 							   val_ptr, r->size / 8) < 0) {
460 						return -1;
461 					}
462 					return r_core_cmd (core, new_cmd, 0);
463 				}
464 				if (r->size <= 64) {
465 					reg_val = r_reg_get_value (core->dbg->reg, r);
466 					return write_reg_val (out_buf, max_len - 1,
467 							      reg_val, r->size / 8, be);
468 				}
469 				r_reg_get_value_big (core->dbg->reg,
470 						     r, &val_big);
471 				return write_big_reg (out_buf, max_len - 1,
472 						      &val_big, r->size / 8, be);
473 			}
474 			// dr - Print all registers
475 			ret = 0;
476 			if (!(gdb_reg = g->registers)) {
477 				return -1;
478 			}
479 			while (*gdb_reg->name) {
480 				if (ret + gdb_reg->size * 2 >= max_len - 1) {
481 					return -1;
482 				}
483 				if (gdb_reg->size <= 8) {
484 					reg_val = r_reg_getv (core->dbg->reg, gdb_reg->name);
485 					if (write_reg_val (out_buf + ret,
486 							   gdb_reg->size * 2 + 1,
487 							   reg_val, gdb_reg->size, be) < 0) {
488 						return -1;
489 					}
490 				} else {
491 					r_reg_get_value_big (core->dbg->reg,
492 							     r_reg_get (core->dbg->reg, gdb_reg->name, -1),
493 							     &val_big);
494 					if (write_big_reg (out_buf + ret, gdb_reg->size * 2 + 1,
495 							   &val_big, gdb_reg->size, be) < 0) {
496 						return -1;
497 					}
498 				}
499 				ret += gdb_reg->size * 2;
500 				gdb_reg++;
501 			}
502 			out_buf[ret] = '\0';
503 			return ret;
504 		default:
505 			return r_core_cmd (core, cmd, 0);
506 		}
507 		break;
508 	case 'i':
509 		switch (cmd[1]) {
510 		case 'f':
511 		{
512 			ut64 off, len, sz, namelen;
513 			RIODesc *desc = core->io->desc;
514 			if (sscanf (cmd + 2, "%"PFMT64x",%"PFMT64x, &off, &len) != 2) {
515 				strcpy (out_buf, "E00");
516 				return 0;
517 			}
518 			namelen = desc ? strlen (desc->name) : 0;
519 			if (off >= namelen) {
520 				out_buf[0] = 'l';
521 				return 0;
522 			}
523 			sz = R_MIN (max_len, len + 2);
524 			len = snprintf (out_buf, sz, "l%s", desc ? (desc->name + off) : "");
525 			if (len >= sz) {
526 				// There's more left
527 				out_buf[0] = 'm';
528 			}
529 			return 0;
530 		}
531 		}
532 		break;
533 	case 'm':
534 		sscanf (cmd + 1, "%"PFMT64x",%x", &m_off, &ret);
535 		if (r_io_read_at (core->io, m_off, (ut8*) out_buf, ret)) {
536 			return ret;
537 		}
538 		return -1;
539 	default:
540 		return r_core_cmd (core, cmd, 0);
541 	}
542 	return -1;
543 }
544 
545 // path = "<port> <file_name>"
r_core_rtr_gdb_run(RCore * core,int launch,const char * path)546 static int r_core_rtr_gdb_run(RCore *core, int launch, const char *path) {
547 	RSocket *sock;
548 	int p, ret;
549 	bool debug_msg = false;
550 	char port[10];
551 	char *file = NULL, *args = NULL;
552 	libgdbr_t *g;
553 
554 	if (!core || !path) {
555 		return -1;
556 	}
557 	if (*path == '!') {
558 		debug_msg = true;
559 		path++;
560 	}
561 	if (!(path = r_str_trim_head_ro (path)) || !*path) {
562 		eprintf ("gdbserver: Port not specified\n");
563 		return -1;
564 	}
565 	if (!(p = atoi (path)) || p < 0 || p > 65535) {
566 		eprintf ("gdbserver: Invalid port: %s\n", port);
567 		return -1;
568 	}
569 	snprintf (port, sizeof (port) - 1, "%d", p);
570 	if (!(file = strchr (path, ' '))) {
571 		eprintf ("gdbserver: File not specified\n");
572 		return -1;
573 	}
574 	if (!(file = (char *)r_str_trim_head_ro (file)) || !*file) {
575 		eprintf ("gdbserver: File not specified\n");
576 		return -1;
577 	}
578 	args = strchr (file, ' ');
579 	if (args) {
580 		*args++ = '\0';
581 		if (!(args = (char *)r_str_trim_head_ro (args))) {
582 			args = "";
583 		}
584 	} else {
585 		args = "";
586 	}
587 
588 	if (!r_core_file_open (core, file, R_PERM_RX, 0)) {
589 		eprintf ("Cannot open file (%s)\n", file);
590 		return -1;
591 	}
592 	r_core_file_reopen_debug (core, args);
593 
594 	if (!(sock = r_socket_new (false))) {
595 		eprintf ("gdbserver: Could not open socket for listening\n");
596 		return -1;
597 	}
598 	if (!r_socket_listen (sock, port, NULL)) {
599 		r_socket_free (sock);
600 		eprintf ("gdbserver: Cannot listen on port: %s\n", port);
601 		return -1;
602 	}
603 	if (!(g = R_NEW0 (libgdbr_t))) {
604 		r_socket_free (sock);
605 		eprintf ("gdbserver: Cannot alloc libgdbr instance\n");
606 		return -1;
607 	}
608 	gdbr_init (g, true);
609 	g->server_debug = debug_msg;
610 	int arch = r_sys_arch_id (r_config_get (core->config, "asm.arch"));
611 	int bits = r_config_get_i (core->config, "asm.bits");
612 	gdbr_set_architecture (g, arch, bits);
613 	core->gdbserver_up = 1;
614 	eprintf ("gdbserver started on port: %s, file: %s\n", port, file);
615 
616 	for (;;) {
617 		if (!(g->sock = r_socket_accept (sock))) {
618 			break;
619 		}
620 		g->connected = 1;
621 		ret = gdbr_server_serve (g, r_core_rtr_gdb_cb, (void*) core);
622 		r_socket_close (g->sock);
623 		g->connected = 0;
624 		if (ret < 0) {
625 			break;
626 		}
627 	}
628 	core->gdbserver_up = 0;
629 	gdbr_cleanup (g);
630 	free (g);
631 	r_socket_free (sock);
632 	return 0;
633 }
634 
r_core_rtr_gdb(RCore * core,int launch,const char * path)635 R_API int r_core_rtr_gdb(RCore *core, int launch, const char *path) {
636 	int ret;
637 	if (r_sandbox_enable (0)) {
638 		eprintf ("sandbox: connect disabled\n");
639 		return -1;
640 	}
641 	// TODO: do stuff with launch
642 	if (core->gdbserver_up) {
643 		eprintf ("gdbserver is already running\n");
644 		return -1;
645 	}
646 	ret = r_core_rtr_gdb_run (core, launch, path);
647 	return ret;
648 }
649 
r_core_rtr_pushout(RCore * core,const char * input)650 R_API void r_core_rtr_pushout(RCore *core, const char *input) {
651 	int fd = atoi (input);
652 	const char *cmd = NULL;
653 	char *str = NULL;
654 	if (fd) {
655 		for (rtr_n = 0; rtr_host[rtr_n].fd && rtr_n < RTR_MAX_HOSTS - 1; rtr_n++) {
656 			if (rtr_host[rtr_n].fd->fd != fd) {
657 				continue;
658 			}
659 		}
660 		if (!(cmd = strchr (input, ' '))) {
661 			eprintf ("Error\n");
662 			return;
663 		}
664 	} else {
665 		cmd = input;
666 	}
667 
668 	if (!rtr_host[rtr_n].fd || !rtr_host[rtr_n].fd->fd) {
669 		eprintf ("Error: Unknown host\n");
670 		return;
671 	}
672 
673 	if (!(str = r_core_cmd_str (core, cmd))) {
674 		eprintf ("Error: radare_cmd_str returned NULL\n");
675 		return;
676 	}
677 
678 	switch (rtr_host[rtr_n].proto) {
679 	case RTR_PROTOCOL_RAP:
680 		eprintf ("Error: Cannot use '=<' to a rap connection.\n");
681 		break;
682 	case RTR_PROTOCOL_UNIX:
683 		r_socket_write (rtr_host[rtr_n].fd, str, strlen (str));
684 		break;
685 	case RTR_PROTOCOL_HTTP:
686 		eprintf ("TODO\n");
687 		break;
688 	case RTR_PROTOCOL_TCP:
689 	case RTR_PROTOCOL_UDP:
690 		r_socket_write (rtr_host[rtr_n].fd, str, strlen (str));
691 		break;
692 	default:
693 		eprintf ("Unknown protocol\n");
694 		break;
695 	}
696 	free (str);
697 }
698 
r_core_rtr_list(RCore * core)699 R_API void r_core_rtr_list(RCore *core) {
700 	int i;
701 	for (i = 0; i < RTR_MAX_HOSTS; i++) {
702 		if (!rtr_host[i].fd) {
703 			continue;
704 		}
705 		const char *proto = "rap";
706 		switch (rtr_host[i].proto) {
707 		case RTR_PROTOCOL_HTTP: proto = "http"; break;
708 		case RTR_PROTOCOL_TCP: proto = "tcp"; break;
709 		case RTR_PROTOCOL_UDP: proto = "udp"; break;
710 		case RTR_PROTOCOL_RAP: proto = "rap"; break;
711 		case RTR_PROTOCOL_UNIX: proto = "unix"; break;
712 		}
713 		r_cons_printf ("%d fd:%i %s://%s:%i/%s\n",
714 			i, rtr_host[i].fd->fd, proto, rtr_host[i].host,
715 			rtr_host[i].port, rtr_host[i].file);
716 	}
717 }
718 
r_core_rtr_add(RCore * core,const char * _input)719 R_API void r_core_rtr_add(RCore *core, const char *_input) {
720 	char *port, input[1024], *file = NULL, *ptr = NULL;
721 	int i, timeout, ret;
722 	RSocket *fd;
723 
724 	timeout = r_config_get_i (core->config, "http.timeout");
725 	strncpy (input, _input, sizeof (input) - 4);
726 	input[sizeof (input) - 4] = '\0';
727 
728 	int proto = RTR_PROTOCOL_RAP;
729 	char *host = (char *)r_str_trim_head_ro (input);
730 	char *pikaboo = strstr (host, "://");
731 	if (pikaboo) {
732 		struct {
733 			const char *name;
734 			int protocol;
735 		} uris[7] = {
736 			{"tcp", RTR_PROTOCOL_TCP},
737 			{"udp", RTR_PROTOCOL_UDP},
738 			{"rap", RTR_PROTOCOL_RAP},
739 			{"r2p", RTR_PROTOCOL_RAP},
740 			{"http", RTR_PROTOCOL_HTTP},
741 			{"unix", RTR_PROTOCOL_UNIX},
742 			{NULL, 0}
743 		};
744 		char *s = r_str_ndup (input, pikaboo - input);
745 		//int nlen = pikaboo - input;
746 		for (i = 0; uris[i].name; i++) {
747 			if (r_str_endswith (s, uris[i].name)) {
748 				proto = uris[i].protocol;
749 				host = pikaboo + 3;
750 				break;
751 			}
752 		}
753 		free (s);
754 	}
755 	if (host) {
756 		if (!(ptr = strchr (host, ':'))) {
757 			ptr = host;
758 			port = "80";
759 		} else {
760 			*ptr++ = '\0';
761 			port = ptr;
762 			r_str_trim (port);
763 		}
764 	} else {
765 		port = NULL;
766 	}
767 	file = strchr (ptr, '/');
768 	if (file) {
769 		*file = 0;
770 		file = (char *)r_str_trim_head_ro (file + 1);
771 	} else {
772 		if (*host == ':' || strstr (host, "://:")) { // listen
773 			// it's fine to listen without serving a file
774 		} else {
775 			file = "cmd/";
776 			eprintf ("Error: Missing '/'\n");
777 			//c:wreturn;
778 		}
779 	}
780 
781 	if (r_sandbox_enable (0)) {
782 		eprintf ("sandbox: connect disabled\n");
783 		return;
784 	}
785 
786 	fd = r_socket_new (false);
787 	if (!fd) {
788 		eprintf ("Error: Cannot create new socket\n");
789 		return;
790 	}
791 	switch (proto) {
792 	case RTR_PROTOCOL_HTTP:
793 		{
794 			int len;
795 			char *uri = r_str_newf ("http://%s:%s/%s", host, port, file);
796 			char *str = r_socket_http_get (uri, NULL, &len);
797 			if (!str) {
798 				eprintf ("Cannot find peer\n");
799 				return;
800 			}
801 			core->num->value = 0;
802 			// eprintf ("Connected to: 'http://%s:%s'\n", host, port);
803 			free (str);
804 		}
805 		break;
806 	case RTR_PROTOCOL_RAP:
807 		if (!r_socket_connect_tcp (fd, host, port, timeout)) { //TODO: Use rap.ssl
808 			eprintf ("Error: Cannot connect to '%s' (%s)\n", host, port);
809 			r_socket_free (fd);
810 			return;
811 		} else {
812 			int n = r_socket_rap_client_open (fd, file, 0);
813 			eprintf ("opened as fd = %d\n", n);
814 		}
815 		break;
816 	case RTR_PROTOCOL_UNIX:
817 		if (!r_socket_connect_unix (fd, host)) {
818 			core->num->value = 1;
819 			eprintf ("Error: Cannot connect to 'unix://%s'\n", host);
820 			r_socket_free (fd);
821 			return;
822 		}
823 		core->num->value = 0;
824 		eprintf ("Connected to: 'unix://%s'\n", host);
825 		break;
826 	case RTR_PROTOCOL_TCP:
827 		if (!r_socket_connect_tcp (fd, host, port, timeout)) { //TODO: Use rap.ssl
828 			core->num->value = 1;
829 			eprintf ("Error: Cannot connect to '%s' (%s)\n", host, port);
830 			r_socket_free (fd);
831 			return;
832 		}
833 		core->num->value = 0;
834 		eprintf ("Connected to: %s at port %s\n", host, port);
835 		break;
836 	case RTR_PROTOCOL_UDP:
837 		if (!r_socket_connect_udp (fd, host, port, timeout)) { //TODO: Use rap.ssl
838 			core->num->value = 1;
839 			eprintf ("Error: Cannot connect to '%s' (%s)\n", host, port);
840 			r_socket_free (fd);
841 			return;
842 		}
843 		core->num->value = 0;
844 		eprintf ("Connected to: %s at port %s\n", host, port);
845 		break;
846 	}
847 	ret = core->num->value;
848 	for (i = 0; i < RTR_MAX_HOSTS; i++) {
849 		if (rtr_host[i].fd) {
850 			continue;
851 		}
852 		rtr_host[i].proto = proto;
853 		strncpy (rtr_host[i].host, host, sizeof (rtr_host[i].host)-1);
854 		rtr_host[i].port = r_num_get (core->num, port);
855 		if (!file) {
856 			file = "";
857 		}
858 		strncpy (rtr_host[i].file, file, sizeof (rtr_host[i].file)-1);
859 		rtr_host[i].fd = fd;
860 		rtr_n = i;
861 		break;
862 	}
863 	core->num->value = ret;
864 	// double free wtf is freed this here? r_socket_free(fd);
865 	//r_core_rtr_list (core);
866 }
867 
r_core_rtr_remove(RCore * core,const char * input)868 R_API void r_core_rtr_remove(RCore *core, const char *input) {
869 	int i;
870 
871 	if (IS_DIGIT (input[0])) {
872 		i = r_num_math (core->num, input);
873 		if (i >= 0 && i < RTR_MAX_HOSTS) {
874 			r_socket_free (rtr_host[i].fd);
875 			rtr_host[i].fd = NULL;
876 		}
877 	} else {
878 		for (i = 0; i < RTR_MAX_HOSTS; i++) {
879 			if (rtr_host[i].fd) {
880 				r_socket_free (rtr_host[i].fd);
881 				rtr_host[i].fd = NULL;
882 			}
883 		}
884 		memset (rtr_host, '\0', RTR_MAX_HOSTS * sizeof (RCoreRtrHost));
885 		rtr_n = 0;
886 	}
887 }
888 
r_core_rtr_session(RCore * core,const char * input)889 R_API void r_core_rtr_session(RCore *core, const char *input) {
890 	__rtr_shell (core, atoi (input));
891 }
892 
r_core_rtr_rap_run(RCore * core,const char * input)893 static bool r_core_rtr_rap_run(RCore *core, const char *input) {
894 	char *file = r_str_newf ("rap://%s", input);
895 	int flags = R_PERM_RW;
896 	RIODesc *fd = r_io_open_nomap (core->io, file, flags, 0644);
897 	if (fd) {
898 		if (r_io_is_listener (core->io)) {
899 			if (!r_core_serve (core, fd)) {
900 				r_cons_singleton ()->context->breaked = true;
901 			}
902 			r_io_desc_close (fd);
903 			// avoid double free, we are not the owners of this fd so we can't destroy it
904 			//r_io_desc_free (fd);
905 		}
906 	} else {
907 		r_cons_singleton ()->context->breaked = true;
908 	}
909 	return !r_cons_singleton ()->context->breaked;
910 	// r_core_cmdf (core, "o rap://%s", input);
911 }
912 
r_core_rtr_rap_thread(RThread * th)913 static RThreadFunctionRet r_core_rtr_rap_thread(RThread *th) {
914 	if (!th) {
915 		return false;
916 	}
917 	RapThread *rt = th->user;
918 	if (!rt || !rt->core) {
919 		return false;
920 	}
921 	return r_core_rtr_rap_run (rt->core, rt->input) ? R_TH_REPEAT : R_TH_STOP;
922 }
923 
r_core_rtr_cmd(RCore * core,const char * input)924 R_API void r_core_rtr_cmd(RCore *core, const char *input) {
925 	unsigned int cmd_len = 0;
926 	int fd = atoi (input);
927 	if (!fd && *input != '0') {
928 		fd = -1;
929 	}
930 	const char *cmd = strchr (r_str_trim_head_ro (input), ' ');
931 	if (cmd) {
932 		cmd ++;
933 		cmd_len = strlen (cmd);
934 	}
935 	// "=:"
936 	if (*input == ':' && !strchr (input + 1, ':')) {
937 		void *bed = r_cons_sleep_begin ();
938 		r_core_rtr_rap_run (core, input);
939 		r_cons_sleep_end (bed);
940 		return;
941 	}
942 
943 	if (*input == '&') { // "=h&" "=&:9090"
944 		if (rapthread) {
945 			eprintf ("RAP Thread is already running\n");
946 			eprintf ("This is experimental and probably buggy. Use at your own risk\n");
947 		} else {
948 			// TODO: use tasks
949 			RapThread *RT = R_NEW0 (RapThread);
950 			if (RT) {
951 				RT->core = core;
952 				RT->input = strdup (input + 1);
953 				//RapThread rt = { core, strdup (input + 1) };
954 				rapthread = r_th_new (r_core_rtr_rap_thread, RT, false);
955 				int cpuaff = (int)r_config_get_i (core->config, "cfg.cpuaffinity");
956 				r_th_setaffinity (rapthread, cpuaff);
957 				r_th_setname (rapthread, "rapthread");
958 				r_th_start (rapthread, true);
959 				eprintf ("Background rap server started.\n");
960 			}
961 		}
962 		return;
963 	}
964 
965 	if (fd != -1) {
966 		if (fd >= 0 && fd < RTR_MAX_HOSTS) {
967 			rtr_n = fd;
968 		} else {
969 			fd = -1;
970 		}
971 	} else {
972 		// XXX
973 		cmd = input;
974 	}
975 
976 	if (!rtr_host[rtr_n].fd) {
977 		eprintf ("Error: Unknown host\n");
978 		core->num->value = 1; // fail
979 		return;
980 	}
981 
982 	if (rtr_host[rtr_n].proto == RTR_PROTOCOL_TCP) {
983 		RCoreRtrHost *rh = &rtr_host[rtr_n];
984 		RSocket *s = rh->fd;
985 		if (cmd_len < 1 || cmd_len > 16384) {
986 			return;
987 		}
988 		r_socket_close (s);
989 		if (!r_socket_connect (s, rh->host, sdb_fmt ("%d", rh->port), R_SOCKET_PROTO_TCP, 0)) {
990 			eprintf ("Error: Cannot connect to '%s' (%d)\n", rh->host, rh->port);
991 			r_socket_free (s);
992 			return;
993 		}
994 		r_socket_write (s, (ut8*)cmd, cmd_len);
995 		r_socket_write (s, "\n", 2);
996 		int maxlen = 4096; // r_read_le32 (blen);
997 		char *cmd_output = calloc (1, maxlen + 1);
998 		if (!cmd_output) {
999 			eprintf ("Error: Allocating cmd output\n");
1000 			return;
1001 		}
1002 		(void)r_socket_read_block (s, (ut8*)cmd_output, maxlen);
1003 		//ensure the termination
1004 		r_socket_close (s);
1005 		cmd_output[maxlen] = 0;
1006 		r_cons_println (cmd_output);
1007 		free ((void *)cmd_output);
1008 		return;
1009 	}
1010 
1011 	if (rtr_host[rtr_n].proto == RTR_PROTOCOL_HTTP) {
1012 		RCoreRtrHost *rh = &rtr_host[rtr_n];
1013 		if (cmd_len < 1 || cmd_len > 16384) {
1014 			return;
1015 		}
1016 		int len;
1017 		char *uri = r_str_newf ("http://%s:%d/cmd/%s", rh->host, rh->port, cmd);
1018 		char *str = r_socket_http_get (uri, NULL, &len);
1019 		if (!str) {
1020 			eprintf ("Cannot find '%s'\n", uri);
1021 			return;
1022 		}
1023 		core->num->value = 0;
1024 		str[len] = 0;
1025 		r_cons_print (str);
1026 		free ((void *)str);
1027 		free ((void *)uri);
1028 		return;
1029 	}
1030 
1031 	if (rtr_host[rtr_n].proto == RTR_PROTOCOL_RAP) {
1032 		core->num->value = 0; // that's fine
1033 		cmd = r_str_trim_head_ro (cmd);
1034 		RSocket *fh = rtr_host[rtr_n].fd;
1035 		if (!strlen (cmd)) {
1036 			// just check if we can connect
1037 			r_socket_close (fh);
1038 			return;
1039 		}
1040 		char *cmd_output = r_socket_rap_client_command (fh, cmd, &core->anal->coreb);
1041 		r_cons_println (cmd_output);
1042 		free (cmd_output);
1043 		return;
1044 	}
1045 	eprintf ("Error: Unknown protocol\n");
1046 }
1047 
1048 // TODO: support len for binary data?
r_core_rtr_cmds_query(RCore * core,const char * host,const char * port,const char * cmd)1049 R_API char *r_core_rtr_cmds_query (RCore *core, const char *host, const char *port, const char *cmd) {
1050 	RSocket *s = r_socket_new (0);
1051 	const int timeout = 0;
1052 	char *rbuf = NULL;
1053 	int retries = 6;
1054 	ut8 buf[1024];
1055 
1056 	for (; retries > 0; r_sys_usleep (10 * 1000)) {
1057 		if (r_socket_connect (s, host, port, R_SOCKET_PROTO_TCP, timeout)) {
1058 			break;
1059 		}
1060 		retries--;
1061 	}
1062 	if (retries > 0) {
1063 		rbuf = strdup ("");
1064 		r_socket_write (s, (void*)cmd, strlen (cmd));
1065 		//r_socket_write (s, "px\n", 3);
1066 		for (;;) {
1067 			int ret = r_socket_read (s, buf, sizeof (buf));
1068 			if (ret < 1) {
1069 				break;
1070 			}
1071 			buf[ret] = 0;
1072 			rbuf = r_str_append (rbuf, (const char *)buf);
1073 		}
1074 	} else {
1075 		eprintf ("Cannot connect\n");
1076 	}
1077 	r_socket_free (s);
1078 	return rbuf;
1079 }
1080 
1081 #if HAVE_LIBUV
1082 
1083 typedef struct rtr_cmds_context_t {
1084 	uv_tcp_t server;
1085 	RPVector clients;
1086 	void *bed;
1087 } rtr_cmds_context;
1088 
1089 typedef struct rtr_cmds_client_context_t {
1090 	RCore *core;
1091 	char buf[4096];
1092 	char *res;
1093 	size_t len;
1094 	uv_tcp_t *client;
1095 } rtr_cmds_client_context;
1096 
rtr_cmds_client_close(uv_tcp_t * client,bool remove)1097 static void rtr_cmds_client_close(uv_tcp_t *client, bool remove) {
1098 	uv_loop_t *loop = client->loop;
1099 	rtr_cmds_context *context = loop->data;
1100 	if (remove) {
1101 		size_t i;
1102 		for (i = 0; i < r_pvector_len (&context->clients); i++) {
1103 			if (r_pvector_at (&context->clients, i) == client) {
1104 				r_pvector_remove_at (&context->clients, i);
1105 				break;
1106 			}
1107 		}
1108 	}
1109 	rtr_cmds_client_context *client_context = client->data;
1110 	uv_close ((uv_handle_t *) client, (uv_close_cb) free);
1111 	free (client_context->res);
1112 	free (client_context);
1113 }
1114 
rtr_cmds_alloc_buffer(uv_handle_t * handle,size_t suggested_size,uv_buf_t * buf)1115 static void rtr_cmds_alloc_buffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf) {
1116 	rtr_cmds_client_context *context = handle->data;
1117 	buf->base = context->buf + context->len;
1118 	buf->len = sizeof (context->buf) - context->len - 1;
1119 }
1120 
rtr_cmds_write(uv_write_t * req,int status)1121 static void rtr_cmds_write(uv_write_t *req, int status) {
1122 	rtr_cmds_client_context *context = req->data;
1123 
1124 	if (status) {
1125 		eprintf ("Write error: %s\n", uv_strerror (status));
1126 	}
1127 
1128 	free (req);
1129 	rtr_cmds_client_close (context->client, true);
1130 }
1131 
rtr_cmds_read(uv_stream_t * client,ssize_t nread,const uv_buf_t * buf)1132 static void rtr_cmds_read(uv_stream_t *client, ssize_t nread, const uv_buf_t *buf) {
1133 	rtr_cmds_context *context = client->loop->data;
1134 	rtr_cmds_client_context *client_context = client->data;
1135 
1136 	if (nread < 0) {
1137 		if (nread != UV_EOF) {
1138 			eprintf ("Failed to read: %s\n", uv_err_name ((int) nread));
1139 		}
1140 		rtr_cmds_client_close ((uv_tcp_t *) client, true);
1141 		return;
1142 	} else if (nread == 0) {
1143 		return;
1144 	}
1145 
1146 	buf->base[nread] = '\0';
1147 	char *end = strchr (buf->base, '\n');
1148 	if (!end) {
1149 		return;
1150 	}
1151 	*end = '\0';
1152 
1153 	r_cons_sleep_end (context->bed);
1154 	client_context->res = r_core_cmd_str (client_context->core, (const char *)client_context->buf);
1155 	context->bed = r_cons_sleep_begin ();
1156 
1157 	if (!client_context->res || !*client_context->res) {
1158 		free (client_context->res);
1159 		client_context->res = strdup ("\n");
1160 	}
1161 
1162 	if (!client_context->res || (!r_config_get_i (client_context->core->config, "scr.prompt") &&
1163 				 !strcmp ((char *)buf, "q!")) ||
1164 				 !strcmp ((char *)buf, ".--")) {
1165 		rtr_cmds_client_close ((uv_tcp_t *) client, true);
1166 		return;
1167 	}
1168 
1169 	uv_write_t *req = R_NEW (uv_write_t);
1170 	if (req) {
1171 		req->data = client_context;
1172 		uv_buf_t wrbuf = uv_buf_init (client_context->res, (unsigned int) strlen (client_context->res));
1173 		uv_write (req, client, &wrbuf, 1, rtr_cmds_write);
1174 	}
1175 	uv_read_stop (client);
1176 }
1177 
rtr_cmds_new_connection(uv_stream_t * server,int status)1178 static void rtr_cmds_new_connection(uv_stream_t *server, int status) {
1179 	if (status < 0) {
1180 		eprintf ("New connection error: %s\n", uv_strerror (status));
1181 		return;
1182 	}
1183 
1184 	rtr_cmds_context *context = server->loop->data;
1185 
1186 	uv_tcp_t *client = R_NEW (uv_tcp_t);
1187 	if (!client) {
1188 		return;
1189 	}
1190 
1191 	uv_tcp_init (server->loop, client);
1192 	if (uv_accept (server, (uv_stream_t *)client) == 0) {
1193 		rtr_cmds_client_context *client_context = R_NEW (rtr_cmds_client_context);
1194 		if (!client_context) {
1195 			uv_close ((uv_handle_t *)client, NULL);
1196 			return;
1197 		}
1198 
1199 		client_context->core = server->data;
1200 		client_context->len = 0;
1201 		client_context->buf[0] = '\0';
1202 		client_context->res = NULL;
1203 		client_context->client = client;
1204 		client->data = client_context;
1205 
1206 		uv_read_start ((uv_stream_t *)client, rtr_cmds_alloc_buffer, rtr_cmds_read);
1207 
1208 		r_pvector_push (&context->clients, client);
1209 	} else {
1210 		uv_close ((uv_handle_t *)client, NULL);
1211 	}
1212 }
1213 
rtr_cmds_stop(uv_async_t * handle)1214 static void rtr_cmds_stop(uv_async_t *handle) {
1215 	uv_close ((uv_handle_t *) handle, NULL);
1216 
1217 	rtr_cmds_context *context = handle->loop->data;
1218 
1219 	uv_close ((uv_handle_t *) &context->server, NULL);
1220 
1221 	void **it;
1222 	r_pvector_foreach (&context->clients, it) {
1223 		uv_tcp_t *client = *it;
1224 		rtr_cmds_client_close (client, false);
1225 	}
1226 }
1227 
rtr_cmds_break(uv_async_t * async)1228 static void rtr_cmds_break(uv_async_t *async) {
1229 	uv_async_send (async);
1230 }
1231 
r_core_rtr_cmds(RCore * core,const char * port)1232 R_API int r_core_rtr_cmds(RCore *core, const char *port) {
1233 	if (!port || port[0] == '?') {
1234 		r_cons_printf ("Usage: .:[tcp-port]    run r2 commands for clients\n");
1235 		return 0;
1236 	}
1237 
1238 	uv_loop_t *loop = R_NEW (uv_loop_t);
1239 	if (!loop) {
1240 		return 0;
1241 	}
1242 	uv_loop_init (loop);
1243 
1244 	rtr_cmds_context context;
1245 	r_pvector_init (&context.clients, NULL);
1246 	loop->data = &context;
1247 
1248 	context.server.data = core;
1249 	uv_tcp_init (loop, &context.server);
1250 
1251 	struct sockaddr_in addr;
1252 	bool local = (bool) r_config_get_i(core->config, "tcp.islocal");
1253 	int porti = r_socket_port_by_name (port);
1254 	uv_ip4_addr (local ? "127.0.0.1" : "0.0.0.0", porti, &addr);
1255 
1256 	uv_tcp_bind (&context.server, (const struct sockaddr *) &addr, 0);
1257 	int r = uv_listen ((uv_stream_t *)&context.server, 32, rtr_cmds_new_connection);
1258 	if (r) {
1259 		eprintf ("Failed to listen: %s\n", uv_strerror (r));
1260 		goto beach;
1261 	}
1262 
1263 	uv_async_t stop_async;
1264 	uv_async_init (loop, &stop_async, rtr_cmds_stop);
1265 
1266 	r_cons_break_push ((RConsBreak) rtr_cmds_break, &stop_async);
1267 	context.bed = r_cons_sleep_begin ();
1268 	uv_run (loop, UV_RUN_DEFAULT);
1269 	r_cons_sleep_end (context.bed);
1270 	r_cons_break_pop ();
1271 
1272 beach:
1273 	uv_loop_close (loop);
1274 	free (loop);
1275 	r_pvector_clear (&context.clients);
1276 	return 0;
1277 }
1278 
1279 #else
1280 
r_core_rtr_cmds(RCore * core,const char * port)1281 R_API int r_core_rtr_cmds (RCore *core, const char *port) {
1282 	unsigned char buf[4097];
1283 	RSocket *ch = NULL;
1284 	int i, ret;
1285 	char *str;
1286 
1287 	if (!port || port[0] == '?') {
1288 		r_cons_printf ("Usage: .:[tcp-port]    run r2 commands for clients\n");
1289 		return false;
1290 	}
1291 
1292 	RSocket *s = r_socket_new (0);
1293 	s->local = r_config_get_i (core->config, "tcp.islocal");
1294 
1295 	if (!r_socket_listen (s, port, NULL)) {
1296 		eprintf ("Error listening on port %s\n", port);
1297 		r_socket_free (s);
1298 		return false;
1299 	}
1300 
1301 	eprintf ("Listening for commands on port %s\n", port);
1302 	listenport = port;
1303 	r_cons_break_push ((RConsBreak)r_core_rtr_http_stop, core);
1304 	for (;;) {
1305 		if (r_cons_is_breaked ()) {
1306 			break;
1307 		}
1308 		void *bed = r_cons_sleep_begin ();
1309 		ch = r_socket_accept (s);
1310 		buf[0] = 0;
1311 		ret = r_socket_read (ch, buf, sizeof (buf) - 1);
1312 		r_cons_sleep_end (bed);
1313 		if (ret > 0) {
1314 			buf[ret] = 0;
1315 			for (i = 0; buf[i]; i++) {
1316 				if (buf[i] == '\n') {
1317 					buf[i] = buf[i + 1]? ';': '\0';
1318 				}
1319 			}
1320 			if ((!r_config_get_i (core->config, "scr.prompt") &&
1321 			     !strcmp ((char *)buf, "q!")) ||
1322 			    !strcmp ((char *)buf, ".--")) {
1323 				r_socket_close (ch);
1324 				break;
1325 			}
1326 			str = r_core_cmd_str (core, (const char *)buf);
1327 			bed = r_cons_sleep_begin ();
1328 			if (str && *str)  {
1329 				r_socket_write (ch, str, strlen (str));
1330 			} else {
1331 				r_socket_write (ch, "\n", 1);
1332 			}
1333 			r_cons_sleep_end (bed);
1334 			free (str);
1335 		}
1336 		r_socket_close (ch);
1337 		r_socket_free (ch);
1338 		ch = NULL;
1339 	}
1340 	r_cons_break_pop ();
1341 	r_socket_free (s);
1342 	r_socket_free (ch);
1343 	return 0;
1344 }
1345 
1346 #endif
1347