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,
" status [MSG] Set the status bar to MSG\n");
221 dStr_sprintfa(r,
" dump Print the content of the current tab\n");
222 dStr_sprintfa(r,
" hdump Print the HTTP headers of the current tab\n");
223 dStr_sprintfa(r,
" load Replace the content in the current tab by stdin\n");
224 dStr_sprintfa(r,
" rawload Replace the HTTP headers and content of the current\n");
227 dStr_sprintfa(r,
" wait [T] Wait until the current tab has finished loading\n");
228 dStr_sprintfa(r,
" at most T seconds (default 60.0). Wait forever with\n");
230 }
else if (strcmp(cmd,
"ping") == 0) {
232 }
else if (strcmp(cmd,
"pid") == 0) {
234 }
else if (strcmp(cmd,
"reload") == 0) {
237 }
else if (strcmp(cmd,
"ready") == 0) {
239 }
else if (strncmp(cmd,
"open ", 5) == 0) {
242 }
else if (strcmp(cmd,
"url") == 0) {
244 }
else if (!strcmp(cmd,
"status") || !strncmp(cmd,
"status ", 7)) {
250 }
else if (strcmp(cmd,
"dump") == 0) {
258 }
else if (strcmp(cmd,
"hdump") == 0) {
261 if (header == NULL) {
268 }
else if (strcmp(cmd,
"load") == 0) {
279 }
else if (strcmp(cmd,
"rawload") == 0) {
289 }
else if (strcmp(cmd,
"quit") == 0) {
292 }
else if (strncmp(cmd,
"cmd ", 4) == 0) {
293 const char *cmdname = cmd + 4;
296 }
else if (strcmp(cmd,
"wait") == 0 || strncmp(cmd,
"wait ", 5) == 0) {
297 float timeout = 60.0f;
300 timeout = atof(&cmd[5]);
308 bw_waiting_req = req;
320 req->stage = REQ_SWITCH_WRITE;
324static void Control_req_read_cb(
int fd,
void *data)
326 struct control_req *req = data;
330 if (req->stage == REQ_READ_COMMAND)
331 Control_req_read_cmd(req);
333 if (req->stage == REQ_READ_BODY) {
335 int ret = Control_read_fd(fd, req->body);
337 req->stage = REQ_PREPARE_REPLY;
339 req->stage = REQ_CLOSE;
342 if (req->stage == REQ_PREPARE_REPLY)
343 Control_req_prepare_reply(req);
345 if (req->stage == REQ_SWITCH_WRITE) {
349 req->stage = REQ_WRITE_REPLY;
352 if (req->stage == REQ_WRITE_REPLY) {
354 if (Control_write_fd(fd, req->reply, &req->reply_offset) <= 0)
355 req->stage = REQ_CLOSE;
358 if (req->stage == REQ_CLOSE) {
362 Control_req_free(req);
367static void Control_listen_cb(
int fd,
void *data)
369 _MSG(
"Control_listen_cb called\n");
371 int new_fd = accept(control_fd, NULL, NULL);
373 if (errno == EAGAIN || errno == EWOULDBLOCK) {
377 MSG_ERR(
"accept failed: %s\n", strerror(errno));
394 if (fcntl(new_fd, F_SETFL, O_NONBLOCK) == -1) {
395 MSG_ERR(
"control socket fcntl failed: %s\n", strerror(errno));
399 struct control_req *req = Control_req_new(new_fd);
404static void handle_wait_timeout(
void *data)
407 assert(bw_waiting_req);
409 struct control_req *req = bw_waiting_req;
411 req->stage = REQ_SWITCH_WRITE;
416 Control_req_read_cb(req->fd, req);
421 return bw_waiting != NULL;
426 if (bw_waiting == NULL || bw_waiting != bw)
429 _MSG(
"a_Control_notify_finish matched\n");
431 assert(bw_waiting_req);
433 struct control_req *req = bw_waiting_req;
435 req->stage = REQ_SWITCH_WRITE;
439 bw_waiting_req = NULL;
442 Control_req_read_cb(req->fd, req);
448 if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
449 MSG(
"cannot create control socket: %s\n", strerror(errno));
453 struct sockaddr_un addr;
454 addr.sun_family = AF_UNIX;
456#define LEN ((int) sizeof(addr.sun_path))
460 MSG(
"control socket dir path too long: %s/.dillo/ctl\n",
dGethomedir());
466 if (mkdir(ctldir, 0700) != 0) {
467 if (errno != EEXIST) {
468 MSG(
"cannot create ctl dir: %s\n", strerror(errno));
473 if (snprintf(addr.sun_path,
LEN,
"%s/%d", ctldir, (
int) getpid()) >=
LEN) {
474 MSG(
"control socket path too long: %s/%d\n", ctldir, (
int) getpid());
478 int slen =
sizeof(addr);
480 if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1) {
481 MSG(
"control socket fcntl failed: %s\n", strerror(errno));
486 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (
char *)&on,
sizeof(on)) < 0) {
487 MSG(
"control socket setsockopt failed: %s\n", strerror(errno));
491 if (ioctl(fd, FIONBIO, (
char *)&on) != 0) {
492 MSG(
"control socket ioctl failed: %s\n", strerror(errno));
496 if (bind(fd, (
struct sockaddr *) &addr, slen) != 0) {
497 MSG(
"cannot bind control socket: %s\n", strerror(errno));
501 if (listen(fd, 32) != 0) {
502 MSG(
"cannot listen control socket: %s\n", strerror(errno));
507 control_path =
dStrdup(addr.sun_path);
517 if (control_fd == -1)
520 assert(control_path);
523 if (
dClose(control_fd) != 0) {
524 MSG_ERR(
"close ctl socket failed\n");
527 if (unlink(control_path) != 0) {
528 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,...)
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.