Dillo v3.1.1-99-gf3103cc4
Loading...
Searching...
No Matches
dpip.c
Go to the documentation of this file.
1/*
2 * File: dpip.c
3 *
4 * Copyright 2005-2015 Jorge Arellano Cid <jcid@dillo.org>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 */
12
13#include <errno.h>
14#include <stdio.h>
15#include <stdlib.h>
16#include <stdarg.h>
17#include <string.h>
18#include <ctype.h>
19#include <unistd.h> /* for close */
20#include <fcntl.h> /* for fcntl */
21
22#include "dpip.h"
23#include "d_size.h"
24
25#define RBUF_SZ 16*1024
26//#define RBUF_SZ 1
27
28#define DPIP_TAG_END " '>"
29#define DPIP_MODE_SWITCH_TAG "cmd='start_send_page' "
30#define MSG_ERR(...) fprintf(stderr, "[dpip]: " __VA_ARGS__)
31
32/*
33 * Local variables
34 */
35static const char Quote = '\'';
36
74
75/* ------------------------------------------------------------------------- */
76
83char *a_Dpip_build_cmd(const char *format, ...)
84{
85 va_list argp;
86 char *p, *q, *s;
87 Dstr *cmd;
88
89 /* Don't allow Quote characters in attribute names */
90 if (strchr(format, Quote))
91 return NULL;
92
93 cmd = dStr_sized_new(64);
94 dStr_append_c(cmd, '<');
95 va_start(argp, format);
96 for (p = q = (char*)format; *q; ) {
97 p = strstr(q, "%s");
98 if (!p) {
99 dStr_append(cmd, q);
100 break;
101 } else {
102 /* Copy format's part */
103 while (q != p)
104 dStr_append_c(cmd, *q++);
105 q += 2;
106
107 dStr_append_c(cmd, Quote);
108 /* Stuff-copy of argument */
109 s = va_arg (argp, char *);
110 for ( ; *s; ++s) {
111 dStr_append_c(cmd, *s);
112 if (*s == Quote)
113 dStr_append_c(cmd, *s);
114 }
115 dStr_append_c(cmd, Quote);
116 }
117 }
118 va_end(argp);
119 dStr_append_c(cmd, ' ');
120 dStr_append_c(cmd, Quote);
121 dStr_append_c(cmd, '>');
122
123 p = cmd->str;
124 dStr_free(cmd, FALSE);
125 return p;
126}
127
134char *a_Dpip_get_attr_l(const char *tag, size_t tagsize, const char *attrname)
135{
136 uint_t i, n = 0, found = 0;
137 const char *p, *q, *start;
138 char *r, *s, *val = NULL;
140
141 if (!tag || !tagsize || !attrname || !*attrname)
142 return NULL;
143
144 for (i = 1; i < tagsize && !found; ++i) {
145 switch (state) {
146 case SEEK_NAME:
147 if (tag[i] == attrname[0] && (tag[i-1] == ' ' || tag[i-1] == '<')) {
148 n = 1;
149 state = MATCH_NAME;
150 } else if (tag[i] == Quote && tag[i-1] == '=')
151 state = SKIP_VALUE;
152 break;
153 case MATCH_NAME:
154 if (tag[i] == attrname[n])
155 ++n;
156 else if (tag[i] == '=' && !attrname[n])
157 state = FOUND;
158 else
159 state = SEEK_NAME;
160 break;
161 case SKIP_VALUE:
162 if (tag[i] == Quote)
163 state = (tag[i+1] == Quote) ? SKIP_QUOTE : SEEK_NAME;
164 break;
165 case SKIP_QUOTE:
166 state = SKIP_VALUE;
167 break;
168 case FOUND:
169 found = 1;
170 break;
171 }
172 }
173
174 if (found) {
175 p = start = tag + i;
176 while ((q = strchr(p, Quote)) && q[1] == Quote)
177 p = q + 2;
178 if (q && q[1] == ' ') {
179 val = dStrndup(start, (uint_t)(q - start));
180 for (r = s = val; (*r = *s); ++r, ++s)
181 if (s[0] == Quote && s[0] == s[1])
182 ++s;
183 }
184 }
185 return val;
186}
187
192char *a_Dpip_get_attr(const char *tag, const char *attrname)
193{
194 return (tag ? a_Dpip_get_attr_l(tag, strlen(tag), attrname) : NULL);
195}
196
201int a_Dpip_check_auth(const char *auth_tag)
202{
203 char SharedSecret[32];
204 FILE *In;
205 char *fname, *rcline = NULL, *tail, *cmd, *msg;
206 int i, port, ret = -1;
207
208 /* sanity checks */
209 if (!auth_tag ||
210 !(cmd = a_Dpip_get_attr(auth_tag, "cmd")) || strcmp(cmd, "auth") ||
211 !(msg = a_Dpip_get_attr(auth_tag, "msg"))) {
212 return ret;
213 }
214
215 fname = dStrconcat(dGethomedir(), "/.dillo/dpid_comm_keys", NULL);
216 if ((In = fopen(fname, "r")) == NULL) {
217 MSG_ERR("[a_Dpip_check_auth] %s\n", dStrerror(errno));
218 } else if ((rcline = dGetline(In)) == NULL) {
219 MSG_ERR("[a_Dpip_check_auth] empty file: %s\n", fname);
220 } else {
221 port = strtol(rcline, &tail, 10);
222 if (tail && port != 0) {
223 for (i = 0; *tail && isxdigit(tail[i+1]); ++i)
224 SharedSecret[i] = tail[i+1];
225 SharedSecret[i] = 0;
226 if (strcmp(msg, SharedSecret) == 0)
227 ret = 1;
228 }
229 }
230 if (In)
231 fclose(In);
232 dFree(rcline);
233 dFree(fname);
234 dFree(msg);
235 dFree(cmd);
236
237 return ret;
238}
239
240/* --------------------------------------------------------------------------
241 * Dpip socket API ----------------------------------------------------------
242 */
243
247Dsh *a_Dpip_dsh_new(int fd_in, int fd_out, int flush_sz)
248{
249 Dsh *dsh = dNew(Dsh, 1);
250
251 /* init descriptors and streams */
252 dsh->fd_in = fd_in;
253 dsh->fd_out = fd_out;
254
255 /* init buffer */
256 dsh->wrbuf = dStr_sized_new(8 *1024);
257 dsh->rdbuf = dStr_sized_new(8 *1024);
258 dsh->flush_sz = flush_sz;
259 dsh->mode = DPIP_TAG;
260 if (fcntl(dsh->fd_in, F_GETFL) & O_NONBLOCK)
261 dsh->mode |= DPIP_NONBLOCK;
262 dsh->status = 0;
263
264 return dsh;
265}
266
267/*
268 * Return value: 1..DataSize sent, -1 eagain, or -3 on big Error
269 */
270static int Dpip_dsh_write(Dsh *dsh, int nb, const char *Data, int DataSize)
271{
272 int req_mode, old_flags = 0, st, ret = -3, sent = 0;
273
274 req_mode = (nb) ? DPIP_NONBLOCK : 0;
275 if ((dsh->mode & DPIP_NONBLOCK) != req_mode) {
276 /* change mode temporarily... */
277 old_flags = fcntl(dsh->fd_out, F_GETFL);
278 fcntl(dsh->fd_out, F_SETFL,
279 (nb) ? O_NONBLOCK | old_flags : old_flags & ~O_NONBLOCK);
280 }
281
282 while (1) {
283 st = write(dsh->fd_out, Data + sent, DataSize - sent);
284 if (st < 0) {
285 if (errno == EINTR) {
286 continue;
287 } else if (errno == EAGAIN) {
288 dsh->status = DPIP_EAGAIN;
289 ret = -1;
290 break;
291 } else {
292 MSG_ERR("[Dpip_dsh_write] %s\n", dStrerror(errno));
293 dsh->status = DPIP_ERROR;
294 break;
295 }
296 } else {
297 sent += st;
298 if (nb || sent == DataSize) {
299 ret = sent;
300 break;
301 }
302 }
303 }
304
305 if ((dsh->mode & DPIP_NONBLOCK) != req_mode) {
306 /* restore old mode */
307 fcntl(dsh->fd_out, F_SETFL, old_flags);
308 }
309
310 return ret;
311}
312
317int a_Dpip_dsh_write(Dsh *dsh, int flush, const char *Data, int DataSize)
318{
319 int ret = 1;
320
321 /* append to buf */
322 dStr_append_l(dsh->wrbuf, Data, DataSize);
323
324 if (!flush || dsh->wrbuf->len == 0)
325 return 0;
326
327 ret = Dpip_dsh_write(dsh, 0, dsh->wrbuf->str, dsh->wrbuf->len);
328 if (ret == dsh->wrbuf->len) {
329 dStr_truncate(dsh->wrbuf, 0);
330 ret = 0;
331 }
332
333 return ret;
334}
335
336/*
337 * Return value: 0 on success or empty buffer,
338 * 1..DataSize sent, -1 eagain, or -3 on big Error
339 */
341{
342 int st;
343
344 if (dsh->wrbuf->len == 0) {
345 st = 0;
346 } else {
347 st = Dpip_dsh_write(dsh, 1, dsh->wrbuf->str, dsh->wrbuf->len);
348 if (st > 0) {
349 /* update internal buffer */
350 dStr_erase(dsh->wrbuf, 0, st);
351 }
352 }
353 return (dsh->wrbuf->len == 0) ? 0 : st;
354}
355
356/*
357 * Return value: 1..DataSize sent, -1 eagain, or -3 on big Error
358 */
359int a_Dpip_dsh_trywrite(Dsh *dsh, const char *Data, int DataSize)
360{
361 int st;
362
363 if ((st = Dpip_dsh_write(dsh, 1, Data, DataSize)) > 0) {
364 /* update internal buffer */
365 if (st < DataSize)
366 dStr_append_l(dsh->wrbuf, Data + st, DataSize - st);
367 }
368 return st;
369}
370
374int a_Dpip_dsh_write_str(Dsh *dsh, int flush, const char *str)
375{
376 return a_Dpip_dsh_write(dsh, flush, str, (int)strlen(str));
377}
378
383static void Dpip_dsh_read(Dsh *dsh, int blocking)
384{
385 char buf[RBUF_SZ];
386 int req_mode, old_flags = 0, st, nb = !blocking;
387
388 dReturn_if (dsh->status == DPIP_ERROR || dsh->status == DPIP_EOF);
389
390 req_mode = (nb) ? DPIP_NONBLOCK : 0;
391 if ((dsh->mode & DPIP_NONBLOCK) != req_mode) {
392 /* change mode temporarily... */
393 old_flags = fcntl(dsh->fd_in, F_GETFL);
394 fcntl(dsh->fd_in, F_SETFL,
395 (nb) ? O_NONBLOCK | old_flags : old_flags & ~O_NONBLOCK);
396 }
397
398 while (1) {
399 st = read(dsh->fd_in, buf, RBUF_SZ);
400 if (st < 0) {
401 if (errno == EINTR) {
402 continue;
403 } else if (errno == EAGAIN) {
404 dsh->status = DPIP_EAGAIN;
405 break;
406 } else {
407 MSG_ERR("[Dpip_dsh_read] %s\n", dStrerror(errno));
408 dsh->status = DPIP_ERROR;
409 break;
410 }
411 } else if (st == 0) {
412 dsh->status = DPIP_EOF;
413 break;
414 } else {
415 /* append to buf */
416 dStr_append_l(dsh->rdbuf, buf, st);
417 if (blocking)
418 break;
419 }
420 }
421
422 if ((dsh->mode & DPIP_NONBLOCK) != req_mode) {
423 /* restore old mode */
424 fcntl(dsh->fd_out, F_SETFL, old_flags);
425 }
426
427 /* assert there's no more data in the wire...
428 * (st < buf upon interrupt || st == buf and no more data) */
429 if (blocking)
430 Dpip_dsh_read(dsh, 0);
431}
432
438char *a_Dpip_dsh_read_token2(Dsh *dsh, int blocking, int *DataSize)
439{
440 char *p, *ret = NULL;
441 *DataSize = 0;
442
443 /* Read all available data without blocking */
444 Dpip_dsh_read(dsh, 0);
445
446 /* switch mode upon request */
447 if (dsh->mode & DPIP_LAST_TAG)
448 dsh->mode = DPIP_RAW;
449
450 if (blocking) {
451 if (dsh->mode & DPIP_TAG) {
452 /* Only wait for data when the tag is incomplete */
453 if (!strstr(dsh->rdbuf->str, DPIP_TAG_END)) {
454 do {
455 Dpip_dsh_read(dsh, 1);
456 p = strstr(dsh->rdbuf->str, DPIP_TAG_END);
457 } while (!p && dsh->status == EAGAIN);
458 }
459
460 } else if (dsh->mode & DPIP_RAW) {
461 /* Wait for data when the buffer is empty and there's no ERR/EOF */
462 while (dsh->rdbuf->len == 0 &&
463 dsh->status != DPIP_ERROR && dsh->status != DPIP_EOF)
464 Dpip_dsh_read(dsh, 1);
465 }
466 }
467
468 if (dsh->mode & DPIP_TAG) {
469 /* return a full tag */
470 if ((p = strstr(dsh->rdbuf->str, DPIP_TAG_END))) {
471 ret = dStrndup(dsh->rdbuf->str, p - dsh->rdbuf->str + 3);
472 *DataSize = p - dsh->rdbuf->str + 3;
473 dStr_erase(dsh->rdbuf, 0, p - dsh->rdbuf->str + 3);
474 if (strstr(ret, DPIP_MODE_SWITCH_TAG))
475 dsh->mode |= DPIP_LAST_TAG;
476 }
477 } else {
478 /* raw mode, return what we have "as is" */
479 if (dsh->rdbuf->len > 0) {
480 ret = dStrndup(dsh->rdbuf->str, dsh->rdbuf->len);
481 *DataSize = dsh->rdbuf->len;
482 dStr_truncate(dsh->rdbuf, 0);
483 }
484 }
485
486 return ret;
487}
488
493char *a_Dpip_dsh_read_token(Dsh *dsh, int blocking)
494{
495 int token_size;
496
497 return a_Dpip_dsh_read_token2(dsh, blocking, &token_size);
498}
499
505{
506 int st;
507
508 /* flush internal buffer */
509 a_Dpip_dsh_write(dsh, 1, "", 0);
510
511 /* close fds */
512 st = dClose(dsh->fd_in);
513 if (st < 0)
514 MSG_ERR("[a_Dpip_dsh_close] close: %s\n", dStrerror(errno));
515 if (dsh->fd_out != dsh->fd_in) {
516 st = dClose(dsh->fd_out);
517 if (st < 0)
518 MSG_ERR("[a_Dpip_dsh_close] close: %s\n", dStrerror(errno));
519 }
520}
521
526{
527 dReturn_if (dsh == NULL);
528
529 dStr_free(dsh->wrbuf, 1);
530 dStr_free(dsh->rdbuf, 1);
531 dFree(dsh);
532}
533
unsigned int uint_t
Definition d_size.h:20
char * dGetline(FILE *stream)
Get a line from a FILE stream.
Definition dlib.c:928
char * dStrconcat(const char *s1,...)
Concatenate a NULL-terminated list of strings.
Definition dlib.c:102
void dFree(void *mem)
Definition dlib.c:68
void dStr_append(Dstr *ds, const char *s)
Append a C string to a Dstr.
Definition dlib.c:316
Dstr * dStr_sized_new(int sz)
Create a new string with a given size.
Definition dlib.c:254
void dStr_erase(Dstr *ds, int pos_0, int len)
Erase a substring.
Definition dlib.c:388
void dStr_free(Dstr *ds, int all)
Free a dillo string.
Definition dlib.c:337
int dClose(int fd)
Close a FD handling EINTR.
Definition dlib.c:951
void dStr_append_l(Dstr *ds, const char *s, int l)
Append a C string to a Dstr (providing length).
Definition dlib.c:308
void dStr_append_c(Dstr *ds, int c)
Append one character.
Definition dlib.c:349
char * dStrndup(const char *s, size_t sz)
Definition dlib.c:88
void dStr_truncate(Dstr *ds, int len)
Truncate a Dstr to be 'len' bytes long.
Definition dlib.c:368
char * dGethomedir(void)
Return the home directory in a static string (don't free)
Definition dlib.c:906
#define dStrerror
Definition dlib.h:95
#define dReturn_if(expr)
Definition dlib.h:64
#define FALSE
Definition dlib.h:19
#define dNew(type, count)
Definition dlib.h:49
int a_Dpip_dsh_trywrite(Dsh *dsh, const char *Data, int DataSize)
Definition dpip.c:359
#define MSG_ERR(...)
Definition dpip.c:30
#define DPIP_TAG_END
Definition dpip.c:28
char * a_Dpip_dsh_read_token2(Dsh *dsh, int blocking, int *DataSize)
Return a newlly allocated string with the next dpip token in the socket.
Definition dpip.c:438
void a_Dpip_dsh_free(Dsh *dsh)
Free the SockHandler structure.
Definition dpip.c:525
char * a_Dpip_build_cmd(const char *format,...)
Printf like function for building dpip commands.
Definition dpip.c:83
int a_Dpip_dsh_write_str(Dsh *dsh, int flush, const char *str)
Convenience function.
Definition dpip.c:374
DpipTagParsingState
Definition dpip.c:67
@ FOUND
Definition dpip.c:72
@ SKIP_VALUE
Definition dpip.c:70
@ SEEK_NAME
Definition dpip.c:68
@ MATCH_NAME
Definition dpip.c:69
@ SKIP_QUOTE
Definition dpip.c:71
static const char Quote
Definition dpip.c:35
static int Dpip_dsh_write(Dsh *dsh, int nb, const char *Data, int DataSize)
Definition dpip.c:270
char * a_Dpip_get_attr(const char *tag, const char *attrname)
Task: given a tag and an attribute name, return its value.
Definition dpip.c:192
char * a_Dpip_dsh_read_token(Dsh *dsh, int blocking)
Return a newlly allocated string with the next dpip token in the socket.
Definition dpip.c:493
void a_Dpip_dsh_close(Dsh *dsh)
Close this socket for reading and writing.
Definition dpip.c:504
static void Dpip_dsh_read(Dsh *dsh, int blocking)
Read raw data from the socket into our buffer in either BLOCKING or NONBLOCKING mode.
Definition dpip.c:383
char * a_Dpip_get_attr_l(const char *tag, size_t tagsize, const char *attrname)
Task: given a tag, its size and an attribute name, return the attribute value (stuffing of ' is remov...
Definition dpip.c:134
int a_Dpip_check_auth(const char *auth_tag)
Check whether the given 'auth' string equals what dpid saved.
Definition dpip.c:201
int a_Dpip_dsh_write(Dsh *dsh, int flush, const char *Data, int DataSize)
Streamed write to socket.
Definition dpip.c:317
#define DPIP_MODE_SWITCH_TAG
Definition dpip.c:29
int a_Dpip_dsh_tryflush(Dsh *dsh)
Definition dpip.c:340
Dsh * a_Dpip_dsh_new(int fd_in, int fd_out, int flush_sz)
Create and initialize a dpip socket handler.
Definition dpip.c:247
#define RBUF_SZ
Definition dpip.c:25
#define DPIP_RAW
Raw data in the socket
Definition dpip.h:19
@ DPIP_ERROR
Definition dpip.h:24
@ DPIP_EOF
Definition dpip.h:25
@ DPIP_EAGAIN
Definition dpip.h:23
#define DPIP_TAG
Dpip tags in the socket.
Definition dpip.h:17
#define DPIP_LAST_TAG
Dpip mode-switching tag.
Definition dpip.h:18
#define DPIP_NONBLOCK
Nonblocking IO
Definition dpip.h:20
Dpip socket handler type.
Definition dpip.h:31
Dstr * rdbuf
read buffer
Definition dpip.h:38
int mode
mode flags: DPIP_TAG | DPIP_LAST_TAG | DPIP_RAW
Definition dpip.h:41
int status
status code: DPIP_EAGAIN | DPIP_ERROR | DPIP_EOF
Definition dpip.h:42
Dstr * wrbuf
write buffer
Definition dpip.h:37
int fd_in
Definition dpip.h:32
int fd_out
Definition dpip.h:33
int flush_sz
max size before flush
Definition dpip.h:39
Definition dlib.h:102
Dstr_char_t * str
Definition dlib.h:105
int len
Definition dlib.h:104