int as_msg_send_reply(as_file_handle *fd_h, uint32_t result_code, uint32_t generation, uint32_t void_time, as_msg_op **ops, as_bin **bins, uint16_t bin_count, as_namespace *ns, uint *written_sz, uint64_t trid, const char *setname) { int rv = 0; // most cases are small messages - try to stack alloc if we can byte fb[MSG_STACK_BUFFER_SZ]; size_t msg_sz = sizeof(fb); // memset(fb,0xff,msg_sz); // helpful to see what you might not be setting uint8_t *msgp = (uint8_t *) as_msg_make_response_msg( result_code, generation, void_time, ops, bins, bin_count, ns, (cl_msg *)fb, &msg_sz, trid, setname); if (!msgp) return(-1); if (fd_h->fd == 0) { cf_warning(AS_PROTO, "write to fd 0 internal error"); cf_crash(AS_PROTO, "send reply: can't write to fd 0"); } // cf_detail(AS_PROTO, "write fd %d",fd); size_t pos = 0; while (pos < msg_sz) { int rv = send(fd_h->fd, msgp + pos, msg_sz - pos, MSG_NOSIGNAL); if (rv > 0) { pos += rv; } else if (rv < 0) { if (errno != EWOULDBLOCK) { // common message when a client aborts cf_debug(AS_PROTO, "protocol write fail: fd %d sz %zd pos %zd rv %d errno %d", fd_h->fd, msg_sz, pos, rv, errno); as_end_of_transaction_force_close(fd_h); rv = -1; goto Exit; } usleep(1); // Yield } else { cf_info(AS_PROTO, "protocol write fail zero return: fd %d sz %d pos %d ", fd_h->fd, msg_sz, pos); as_end_of_transaction_force_close(fd_h); rv = -1; goto Exit; } } // good for stats as a higher layer if (written_sz) *written_sz = msg_sz; as_end_of_transaction_ok(fd_h); Exit: if ((uint8_t *)msgp != fb) cf_free(msgp); return(rv); }
// Security is an enterprise feature. If we receive a security message from a // client here, quickly return AS_SEC_ERR_NOT_SUPPORTED. The client may choose // to continue using this (unsecured) socket. void as_security_transact(as_transaction* tr) { // We don't need the request, since we're ignoring it. cf_free(tr->msgp); tr->msgp = NULL; // Set up a simple response with a single as_sec_msg that has no fields. size_t resp_size = sizeof(as_proto) + sizeof(as_sec_msg); uint8_t resp[resp_size]; // Fill out the as_proto fields. as_proto* p_resp_proto = (as_proto*)resp; p_resp_proto->version = PROTO_VERSION; p_resp_proto->type = PROTO_TYPE_SECURITY; p_resp_proto->sz = sizeof(as_sec_msg); // Switch to network byte order. as_proto_swap(p_resp_proto); uint8_t* p_proto_body = resp + sizeof(as_proto); memset((void*)p_proto_body, 0, sizeof(as_sec_msg)); // Fill out the relevant as_sec_msg fields. as_sec_msg* p_sec_msg = (as_sec_msg*)p_proto_body; p_sec_msg->scheme = AS_SEC_MSG_SCHEME; p_sec_msg->result = AS_SEC_ERR_NOT_SUPPORTED; // Send the complete response. cf_socket *sock = &tr->from.proto_fd_h->sock; if (cf_socket_send_all(sock, resp, resp_size, MSG_NOSIGNAL, CF_SOCKET_TIMEOUT) < 0) { cf_warning(AS_SECURITY, "fd %d send failed, errno %d", CSFD(sock), errno); as_end_of_transaction_force_close(tr->from.proto_fd_h); tr->from.proto_fd_h = NULL; return; } as_end_of_transaction_ok(tr->from.proto_fd_h); tr->from.proto_fd_h = NULL; }
// Send a response made by write_local(). // TODO - refactor and share with as_msg_send_reply(). int as_msg_send_ops_reply(as_file_handle *fd_h, cf_dyn_buf *db) { int rv = 0; if (fd_h->fd == 0) { cf_crash(AS_PROTO, "fd is 0"); } uint8_t *msgp = db->buf; size_t msg_sz = db->used_sz; size_t pos = 0; while (pos < msg_sz) { int result = send(fd_h->fd, msgp + pos, msg_sz - pos, MSG_NOSIGNAL); if (result > 0) { pos += result; } else if (result < 0) { if (errno != EWOULDBLOCK) { // Common when a client aborts. cf_debug(AS_PROTO, "protocol write fail: fd %d sz %zd pos %zd rv %d errno %d", fd_h->fd, msg_sz, pos, rv, errno); as_end_of_transaction_force_close(fd_h); rv = -1; goto Exit; } usleep(1); // yield } else { cf_info(AS_PROTO, "protocol write fail zero return: fd %d sz %d pos %d ", fd_h->fd, msg_sz, pos); as_end_of_transaction_force_close(fd_h); rv = -1; goto Exit; } } as_end_of_transaction_ok(fd_h); Exit: return rv; }
// Security is an enterprise feature. If we receive a security message from a // client here, quickly return AS_SEC_ERR_NOT_SUPPORTED. The client may choose // to continue using this (unsecured) socket. void as_security_transact(as_transaction* tr) { // We don't need the request, since we're ignoring it. cf_free(tr->msgp); tr->msgp = NULL; // Set up a simple response with a single as_sec_msg that has no fields. size_t resp_size = sizeof(as_proto) + sizeof(as_sec_msg); uint8_t resp[resp_size]; // Fill out the as_proto fields. as_proto* p_resp_proto = (as_proto*)resp; p_resp_proto->version = PROTO_VERSION; p_resp_proto->type = PROTO_TYPE_SECURITY; p_resp_proto->sz = sizeof(as_sec_msg); // Switch to network byte order. as_proto_swap(p_resp_proto); uint8_t* p_proto_body = resp + sizeof(as_proto); memset((void*)p_proto_body, 0, sizeof(as_sec_msg)); // Fill out the relevant as_sec_msg fields. as_sec_msg* p_sec_msg = (as_sec_msg*)p_proto_body; p_sec_msg->scheme = AS_SEC_MSG_SCHEME; p_sec_msg->result = AS_SEC_ERR_NOT_SUPPORTED; // Send the complete response. uint8_t* p_write = resp; uint8_t* p_end = resp + resp_size; int fd = tr->from.proto_fd_h->fd; while (p_write < p_end) { int rv = send(fd, (void*)p_write, p_end - p_write, MSG_NOSIGNAL); if (rv > 0) { p_write += rv; } else if (rv == 0) { cf_warning(AS_SECURITY, "fd %d send returned 0", fd); as_end_of_transaction_force_close(tr->from.proto_fd_h); tr->from.proto_fd_h = NULL; return; } // rv < 0 else if (errno == EAGAIN || errno == EWOULDBLOCK) { usleep(1); } else { cf_warning(AS_SECURITY, "fd %d send failed, errno %d", fd, errno); as_end_of_transaction_force_close(tr->from.proto_fd_h); tr->from.proto_fd_h = NULL; return; } } as_end_of_transaction_ok(tr->from.proto_fd_h); tr->from.proto_fd_h = NULL; }