/** Flush empty lines from a buffer. * @param[in,out] dyn Data buffer to flush. * @return Number of bytes in first available block (or zero if none). */ static unsigned int dbuf_flush(struct DBuf *dyn) { struct DBufBuffer *db = dyn->head; if (0 == db) return 0; assert(db->start < db->end); /* * flush extra line terms */ while (IsEol(*db->start)) { if (++db->start == db->end) { dyn->head = db->next; dbuf_free(db); if (0 == (db = dyn->head)) { dyn->tail = 0; dyn->length = 0; break; } } --dyn->length; } return dyn->length; }
void va_emitcode (const char *inst, const char *fmt, va_list ap) { const char *line = format_opcode (inst, fmt, ap); emit_raw (line); dbuf_free (line); }
/** Discard data from a DBuf. * @param[in,out] dyn DBuf to drop data from. * @param[in] length Number of bytes to discard. */ void dbuf_delete(struct DBuf *dyn, unsigned int length) { struct DBufBuffer *db; unsigned int chunk; if (length > dyn->length) length = dyn->length; while (length > 0) { if (0 == (db = dyn->head)) break; chunk = db->end - db->start; if (chunk > length) chunk = length; length -= chunk; dyn->length -= chunk; db->start += chunk; if (db->start == db->end) { dyn->head = db->next; dbuf_free(db); } } if (0 == dyn->head) { dyn->length = 0; dyn->tail = 0; } }
/* ** This is called when malloc fails. Scrap the whole content ** of dynamic buffer and return -1. (malloc errors are FATAL, ** there is no reason to continue this buffer...). After this ** the "dbuf" has consistent EMPTY status... ;) */ static int dbuf_malloc_error(struct DBuf* dyn) { struct DBufBuffer* db; dyn->length = 0; while (0 != (db = dyn->head)) { dyn->head = db->next; dbuf_free(db); } dyn->tail = 0; return 0; }
/* * TASK to handle an incoming request */ int server_request (void *parm) { SERVERPARM *s; DBUF *req, *res; char *curl; s = (SERVERPARM *) parm; curl = xml_get_text (s->xml, "Phineas.Console.Url"); res = NULL; while ((req = server_receive (s->conn)) != NULL) { debug ("received %d bytes\n", dbuf_size (req)); if (dbuf_size (req) == 0) { dbuf_free (req); net_close (s->conn); return (-1); } dbuf_putc (req, 0); /* * log the request, but filter out GET requests for the console... * noise */ if (!(*curl && strstarts (dbuf_getbuf (req) + 4, curl))) server_logrequest (s->conn, dbuf_size (req), dbuf_getbuf (req)); if ((res = server_response (s->xml, dbuf_getbuf (req))) == NULL) { res = server_respond (500, "<h3>Failure processing ebXML request</h3>"); } server_header (res); net_write (s->conn, dbuf_getbuf (res), dbuf_size (res)); dbuf_free (res); dbuf_free (req); } net_close (s->conn); debug ("request completed\n"); return (0); }
/** Handle a memory allocation error on a DBuf. * This frees all the buffers owned by the DBuf, since we have to * close the associated connection. * @param[in] dyn DBuf to clean out. * @return Zero. */ static int dbuf_malloc_error(struct DBuf *dyn) { struct DBufBuffer *db; struct DBufBuffer *next; for (db = dyn->head; db; db = next) { next = db->next; dbuf_free(db); } dyn->tail = dyn->head = 0; dyn->length = 0; return 0; }
/*-----------------------------------------------------------------*/ void genInline (iCode * ic) { char *buf, *bp, *begin; bool inComment = FALSE; D (emitcode (";", "genInline")); genLine.lineElement.isInline += (!options.asmpeep); buf = bp = begin = Safe_strdup (IC_INLINE (ic)); /* Emit each line as a code */ while (*bp) { switch (*bp) { case ';': inComment = TRUE; ++bp; break; case '\x87': case '\n': inComment = FALSE; *bp++ = '\0'; /* Don't emit leading whitespaces */ while (isspace (*begin)) ++begin; if (*begin) emitcode (begin, NULL); begin = bp; break; default: /* Add \n for labels, not dirs such as c:\mydir */ if (!inComment && (*bp == ':') && (isspace ((unsigned char) bp[1]))) { ++bp; *bp = '\0'; ++bp; emitcode (begin, NULL); begin = bp; } else ++bp; break; } } if (begin != bp) { /* Don't emit leading whitespaces */ while (isspace (*begin)) ++begin; if (*begin) emitcode (begin, NULL); } Safe_free (buf); /* consumed; we can free it here */ dbuf_free (IC_INLINE (ic)); genLine.lineElement.isInline -= (!options.asmpeep); }
/* * send a message * return non-zero if message not sent successful with completed * queue info for status and transport */ int ebxml_send (XML*xml, QUEUEROW *r, MIME *msg) { DBUF *b; NETCON *conn; char host[MAX_PATH]; /* need buffers for redirect */ char path[MAX_PATH]; int port, route, timeout, delay, retry; SSL_CTX *ctx; char *rname, /* route name */ *content, /* message content */ buf[MAX_PATH]; /* format up the message */ if ((content = mime_format (msg)) == NULL) { queue_field_set (r, "PROCESSINGSTATUS", "done"); queue_field_set (r, "TRANSPORTSTATUS", "failed"); queue_field_set (r, "TRANSPORTERRORCODE", "failed formatting message"); return (-1); } debug ("Send content:\n%s\n", content); /* * get connection info from the record route */ if ((route = cfg_route_index (xml, queue_field_get (r, "ROUTEINFO"))) < 0) { queue_field_set (r, "PROCESSINGSTATUS", "done"); queue_field_set (r, "TRANSPORTSTATUS", "failed"); queue_field_set (r, "TRANSPORTERRORCODE", "bad route"); return (-1); } rname = cfg_route (xml, route, "Name"); ctx = ebxml_route_ctx (xml, route); strcpy (host, cfg_route (xml, route, "Host")); port = atoi (cfg_route (xml, route, "Port")); if ((retry = atoi (cfg_route (xml, route, "Retry"))) == 0) retry = cfg_retries (xml); timeout = atoi (cfg_route (xml, route, "Timeout")); delay = cfg_delay (xml); strcpy (path, cfg_route (xml, route, "Path")); sendmsg: info ("Sending ebXML %s:%d to %s\n", r->queue->name, r->rowid, rname); debug ("opening connection socket on port=%d retrys=%d timeout=%d\n", port, retry, timeout); if ((conn = net_open (host, port, 0, ctx)) == NULL) { error ("failed opening connection to %s:%d\n", host, port); goto retrysend; } /* set read timeout if given */ if (timeout) { net_timeout (conn, timeout * 1000); timeout <<= 1; /* bump each try */ } delay = 0; /* connection OK, don't delay */ queue_field_set (r, "MESSAGESENTTIME", ptime (NULL, buf)); sprintf (buf, "POST %s HTTP/1.1\r\n", path); // ch = ebxml_beautify (ch); /* all set... send the message */ debug ("sending message...\n"); net_write (conn, buf, strlen (buf)); net_write (conn, content, strlen (content)); debug ("reading response...\n"); b = ebxml_receive (conn); debug ("closing socket...\n"); net_close (conn); /* no reply? */ if (b == NULL) { warn ("Send response timed out or closed for %s\n", rname); retrysend: /* retry with a wait, or.. */ if (retry-- && phineas_running ()) { if (delay) { info ("Retrying send to %s in %d seconds\n", rname, delay); sleep (delay * 1000); delay <<= 1; } else /* reset connection delay */ delay = cfg_delay (xml); goto sendmsg; } if (ctx != NULL) /* give up! */ SSL_CTX_free (ctx); free (content); queue_field_set (r, "PROCESSINGSTATUS", "done"); queue_field_set (r, "TRANSPORTSTATUS", "failed"); queue_field_set (r, "TRANSPORTERRORCODE", "retries exhausted"); return (-1); } debug ("reply was %d bytes\n%.*s\n", dbuf_size (b), dbuf_size (b), dbuf_getbuf (b)); /* * handle redirects... * note this assumes the same SSL context should be used */ if (ebxml_redirect (dbuf_getbuf (b), host, &port, path)) { dbuf_free (b); goto sendmsg; } if (ctx != NULL) SSL_CTX_free (ctx); if (ebxml_parse_reply (dbuf_getbuf (b), r)) { queue_field_set (r, "PROCESSINGSTATUS", "done"); queue_field_set (r, "TRANSPORTSTATUS", "failed"); queue_field_set (r, "TRANSPORTERRORCODE", "garbled reply"); } debug ("send completed\n"); dbuf_free (b); free (content); return (0); }
/* * 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); }