void dbuf_put(struct dbuf_queue *qptr, char *data, size_t count) { struct dbuf_block *last; size_t amount; assert(count > 0); if (qptr->blocks.tail == NULL) dbuf_alloc(qptr); do { last = qptr->blocks.tail->data; amount = DBUF_BLOCK_SIZE - last->size; if (!amount) { last = dbuf_alloc(qptr); amount = DBUF_BLOCK_SIZE; } if (amount > count) amount = count; memcpy((void *) &last->data[last->size], data, amount); count -= amount; last->size += amount; qptr->total_size += amount; data += amount; } while (count > 0); }
/* * format up an HTTP response and return it */ DBUF *server_respond (int code, char *fmt, ...) { int l, len, avail; va_list ap; char *ch; DBUF *b; char buf[4096]; /* * note our response body is limited to 4096 bytes - only small * response is needed or allowed. */ len = sprintf (buf, "<html><body>"); avail = 4096 - (len * 2 + 4); va_start (ap, fmt); l = vsnprintf (buf + len, avail, fmt, ap); va_end (ap); if ((l > 0) && (l < avail)) len += l; len += sprintf (buf + len, "</body></html>"); /* * if we are no longer running, notify the client that we are * closing this connection. */ b = dbuf_alloc (); dbuf_printf (b, "Status: %d\r\n" "Content-Length: %d\r\n" "Connection: %s\r\n\r\n%s", code, len, phineas_running () ? "Keep-alive" : "Close", buf); debug ("response:\n%s\n", dbuf_getbuf (b)); return (b); }
/* * Format a MIME message to an allocated character buffer. Caller * is responsible for freeing this buffer. */ char *mime_format (MIME *m) { DBUF *b; b = dbuf_alloc (); mime_format_part (m, b); return (dbuf_extract (b)); }
/* * Allocate and return an authorization required response */ DBUF *basicauth_response (char *realm) { DBUF *b = dbuf_alloc (); char *html = "<html><body>Access restricted - " "Authorization required!</body></html>"; dbuf_printf (b, "Status: 401\r\n" "WWW-Authenticate: Basic realm=\"%s\"\r\n" "Content-Length: %d\r\n\r\n%s", realm, strlen (html), html); return (b); }
/* * dbuf_put - put a sequence of bytes in a dbuf */ int dbuf_put(struct DBuf* dyn, const char* buf, size_t length) { struct DBufBuffer** h; struct DBufBuffer* d; int chunk; /* * Locate the last non-empty buffer. If the last buffer is * full, the loop will terminate with 'd==NULL'. This loop * assumes that the 'dyn->length' field is correctly * maintained, as it should--no other check really needed. */ if (0 == dyn->length) h = &(dyn->head); else h = &(dyn->tail); /* * Append users data to buffer, allocating buffers as needed */ dyn->length += length; for ( ; length > 0; h = &(d->next)) { if (0 == (d = *h)) { if (0 == (d = dbuf_alloc())) return dbuf_malloc_error(dyn); dyn->tail = d; *h = d; /* prev->next = d */ } chunk = (d->data + DBUF_SIZE) - d->end; if (chunk) { if (chunk > length) chunk = length; memcpy(d->end, buf, chunk); length -= chunk; buf += chunk; d->end += chunk; } } return 1; }
/** Append bytes to a data buffer. * @param[in] dyn Buffer to append to. * @param[in] buf Data to append. * @param[in] length Number of bytes to append. * @return Non-zero on success, or zero on failure. */ int dbuf_put(struct DBuf *dyn, const char *buf, unsigned int length) { struct DBufBuffer** h; struct DBufBuffer* db; unsigned int chunk; assert(0 != dyn); assert(0 != buf); /* * Locate the last non-empty buffer. If the last buffer is full, * the loop will terminate with 'db==NULL'. * This loop assumes that the 'dyn->length' field is correctly * maintained, as it should--no other check really needed. */ if (!dyn->length) h = &(dyn->head); else h = &(dyn->tail); /* * Append users data to buffer, allocating buffers as needed */ dyn->length += length; for (; length > 0; h = &(db->next)) { if (0 == (db = *h)) { if (0 == (db = dbuf_alloc())) { if (feature_bool(FEAT_HAS_FERGUSON_FLUSHER)) { /* * from "Married With Children" episode were Al bought a REAL toilet * on the black market because he was tired of the wimpy water * conserving toilets they make these days --Bleep */ /* * Apparently this doesn't work, the server _has_ to * dump a few clients to handle the load. A fully loaded * server cannot handle a net break without dumping some * clients. If we flush the connections here under a full * load we may end up starving the kernel for mbufs and * crash the machine */ /* * attempt to recover from buffer starvation before * bailing this may help servers running out of memory */ flush_connections(0); db = dbuf_alloc(); } if (0 == db) return dbuf_malloc_error(dyn); } dyn->tail = db; *h = db; db->next = 0; db->start = db->end = db->data; } chunk = (db->data + DBUF_SIZE) - db->end; if (chunk) { if (chunk > length) chunk = length; memcpy(db->end, buf, chunk); length -= chunk; buf += chunk; db->end += chunk; } } return 1; }
/* * Receive a reply message */ DBUF *ebxml_receive (NETCON *conn) { long n; int e; char c, *ch; DBUF *b; b = dbuf_alloc (); n = 0; /* * read to end of message request header - empty line */ while ((e = net_read (conn, &c, 1)) == 1) { dbuf_putc (b, c); if (c == '\n') { if (n++ == 1) break; } else if (c != '\r') n = 0; } if (e != 1) { if (e == 0) error ("Acknowledgment header read failed or connection closed\n"); else error ("Timed out reading acknowledgment header\n"); dbuf_free (b); return (NULL); } ch = strnstr (dbuf_getbuf (b), "Content-Length: ", dbuf_size (b)); if (ch == NULL) { error ("Acknowledgment header missing Content-Length\n"); dbuf_free (b); return (NULL); } n = atol (ch + 16); debug ("expecting %d bytes\n", n); readbytes: while (n--) { if ((e = net_read (conn, &c, 1)) != 1) { if (e == 0) error ("Acknowledgment content read failed or connection closed"); else error ("Timed out reading acknowledgment content\n"); // note we'll take what we get and hope it's enough... break; } dbuf_putc (b, c); } if (n = net_available (conn)) { warn ("Found %d unread bytes...\n", n); goto readbytes; } debug ("returning %d bytes\n", dbuf_size (b)); return (b); }
/* * Build and return the mime payload container */ MIME *ebxml_getpayload (XML *xml, QUEUEROW *r) { int l, mapi; XML *exml; MIME *msg; char *b, /* buffer for payload */ *type, *unc = NULL, /* encryption info */ *pw = NULL, dn[DNSZ], *organization, pid[MAX_PATH], buf[MAX_PATH], fname[MAX_PATH]; debug ("getpayload container...\n"); if ((mapi = ebxml_pid (xml, r, pid)) < 0) return (NULL); ppathf (fname, cfg_map (xml, mapi, "Processed"), "%s", queue_field_get (r, "PAYLOADFILE")); /* invoke the filter if given */ b = cfg_map (xml, mapi, "Filter"); if (*b) { char *emsg; DBUF *rbuf = dbuf_alloc (); debug ("filter read %s with %s\n", fname, b); if (filter_run (b, fname, NULL, NULL, rbuf, &emsg, cfg_timeout (xml))) { error ("Can't filter %s - %s\n", fname, strerror (errno)); dbuf_free (rbuf); return (NULL); } if (*emsg) warn ("filter %s returned %s\n", b, emsg); free (emsg); l = dbuf_size (rbuf); b = dbuf_extract (rbuf); } else { debug ("reading data from %s\n", fname); if ((b = readfile (fname, &l)) == NULL) { error ("Can't read %s - %s\n", fname, strerror (errno)); return (NULL); } } organization = cfg_org (xml); type = cfg_map (xml, mapi, "Encryption.Type"); if ((type != NULL) && *type) /* encrypted */ { unc = cfg_map (xml, mapi, "Encryption.Unc"); pw = cfg_map (xml, mapi, "Encryption.Password"); strcpy (dn, cfg_map (xml, mapi, "Encryption.Id")); } msg = payload_create (b, l, fname, organization, unc, dn, pw); free (b); if (msg == NULL) error ("Can't create payload container for %s\n", fname); return (msg); }
/* * Receive an incoming message */ DBUF *server_receive (NETCON *conn) { long n, sz; char c, *ch; DBUF *b; b = dbuf_alloc (); n = 0; /* * read to end of message request header - empty line */ while (net_read (conn, &c, 1) == 1) { dbuf_putc (b, c); if (c == '\n') { if (n++ == 1) break; } else if (c != '\r') n = 0; } if (n != 2) { debug ("no header - %d read\n", dbuf_size (b)); if (dbuf_size (b)) { dbuf_printf (b, "%s", n == 1 ? "\r\n" : "\r\n\r\n"); warn ("can't find end of request header: %.*s", dbuf_size (b), dbuf_getbuf (b)); } n = 0; } else { ch = strnstr (dbuf_getbuf (b), "Content-Length: ", dbuf_size (b)); if (ch == NULL) n = 0; else n = atol (ch + 16); } debug ("expecting %d bytes\n", n); readbytes: while (n--) { if ((sz = net_read (conn, &c, 1)) != 1) { if (sz == 0) error ("Read failed or connection closed\n"); else error ("Read timed out\n"); // note we'll take what we get and hope it's enough... break; } dbuf_putc (b, c); } if (n = net_available (conn)) { warn ("Found %d unread bytes...\n", n); goto readbytes; } debug ("returning %d bytes\n", dbuf_size (b)); return (b); }