static int handler_process_control_request(Connection *conn, tns_value_t *data) { tns_value_t *args = darray_get(data->value.list, 1); check(args->type==tns_tag_dict, "Invalid control response: not a dict."); hnode_t *n = hash_lookup(args->value.dict, &KEEP_ALIVE); if(n != NULL) { Register_ping(IOBuf_fd(conn->iob)); } n = hash_lookup(args->value.dict, &CREDITS); if(n != NULL) { tns_value_t *credits = (tns_value_t *)hnode_get(n); conn->sendCredits += credits->value.number; taskwakeup(&conn->uploadRendez); } n = hash_lookup(args->value.dict, &CANCEL); if(n != NULL && !conn->closing) { Register_disconnect(IOBuf_fd(conn->iob)); taskwakeup(&conn->uploadRendez); } tns_value_destroy(data); return 0; error: return -1; }
int connection_msg_to_handler(Connection *conn) { Handler *handler = Request_get_action(conn->req, handler); int rc = 0; int header_len = Request_header_length(conn->req); // body_len will include \0 int body_len = Request_content_length(conn->req); check(handler, "JSON request doesn't match any handler: %s", bdata(Request_path(conn->req))); if(pattern_match(IOBuf_start(conn->iob), header_len + body_len, bdata(&PING_PATTERN))) { Register_ping(IOBuf_fd(conn->iob)); } else { check(body_len >= 0, "Parsing error, body length ended up being: %d", body_len); bstring payload = Request_to_payload(conn->req, handler->send_ident, IOBuf_fd(conn->iob), IOBuf_start(conn->iob) + header_len, body_len - 1); // drop \0 on payloads rc = Handler_deliver(handler->send_socket, bdata(payload), blength(payload)); bdestroy(payload); check(rc == 0, "Failed to deliver to handler: %s", bdata(Request_path(conn->req))); } // consumes \0 from body_len IOBuf_read_commit(conn->iob, header_len + body_len); return REQ_SENT; error: return CLOSE; }
static inline int close_or_error(Connection *conn, int next) { IOBuf_destroy(conn->proxy_iob); conn->proxy_iob = NULL; check_debug(Register_disconnect(IOBuf_fd(conn->iob)) != -1, "Register disconnect didn't work for %d", IOBuf_fd(conn->iob)); error: // fallthrough on purpose return next; }
Connection *Connection_create(Server *srv, int fd, int rport, const char *remote, SSL_CTX *ssl_ctx) { Connection *conn = h_calloc(sizeof(Connection), 1); check_mem(conn); conn->server = srv; conn->rport = rport; memcpy(conn->remote, remote, IPADDR_SIZE); conn->remote[IPADDR_SIZE] = '\0'; conn->type = 0; conn->req = Request_create(); check_mem(conn->req); if(ssl_ctx != NULL) { conn->iob = IOBuf_create(BUFFER_SIZE, fd, IOBUF_SSL); check(conn->iob != NULL, "Failed to create the SSL IOBuf."); conn->iob->ssl = ssl_server_new(ssl_ctx, IOBuf_fd(conn->iob)); check(conn->iob->ssl != NULL, "Failed to create new ssl for connection"); } else { conn->iob = IOBuf_create(BUFFER_SIZE, fd, IOBUF_SOCKET); } return conn; error: Connection_destroy(conn); return NULL; }
static ssize_t plain_stream_file(IOBuf *iob, int fd, off_t len) { off_t sent = 0; off_t total = 0; off_t offset = 0; off_t block_size = MAX_SEND_BUFFER; int conn_fd = IOBuf_fd(iob); for(total = 0; fdwait(conn_fd, 'w') == 0 && total < len; total += sent) { block_size = (len - total) > block_size ? block_size : (len - total); sent = IOBuf_sendfile(conn_fd, fd, &offset, block_size); check(Register_write(iob->fd, sent) != -1, "Socket seems to be closed."); check_debug(sent > 0, "Client closed probably during sendfile on socket: %d from " "file %d", conn_fd, fd); } check(total <= len, "Wrote way too much, wrote %d but size was %zd", (int)total, len); check(total == len, "Sent other than expected, sent: %d, but expected: %zd", (int)total, len); return total; error: return -1; }
void Connection_task(void *v) { Connection *conn = (Connection *)v; int i = 0; int next = OPEN; State_init(&conn->state, &CONN_ACTIONS); while(1) { if(Filter_activated()) { next = Filter_run(next, conn); check(next >= CLOSE && next < EVENT_END, "!!! Invalid next event[%d]: %d from filter!", i, next); } if(next == CLOSE) break; next = State_exec(&conn->state, next, (void *)conn); check(next >= CLOSE && next < EVENT_END, "!!! Invalid next event[%d]: %d, Tell ZED!", i, next); if(conn->iob && !conn->iob->closed) { Register_ping(IOBuf_fd(conn->iob)); } i++; } error: // fallthrough State_exec(&conn->state, CLOSE, (void *)conn); Connection_destroy(conn); taskexit(0); }
int connection_msg_to_handler(Connection *conn) { Handler *handler = Request_get_action(conn->req, handler); int rc = 0; int header_len = Request_header_length(conn->req); // body_len will include \0 int body_len = Request_content_length(conn->req); check(handler, "JSON request doesn't match any handler: %s", bdata(Request_path(conn->req))); if(pattern_match(IOBuf_start(conn->iob), header_len + body_len, bdata(&PING_PATTERN))) { Register_ping(IOBuf_fd(conn->iob)); } else { check(body_len >= 0, "Parsing error, body length ended up being: %d", body_len); bstring payload = NULL; if(handler->protocol == HANDLER_PROTO_TNET) { payload = Request_to_tnetstring(conn->req, handler->send_ident, IOBuf_fd(conn->iob), IOBuf_start(conn->iob) + header_len, body_len - 1); // drop \0 on payloads } else if(handler->protocol == HANDLER_PROTO_JSON) { payload = Request_to_payload(conn->req, handler->send_ident, IOBuf_fd(conn->iob), IOBuf_start(conn->iob) + header_len, body_len - 1); // drop \0 on payloads } else { sentinel("Invalid protocol type: %d", handler->protocol); } debug("SENT: %s", bdata(payload)); check(payload != NULL, "Failed to generate payload."); check(handler->send_socket != NULL, "Handler socket is NULL, tell Zed."); rc = Handler_deliver(handler->send_socket, bdata(payload), blength(payload)); free(payload); check(rc == 0, "Failed to deliver to handler: %s", bdata(Request_path(conn->req))); } // consumes \0 from body_len check(IOBuf_read_commit(conn->iob, header_len + body_len) != -1, "Final commit failed."); return REQ_SENT; error: return CLOSE; }
char *test_IOBuf_send_operations() { Connection *conn = fake_conn("/dev/null", O_WRONLY); mu_assert(conn != NULL, "Failed to allocate buf."); IOBuf *buf = conn->iob; mu_assert(Register_fd_exists(IOBuf_fd(buf)) != NULL, "Damn fd isn't registered."); int rc = IOBuf_send(buf, "012345789", 10); mu_assert(!IOBuf_closed(buf), "Should not be closed."); mu_assert(rc == 10, "Should have sent 10 bytes."); fdclose(IOBuf_fd(buf)); rc = IOBuf_send(buf, "012345789", 10); mu_assert(IOBuf_closed(buf), "Should be closed."); mu_assert(rc == -1, "Should send nothing."); fake_conn_close(conn); return NULL; }
void Connection_deliver_task(void *v) { Connection *conn=v; bstring msg=NULL; while(1) { msg = Connection_deliver_dequeue(conn); check_debug(msg,"Received NULL msg on FD %d, exiting deliver task",IOBuf_fd(conn->iob)); check(-1 != Connection_deliver_raw_internal(conn,msg),"Error delivering to MSG listener on FD %d, closing them.", IOBuf_fd(conn->iob)); bdestroy(msg); msg=NULL; } error: conn->deliverTaskStatus=DT_DYING; while(conn->deliverPost > conn->deliverAck) { bdestroy(Connection_deliver_dequeue(conn)); } bdestroy(msg); if (IOBuf_fd(conn->iob) >= 0) shutdown(IOBuf_fd(conn->iob), SHUT_RDWR); debug("Deliver Task Shut Down\n"); conn->deliverTaskStatus=DT_DEAD; taskexit(0); }
int Connection_send_to_handler(Connection *conn, Handler *handler, char *body, int content_len) { int rc = 0; bstring payload = NULL; if(conn->iob->use_ssl) Connection_fingerprint_from_cert(conn); error_unless(handler->running, conn, 404, "Handler shutdown while trying to deliver: %s", bdata(Request_path(conn->req))); if(handler->protocol == HANDLER_PROTO_TNET) { payload = Request_to_tnetstring(conn->req, handler->send_ident, IOBuf_fd(conn->iob), body, content_len); } else if(handler->protocol == HANDLER_PROTO_JSON) { payload = Request_to_payload(conn->req, handler->send_ident, IOBuf_fd(conn->iob), body, content_len); } else { sentinel("Invalid protocol type: %d", handler->protocol); } check(payload, "Failed to create payload for request."); debug("HTTP TO HANDLER: %.*s", blength(payload) - content_len, bdata(payload)); rc = Handler_deliver(handler->send_socket, bdata(payload), blength(payload)); free(payload); payload = NULL; error_unless(rc != -1, conn, 502, "Failed to deliver to handler: %s", bdata(Request_path(conn->req))); return 0; error: if(payload) free(payload); return -1; }
int Connection_accept(Connection *conn) { check(Register_connect(IOBuf_fd(conn->iob), (void*)conn) != -1, "Failed to register connection."); check(taskcreate(Connection_task, conn, CONNECTION_STACK) != -1, "Failed to create connection task."); check(taskcreate(Connection_deliver_task, conn, CONNECTION_STACK) != -1, "Failed to create connection task."); conn->deliverTaskStatus=DT_RUNNING; return 0; error: IOBuf_register_disconnect(conn->iob); return -1; }
int Connection_deliver(Connection *conn, bstring buf) { int rc = 0; bstring b64_buf = bBase64Encode(buf); check(b64_buf != NULL, "Failed to base64 encode data."); check(conn->iob != NULL, "There's no IOBuffer to send to, Tell Zed."); /* The deliver task will free the buffer */ rc = Connection_deliver_enqueue(conn,b64_buf); check_debug(rc == 0, "Failed to write message to conn %d", IOBuf_fd(conn->iob)); return 0; error: bdestroy(b64_buf); return -1; }
static ssize_t ssl_stream_file(IOBuf *iob, int fd, off_t len) { ssize_t sent = 0; off_t total = 0; ssize_t amt = 0; ssize_t tosend = 0; int conn_fd = IOBuf_fd(iob); char buff[1024]; for(total = 0; fdwait(conn_fd, 'w') == 0 && total < len; total += tosend) { tosend = pread(fd, buff, sizeof(buff), total); check_debug(tosend > 0, "Came up short in reading file %d\n", fd); // We do this in case the file somehow lengthened on us. In general, // it shouldn't happen. if(tosend + total > len) tosend = len - total; sent = 0; while(sent < tosend) { amt = ssl_send(iob, buff, tosend); check_debug(amt > 0, "ssl_send failed in ssl_stream_file with " "return code %zd", amt); sent += amt; } check(Register_write(iob->fd, sent) != -1, "Failed to record write, must have died."); } check(total <= len, "Wrote way too much, wrote %d but size was %zd", (int)total, len); check(total == len, "Sent other than expected, sent: %d, but expected: %zd", (int)total, len); return total; error: return -1; }
int Connection_send_to_handler(Connection *conn, Handler *handler, char *body, int content_len) { int rc = 0; bstring result = NULL; result = Request_to_payload(conn->req, handler->send_ident, IOBuf_fd(conn->iob), body, content_len); check(result, "Failed to create payload for request."); debug("HTTP TO HANDLER: %.*s", blength(result) - content_len, bdata(result)); rc = Handler_deliver(handler->send_socket, bdata(result), blength(result)); error_unless(rc != -1, conn, 502, "Failed to deliver to handler: %s", bdata(Request_path(conn->req))); bdestroy(result); return 0; error: bdestroy(result); return -1; }
static inline int ident_and_register(Connection *conn, int reg_too) { int next = CLOSE; if(Request_is_xml(conn->req)) { if(biseq(Request_path(conn->req), &POLICY_XML_REQUEST)) { debug("XML POLICY CONNECTION"); conn->type = CONN_TYPE_SOCKET; taskname("XML"); next = SOCKET_REQ; } else { debug("XML MESSAGE"); conn->type = CONN_TYPE_MSG; taskname("MSG"); next = MSG_REQ; } } else if(Request_is_json(conn->req)) { debug("JSON SOCKET MESSAGE"); conn->type = CONN_TYPE_MSG; taskname("MSG"); next = MSG_REQ; } else if(Request_is_http(conn->req)) { debug("HTTP MESSAGE"); conn->type = CONN_TYPE_HTTP; taskname("HTTP"); next = HTTP_REQ; } else { error_response(conn, 500, "Invalid code branch, tell Zed."); } if(reg_too) Register_connect(IOBuf_fd(conn->iob), (void*)conn); return next; error: return CLOSE; }
int Connection_deliver(Connection *conn, bstring buf) { int rc = 0; bstring b64_buf = bBase64Encode(buf); rc = IOBuf_send(conn->iob, bdata(b64_buf), blength(b64_buf)+1); check_debug(rc == blength(b64_buf)+1, "Failed to write entire message to conn %d", IOBuf_fd(conn->iob)); bdestroy(b64_buf); return 0; error: bdestroy(b64_buf); return -1; }