aboutsummaryrefslogtreecommitdiff
path: root/dpip/dpip.c
diff options
context:
space:
mode:
Diffstat (limited to 'dpip/dpip.c')
-rw-r--r--dpip/dpip.c184
1 files changed, 180 insertions, 4 deletions
diff --git a/dpip/dpip.c b/dpip/dpip.c
index f07070a5..fb5e0a3d 100644
--- a/dpip/dpip.c
+++ b/dpip/dpip.c
@@ -16,18 +16,21 @@
#include <stdarg.h>
#include <string.h>
#include <ctype.h>
+#include <unistd.h> /* for close */
+#include <fcntl.h> /* for fcntl */
-#include "../dlib/dlib.h"
#include "dpip.h"
#include "d_size.h"
-#define MSG_ERR(...) fprintf(stderr, "[dpip]: " __VA_ARGS__)
+#define DPIP_TAG_END " '>"
+#define DPIP_MODE_SWITCH_TAG "cmd='start_send_page' "
+#define MSG_ERR(...) fprintf(stderr, "[dpip]: " __VA_ARGS__)
/*
* Local variables
*/
static const char Quote = '\'';
-
+static const int DpipTag = 1;
/*
* Basically the syntax of a dpip tag is:
@@ -215,5 +218,178 @@ int a_Dpip_check_auth(const char *auth)
return ret;
}
-/* ------------------------------------------------------------------------- */
+/* --------------------------------------------------------------------------
+ * Dpip socket API ----------------------------------------------------------
+ */
+
+/*
+ * Create and initialize a dpip socket handler
+ */
+Dsh *a_Dpip_dsh_new(int fd_in, int fd_out, int flush_sz)
+{
+ Dsh *dsh = dNew(Dsh, 1);
+
+ /* init descriptors and streams */
+ dsh->fd_in = fd_in;
+ dsh->fd_out = fd_out;
+ dsh->out = fdopen(fd_out, "w");
+
+ /* init buffer */
+ dsh->dbuf = dStr_sized_new(8 *1024);
+ dsh->rd_dbuf = dStr_sized_new(8 *1024);
+ dsh->flush_sz = flush_sz;
+ dsh->mode = DPIP_TAG;
+ if (fcntl(dsh->fd_in, F_GETFL) & O_NONBLOCK)
+ dsh->mode |= DPIP_NONBLOCK;
+ dsh->status = 0;
+
+ return dsh;
+}
+
+/*
+ * Streamed write to socket
+ * Return: 0 on success, 1 on error.
+ */
+int a_Dpip_dsh_write(Dsh *dsh, int flush, const char *Data, int DataSize)
+{
+ int ret = 1;
+
+ /* append to buf */
+ dStr_append_l(dsh->dbuf, Data, DataSize);
+
+ /* flush data if necessary */
+ if (flush || dsh->dbuf->len >= dsh->flush_sz) {
+ if (dsh->dbuf->len &&
+ fwrite (dsh->dbuf->str, dsh->dbuf->len, 1, dsh->out) != 1) {
+ MSG_ERR("[a_Dpip_dsh_write] %s\n", dStrerror(errno));
+ } else {
+ fflush(dsh->out);
+ dStr_truncate(dsh->dbuf, 0);
+ ret = 0;
+ }
+
+ } else {
+ ret = 0;
+ }
+
+ return ret;
+}
+
+/*
+ * Convenience function.
+ */
+int a_Dpip_dsh_write_str(Dsh *dsh, int flush, const char *str)
+{
+ return a_Dpip_dsh_write(dsh, flush, str, (int)strlen(str));
+}
+
+/*
+ * Read new data from the socket into our buffer.
+ * Used by both blocking and non-blocking IO.
+ */
+static void Dpip_dsh_read(Dsh *dsh)
+{
+//#define LBUF_SZ 16384
+#define LBUF_SZ 1
+
+ ssize_t st;
+ int old_flags, blocking;
+ char buf[LBUF_SZ];
+
+ blocking = !(dsh->mode & DPIP_NONBLOCK);
+ if (blocking) {
+ old_flags = fcntl(dsh->fd_in, F_GETFL);
+ }
+
+ while (1) {
+ /* can't use fread() */
+ do
+ st = read(dsh->fd_in, buf, LBUF_SZ);
+ while (st < 0 && errno == EINTR);
+
+ if (st < 0) {
+ if (errno == EAGAIN) {
+ /* no problem, return what we've got so far... */
+ dsh->status = DPIP_EAGAIN;
+ } else {
+ MSG_ERR("[Dpip_dsh_read] %s\n", dStrerror(errno));
+ dsh->status = DPIP_ERROR;
+ }
+ break;
+ } else if (st == 0) {
+ dsh->status = DPIP_EOF;
+ break;
+ } else {
+ /* append to buf */
+ dStr_append_l(dsh->rd_dbuf, buf, st);
+ if (blocking) {
+ /* set NONBLOCKING temporarily... */
+ fcntl(dsh->fd_in, F_SETFL, O_NONBLOCK | old_flags);
+ }
+ }
+ }
+
+ if (blocking) {
+ /* restore blocking mode */
+ fcntl(dsh->fd_in, F_SETFL, old_flags);
+ }
+}
+
+/*
+ * Return a newlly allocated string with the next dpip token in the socket.
+ * Return value: token string on success, NULL otherwise
+ */
+char *a_Dpip_dsh_read_token(Dsh *dsh)
+{
+ char *p, *ret = NULL;
+
+ /* switch mode upon request */
+ if (dsh->mode & DPIP_LAST_TAG)
+ dsh->mode = DPIP_RAW;
+
+ /* Only read from socket when there's no data in buffer or
+ * the tag is incomplete */
+ if (dsh->rd_dbuf->len == 0 ||
+ (dsh->mode & DPIP_TAG &&
+ !(p = strstr(dsh->rd_dbuf->str, DPIP_TAG_END)))) {
+ Dpip_dsh_read(dsh);
+ }
+
+ if (dsh->mode & DPIP_TAG) {
+ /* return a full tag */
+ if ((p = strstr(dsh->rd_dbuf->str, DPIP_TAG_END))) {
+ ret = dStrndup(dsh->rd_dbuf->str, p - dsh->rd_dbuf->str + 3);
+ dStr_erase(dsh->rd_dbuf, 0, p - dsh->rd_dbuf->str + 3);
+ if (strstr(ret, DPIP_MODE_SWITCH_TAG))
+ dsh->mode |= DPIP_LAST_TAG;
+ }
+ } else {
+ /* raw mode, return what we have "as is" */
+ if (dsh->rd_dbuf->len > 0) {
+ ret = dStrndup(dsh->rd_dbuf->str, dsh->rd_dbuf->len);
+ dStr_truncate(dsh->rd_dbuf, 0);
+ }
+ }
+
+ return ret;
+}
+
+/*
+ * Close this socket for reading and writing.
+ */
+void a_Dpip_dsh_close(Dsh *dsh)
+{
+ fclose(dsh->out);
+ close(dsh->fd_out);
+}
+
+/*
+ * Free the SockHandler structure
+ */
+void a_Dpip_dsh_free(Dsh *dsh)
+{
+ dStr_free(dsh->dbuf, 1);
+ dStr_free(dsh->rd_dbuf, 1);
+ dFree(dsh);
+}