22#if ENABLE_CONTROL_SOCKET
27#include <netinet/in.h>
30#include <sys/socket.h>
42enum control_req_stage {
53 enum control_req_stage stage;
61static int control_fd = -1;
62static char *control_path = NULL;
66static struct control_req *bw_waiting_req = NULL;
68static void handle_wait_timeout(
void *data);
77Control_read_fd(
int fd,
Dstr *output)
83 _MSG(
"read buf = %zd\n", r);
87 }
else if (errno == EAGAIN || errno == EWOULDBLOCK) {
103Control_write_fd(
int fd,
Dstr *input,
size_t *ptr_offset)
105 size_t offset = *ptr_offset;
108 while ((
size_t) input->
len > offset) {
109 const char *src = input->
str + offset;
110 size_t left = input->
len - offset;
111 w = write(fd, src, left);
113 if (errno == EINTR) {
115 }
else if (errno == EAGAIN || errno == EWOULDBLOCK) {
117 *ptr_offset = offset;
129 *ptr_offset = offset;
135static struct control_req *Control_req_new(
int fd)
137 struct control_req *req =
dMalloc0(
sizeof(
struct control_req));
142 req->stage = REQ_READ_COMMAND;
147static void Control_req_free(
struct control_req *req)
155static void Control_req_read_cmd(
struct control_req *req)
162 r = read(req->fd, buf, 1);
164 if (errno == EINTR) {
166 }
else if (errno == EAGAIN || errno == EWOULDBLOCK) {
181 if (err || req->cmd->len == 0) {
184 req->stage = REQ_CLOSE;
187 char *cmd = req->cmd->str;
188 for (
char *p = cmd; *p !=
'\0'; p++) {
189 if (*p ==
'\n' || *p ==
'\r') {
196 if (!strcmp(cmd,
"load") || !strcmp(cmd,
"rawload"))
197 req->stage = REQ_READ_BODY;
199 req->stage = REQ_PREPARE_REPLY;
203static void Control_req_prepare_reply(
struct control_req *req)
206 const char *cmd = req->cmd->str;
207 Dstr *r = req->reply;
210 if (strcmp(cmd,
"help") == 0) {
212 dStr_sprintfa(r,
"Commands return 0 on success or non-zero on error.\n");
214 dStr_sprintfa(r,
" ping Check if dillo replies correctly:\n");
215 dStr_sprintfa(r,
" pid Print PID of selected dillo process\n");
217 dStr_sprintfa(r,
" ready Exits with 0 if finished loading, 1 otherwise\n");
218 dStr_sprintfa(r,
" open URL Open the given URL in the current tab\n");
220 dStr_sprintfa(r,
" title Print the title of page in the current tab\n");
221 dStr_sprintfa(r,
" status [MSG] Set the status bar to MSG\n");
222 dStr_sprintfa(r,
" dump Print the content of the current tab\n");
223 dStr_sprintfa(r,
" hdump Print the HTTP headers of the current tab\n");
224 dStr_sprintfa(r,
" load Replace the content in the current tab by stdin\n");
225 dStr_sprintfa(r,
" rawload Replace the HTTP headers and content of the current\n");
228 dStr_sprintfa(r,
" wait [T] Wait until the current tab has finished loading\n");
229 dStr_sprintfa(r,
" at most T seconds (default 60.0). Wait forever with\n");
231 }
else if (strcmp(cmd,
"ping") == 0) {
233 }
else if (strcmp(cmd,
"pid") == 0) {
235 }
else if (strcmp(cmd,
"reload") == 0) {
238 }
else if (strcmp(cmd,
"ready") == 0) {
240 }
else if (strncmp(cmd,
"open ", 5) == 0) {
243 }
else if (strcmp(cmd,
"url") == 0) {
245 }
else if (strcmp(cmd,
"title") == 0) {
251 }
else if (!strcmp(cmd,
"status") || !strncmp(cmd,
"status ", 7)) {
257 }
else if (strcmp(cmd,
"dump") == 0) {
265 }
else if (strcmp(cmd,
"hdump") == 0) {
268 if (header == NULL) {
275 }
else if (strcmp(cmd,
"load") == 0) {
286 }
else if (strcmp(cmd,
"rawload") == 0) {
296 }
else if (strcmp(cmd,
"quit") == 0) {
299 }
else if (strncmp(cmd,
"cmd ", 4) == 0) {
300 const char *cmdname = cmd + 4;
303 }
else if (strcmp(cmd,
"wait") == 0 || strncmp(cmd,
"wait ", 5) == 0) {
304 float timeout = 60.0f;
307 timeout = atof(&cmd[5]);
315 bw_waiting_req = req;
327 req->stage = REQ_SWITCH_WRITE;
331static void Control_req_read_cb(
int fd,
void *data)
333 struct control_req *req = data;
337 if (req->stage == REQ_READ_COMMAND)
338 Control_req_read_cmd(req);
340 if (req->stage == REQ_READ_BODY) {
342 int ret = Control_read_fd(fd, req->body);
344 req->stage = REQ_PREPARE_REPLY;
346 req->stage = REQ_CLOSE;
349 if (req->stage == REQ_PREPARE_REPLY)
350 Control_req_prepare_reply(req);
352 if (req->stage == REQ_SWITCH_WRITE) {
356 req->stage = REQ_WRITE_REPLY;
359 if (req->stage == REQ_WRITE_REPLY) {
361 if (Control_write_fd(fd, req->reply, &req->reply_offset) <= 0)
362 req->stage = REQ_CLOSE;
365 if (req->stage == REQ_CLOSE) {
369 Control_req_free(req);
374static void Control_listen_cb(
int fd,
void *data)
376 _MSG(
"Control_listen_cb called\n");
378 int new_fd = accept(control_fd, NULL, NULL);
380 if (errno == EAGAIN || errno == EWOULDBLOCK) {
384 MSG_ERR(
"accept failed: %s\n", strerror(errno));
401 if (fcntl(new_fd, F_SETFL, O_NONBLOCK) == -1) {
402 MSG_ERR(
"control socket fcntl failed: %s\n", strerror(errno));
406 struct control_req *req = Control_req_new(new_fd);
411static void handle_wait_timeout(
void *data)
414 assert(bw_waiting_req);
416 struct control_req *req = bw_waiting_req;
418 req->stage = REQ_SWITCH_WRITE;
423 Control_req_read_cb(req->fd, req);
428 return bw_waiting != NULL;
433 if (bw_waiting == NULL || bw_waiting != bw)
436 _MSG(
"a_Control_notify_finish matched\n");
438 assert(bw_waiting_req);
440 struct control_req *req = bw_waiting_req;
442 req->stage = REQ_SWITCH_WRITE;
446 bw_waiting_req = NULL;
449 Control_req_read_cb(req->fd, req);
455 if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
456 MSG(
"cannot create control socket: %s\n", strerror(errno));
460 struct sockaddr_un addr;
461 addr.sun_family = AF_UNIX;
463#define LEN ((int) sizeof(addr.sun_path))
467 MSG(
"control socket dir path too long: %s/.dillo/ctl\n",
dGethomedir());
473 if (mkdir(ctldir, 0700) != 0) {
474 if (errno != EEXIST) {
475 MSG(
"cannot create ctl dir: %s\n", strerror(errno));
480 if (snprintf(addr.sun_path,
LEN,
"%s/%d", ctldir, (
int) getpid()) >=
LEN) {
481 MSG(
"control socket path too long: %s/%d\n", ctldir, (
int) getpid());
485 int slen =
sizeof(addr);
487 if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1) {
488 MSG(
"control socket fcntl failed: %s\n", strerror(errno));
493 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (
char *)&on,
sizeof(on)) < 0) {
494 MSG(
"control socket setsockopt failed: %s\n", strerror(errno));
498 if (ioctl(fd, FIONBIO, (
char *)&on) != 0) {
499 MSG(
"control socket ioctl failed: %s\n", strerror(errno));
503 if (bind(fd, (
struct sockaddr *) &addr, slen) != 0) {
504 MSG(
"cannot bind control socket: %s\n", strerror(errno));
508 if (listen(fd, 32) != 0) {
509 MSG(
"cannot listen control socket: %s\n", strerror(errno));
514 control_path =
dStrdup(addr.sun_path);
524 if (control_fd == -1)
527 assert(control_path);
530 if (
dClose(control_fd) != 0) {
531 MSG_ERR(
"close ctl socket failed\n");
534 if (unlink(control_path) != 0) {
535 MSG_ERR(
"unlink ctl socket failed\n");
Dstr * a_Cache_get_header(const DilloUrl *Url)
void a_Cache_entry_inject(const DilloUrl *Url, const char *buf, size_t len, int flags)
Inject full page content directly into the cache.
int a_Capi_get_buf(const DilloUrl *Url, char **PBuf, int *BufSize)
Get the cache's buffer for the URL, and its size.
void a_Control_notify_finish(BrowserWindow *bw)
int a_Control_is_waiting(void)
void * dMalloc0(size_t size)
void dStr_sprintfa(Dstr *ds, const char *format,...)
Printf-like function that appends.
char * dStrdup(const char *s)
Dstr * dStr_sized_new(int sz)
Create a new string with a given size.
void dStr_free(Dstr *ds, int all)
Free a dillo string.
int dClose(int fd)
Close a FD handling EINTR.
void dStr_append_l(Dstr *ds, const char *s, int l)
Append a C string to a Dstr (providing length).
char * dGethomedir(void)
Return the home directory in a static string (don't free)
void a_IOwatch_add_fd(int fd, int when, Fl_FD_Handler Callback, void *usr_data=0)
Hook a Callback for a certain activities in a FD.
void a_IOwatch_remove_fd(int fd, int when)
Remove a Callback for a given FD (or just remove some events)
Contains the specific data for a single window.
void a_Timeout_add(float t, TimeoutCb_t cb, void *cbdata)
Hook a one-time timeout function 'cb' after 't' seconds with 'cbdata" as its data.
void a_Timeout_actually_remove(TimeoutCb_t cb, void *data)
void a_UIcmd_set_msg(BrowserWindow *bw, const char *format,...)
const char * a_UIcmd_get_page_title(BrowserWindow *bw)
void a_UIcmd_reload_all_active()
BrowserWindow * a_UIcmd_get_first_active_bw(void)
int a_UIcmd_by_name(void *vbw, const char *cmd_name)
void a_UIcmd_close_all_bw(void *force)
void a_UIcmd_open_urlstr(void *vbw, const char *urlstr)
int a_UIcmd_has_finished(BrowserWindow *bw)
void a_UIcmd_repush(void *vbw)
char * a_UIcmd_get_location_text(BrowserWindow *bw)
void a_Url_free(DilloUrl *url)
Free a DilloUrl.
DilloUrl * a_Url_new(const char *url_str, const char *base_url)
Transform (and resolve) an URL string into the respective DilloURL.