static int is_dupe(merlin_event *pkt) { if (!check_dupes) { return 0; } if (last_pkt.hdr.type != pkt->hdr.type) { return 0; } if (packet_size(&last_pkt) != packet_size(pkt)) { return 0; } /* if this is truly a dupe, return 1 and log every 100'th */ if (!memcmp(&last_pkt, pkt, packet_size(pkt))) { dupe_bytes += packet_size(pkt); if (!(++dupes % 100)) { ldebug("%s in %llu duplicate packets dropped", human_bytes(dupe_bytes), dupes); } return 1; } return 0; }
/* * Send the given event "pkt" to the node "node", or take appropriate * actions on the node itself in case sending fails. * Returns 0 on success, and < 0 otherwise. */ int node_send_event(merlin_node *node, merlin_event *pkt, int msec) { int result; node_log_event_count(node, 0); if (packet_size(pkt) > TOTAL_PKT_SIZE) { lerr("header is invalid, or packet is too large. aborting"); return -1; } if (node->sock < 0 || node->state != STATE_CONNECTED) { return node_binlog_add(node, pkt); } /* * msec less than zero means the caller has already polled the * socket, which should also mean it's connected */ if (msec >= 0 && !io_write_ok(node->sock, msec)) { return node_binlog_add(node, pkt); } if (is_module && is_stalling()) { return node_binlog_add(node, pkt); } /* if binlog has entries, we must send those first */ if (binlog_has_entries(node->binlog)) { node_send_binlog(node, pkt); } /* binlog may still have entries. If so, add to it and return */ if (binlog_has_entries(node->binlog)) return node_binlog_add(node, pkt); result = node_send(node, pkt, packet_size(pkt), MSG_DONTWAIT); /* successfully sent, so add it to the counter and return 0 */ if (result == packet_size(pkt)) { node->stats.events.sent++; return 0; } /* * zero size writes and write errors get stashed in binlog. * From the callers point of view, this counts as a success. */ if (result <= 0 && !node_binlog_add(node, pkt)) return 0; /* node_send will have marked the node as out of sync now */ return -1; }
static int node_binlog_add(merlin_node *node, merlin_event *pkt) { int result; /* * we skip stashing some packet types in the binlog. Typically * those that get generated immediately upon reconnect anyway * since they would just cause unnecessary overhead and might * trigger a lot of unnecessary actions if stashed. */ if (pkt->hdr.type == CTRL_PACKET) { if (pkt->hdr.code == CTRL_ACTIVE || pkt->hdr.code == CTRL_INACTIVE) return 0; } if (!node->binlog) { char *path; /* +20 to safely accommodate for "/.module.binlog\0" */ path = calloc(1, strlen(binlog_dir) + strlen(node->name) + 20); sprintf(path, "%s/%s.%s.binlog", binlog_dir, is_module ? "module" : "daemon", node->name); linfo("Creating binary backlog for %s. On-disk location: %s", node->name, path); /* 10MB in memory, 100MB on disk */ node->binlog = binlog_create(path, 10 << 20, 100 << 20, BINLOG_UNLINK); if (!node->binlog) { lerr("Failed to create binary backlog for %s: %s", node->name, strerror(errno)); return -1; } free(path); } result = binlog_add(node->binlog, pkt, packet_size(pkt)); if (result < 0) { binlog_wipe(node->binlog, BINLOG_UNLINK); /* XXX should mark node as unsynced here */ node->stats.events.dropped += node->stats.events.logged + 1; node->stats.bytes.dropped += node->stats.bytes.logged + packet_size(pkt); node->stats.events.logged = 0; node->stats.bytes.logged = 0; } else { node->stats.events.logged++; node->stats.bytes.logged += packet_size(pkt); } node_log_event_count(node, 0); return result; }
QByteArray Message::createPacket() const { QByteArray packet; qint32 packet_size(0); QDataStream out(&packet, QIODevice::WriteOnly ); //qDebug() << Q_FUNC_INFO << "\n ----------------- Create packet ---------------------\n"; out.setVersion(QDataStream::Qt_4_0); // Вставим размер пакета равный нулю, но отведем под него 8 байт out << packet_size; //Вставим Тип сообщения и само сообщение в пакет //qDebug() << "\n (qint32) packet type " << ( qint32 ) this->getType(); out << ( qint32 ) this->getType(); //qDebug() << "\n message data_size " << this->msgData.size(); out << this->msgData; // возврат на начало блока out.device()->seek(0); // Вычислим размер блока данных и запишем их на свое место packet_size =(qint32)(packet.size() - sizeof(qint32)); out << ( qint32 ) packet_size; /* qDebug() << "data size " << packet_size; qDebug() << "all packet size " << (qint32)(packet.size() + sizeof(qint32)); qDebug() << "------------- end create packet -----------------------\n"; */ return packet; }
int main(int argc, char** argv) { bool bShutdown = false; fprintf(stderr, "Entering the loop.\n"); while ( !bShutdown ) { byte_t packet_size_buff[ERL_MSG_HEADER_SIZE]; byte_t packet_payload[ERL_MSG_MAX_SIZE]; ssize_t bytes_read = 0; bytes_read = read(fileno(stdin), (void*) packet_size_buff, ERL_MSG_HEADER_SIZE); if ( bytes_read > 0 ) { size_t bytes_to_read = packet_size(packet_size_buff); fprintf(stderr, "Packet size: %d\n", bytes_to_read); bytes_read = read(fileno(stdin), (void*) packet_payload, bytes_to_read); if ( bytes_read != bytes_to_read ) { // fprintf(stderr, "wrong bytes_read: %d. Expected: %d\n. Errno: %s\n", bytes_read, bytes_to_read, strerror(errno)); bShutdown = true; } else { // process(packet_payload, bytes_to_read); } } else { fprintf(stderr, "Error: %s\n", strerror(errno)); bShutdown = true; } } fprintf(stderr, "Left the loop. Quitting.\n"); }
/** * hold_notification_packet() makes a deep copy of a notification message and * stores it in a global variable tmp_notif_data. The purpose is to make it * possible to send notification messages the triggering check result. * Meaning that if a processed check result generates a notification, the * notification will be stored and sent once the ending check result is sent. * Without this the check result will be sent right after the notification * packet making the receiver overwrite any information stored from the * notification packet. */ static int hold_notification_packet(merlin_event *pkt, nebstruct_notification_data *data) { if(tmp_notif_data) { return -1; /* there is already some stored notification, bailing */ } if (data->notification_type == HOST_NOTIFICATION) { ldebug("holding host notification for %s", data->host_name); } else { ldebug("holding service notification for %s;%s", data->service_description, data->host_name); } /* copy the notification data to storage */ memcpy(&tmp_notif_pkt, pkt, packet_size(pkt)); tmp_notif_data = malloc(sizeof(nebstruct_notification_data)); memcpy(tmp_notif_data, data, sizeof(nebstruct_notification_data)); tmp_notif_data->host_name = data->host_name ? strdup(data->host_name) : NULL; tmp_notif_data->service_description = data->service_description ? strdup(data->service_description) : NULL; tmp_notif_data->output = data->output ? strdup(data->output) : NULL; tmp_notif_data->ack_author = data->ack_author ? strdup(data->ack_author) : NULL; tmp_notif_data->ack_data = data->ack_data ? strdup(data->ack_data) : NULL; return 0; }
static char *recv_finish_packet(int sock, Buffer *buffer) { char *pack_start; uint32_t pack_size; ssize_t n_recvd; pack_start = buffer->buf_end; while ( (n_recvd = recv(sock, buffer->buf_end, (BUF_ALLOC_SIZE - (buffer->buf_end - buffer->next_boundary)), 0)) > 0) { buffer->buf_end += n_recvd; //check for oversized packets if ( buffer->buf_end - buffer->buf >= BUF_ALLOC_SIZE ) { fprintf(stderr, "packet is larger than buffer!\n"); return NULL; } //didn't even get full SIZE header, ask for more if ( buffer->buf_end - pack_start < PACK_HEAD_SIZE) { continue; } //get the final packet size pack_size = packet_size(buffer->buf); //have we read enough to encompass the packet? if ((uint32_t)(buffer->buf_end - pack_start) < pack_size) { continue; //not enough yet } else { break; // we got it! } } if (n_recvd == 0) { fprintf(stderr, "client disconnect\n"); return NULL; } else if (n_recvd < 0) { perror("recv (finish packet)"); return NULL; } if ((uint32_t)(buffer->buf_end - pack_start) < pack_size) { return NULL; //didn't get the whole packet, and didn't catch it in the loop. panic } else if ((uint32_t)(buffer->buf_end - pack_start) > pack_size) { buffer->next_boundary = pack_start + pack_size; //we started reading into the next packet } else { //we matched packet length exactly. next packet can start at buffer start buffer->buf_end = buffer->buf; buffer->next_boundary = NULL; } return pack_start; }
unsigned char *get_hub_query_cmd(size_t byte_count, size_t *buf_size) { unsigned char hub_query_cmd[] = { 0x01, 0x85, 0xf0, 0x10, 0x8f, 0x30, 0x0e, 0x00, 0x60, 0x82, 0x10, 0xde, 0x01, 0x81, 0x30, 0x8f, 0x30, 0x0c, 0x00, 0x60, 0x82, 0x10, 0x43, 0x00, 0x80, 0xa2, 0x00, 0x00, 0x81, 0x30, 0x82, 0x10, 0x43, 0x00, 0x80, 0xa2, 0x00, 0x00, 0x81, 0x30, 0x82, 0x10, 0x43, 0x00, 0x80, 0xa2, 0x00, 0x00, 0x81, 0x30, 0x82, 0x10, 0x43, 0x00, 0x80, 0xa2, 0x00, 0x00, 0x81, 0x30, 0x82, 0x10, 0x43, 0x00, 0x80, 0xa2, 0x00, 0x00, 0x81, 0x30, 0x82, 0x10, 0x43, 0x00, 0x80, 0xa2, 0x00, 0x00, 0x81, 0x30, 0x82, 0x10, 0x43, 0x00, 0x80, 0xa2, 0x00, 0x00, 0x81, 0x30, 0x82, 0x10, 0x43, 0x00, 0xc0, 0xa2, 0x00, 0x00, 0x81, 0x30, }; size_t len = sizeof(hub_query_cmd) / sizeof(*hub_query_cmd); *buf_size = packet_size(len); return packetize(hub_query_cmd, len, 1); }
unsigned char *packetize(unsigned char *the_bytes, size_t len, int channel) { size_t packet_len = packet_size(len); unsigned char *packet = new unsigned char[packet_len]; packet[0] = 0x7C; packet[1] = (unsigned char)channel; packet[2] = 0x7A; for (int i = 0; i < len; ++i) packet[i + 3] = the_bytes[i]; packet[packet_len - 1] = packet[packet_len - 2]; packet[packet_len - 2] = 0x7B; return packet; }
int ipc_binlog_add(merlin_event *pkt) { if (!ipc_binlog) { char *path; asprintf(&path, "/opt/monitor/op5/merlin/binlogs/ipc.%s.binlog", is_module ? "module" : "daemon"); /* 1MB in memory, 100MB on disk */ ipc_binlog = binlog_create(path, 1 << 20, 100 << 20, BINLOG_UNLINK); free(path); if (!ipc_binlog) return -1; } binlog_add(ipc_binlog, pkt, packet_size(pkt)); return 0; }
//! tries to convert the available bytes into a valid AuthHandler LinkLevelEvent. SEGSEvent * AuthLink::bytes_to_event() { uint16_t packet_size(0); uint8_t * tmp(nullptr); while(true) // we loop and loop and loop loopy loop through the buffery contents! { if(m_received_bytes_storage.GetReadableDataSize()<=2) // no more bytes for us, so we'll go hungry for a while return nullptr; // And the skies are clear on the Packet Fishing Waters m_received_bytes_storage.uGet(packet_size); // Ah ha! I smell packet in there! if(m_received_bytes_storage.GetReadableDataSize()<packet_size) // tis' a false trail capt'n ! { m_received_bytes_storage.PopFront(1); // Crew, Dead Slow Ahead ! we're in hunting mode ! continue; } // this might be a live packet in there tmp = m_received_bytes_storage.GetBuffer()+2; m_codec.XorDecodeBuf(tmp, packet_size+1); // Let's see what's in those murky waters eAuthPacketType recv_type = OpcodeToType(tmp[0]); AuthLinkEvent *evt = AuthEventFactory::EventForType(recv_type); // Crow's nest, report ! if(!evt) { if(m_received_bytes_storage.GetReadableDataSize()>2) // False alarm Skipper! m_received_bytes_storage.uGet(packet_size); // On to next adventure crew. Slow Ahead ! continue; } // A catch ! if(evt->type() == evLogin) // Is tis' on of those pesky AuthLogin Packets ?!!? { // Bring out the Codec Cannon, an' load it with Des m_codec.DesDecode(tmp+1,30); // It'll crack it's chitinous armor } evt->serializefrom(m_received_bytes_storage); m_received_bytes_storage.PopFront(packet_size+3); //Let's sail away from this depleted fishery. return evt; // And throw our catch to the Cook. } }
void http_seed_connection::on_receive(error_code const& error , std::size_t bytes_transferred) { INVARIANT_CHECK; if (error) { m_statistics.received_bytes(0, bytes_transferred); #ifdef TORRENT_VERBOSE_LOGGING peer_log("*** http_seed_connection error: %s", error.message().c_str()); #endif return; } boost::shared_ptr<torrent> t = associated_torrent().lock(); TORRENT_ASSERT(t); for (;;) { buffer::const_interval recv_buffer = receive_buffer(); if (bytes_transferred == 0) break; TORRENT_ASSERT(recv_buffer.left() > 0); TORRENT_ASSERT(!m_requests.empty()); if (m_requests.empty()) { m_statistics.received_bytes(0, bytes_transferred); disconnect(errors::http_error, 2); return; } peer_request front_request = m_requests.front(); bool header_finished = m_parser.header_finished(); if (!header_finished) { bool parse_error = false; int protocol = 0; int payload = 0; boost::tie(payload, protocol) = m_parser.incoming(recv_buffer, parse_error); m_statistics.received_bytes(0, protocol); bytes_transferred -= protocol; if (payload > front_request.length) payload = front_request.length; if (parse_error) { m_statistics.received_bytes(0, bytes_transferred); disconnect(errors::http_parse_error, 2); return; } TORRENT_ASSERT(recv_buffer.left() == 0 || *recv_buffer.begin == 'H'); TORRENT_ASSERT(recv_buffer.left() <= packet_size()); // this means the entire status line hasn't been received yet if (m_parser.status_code() == -1) { TORRENT_ASSERT(payload == 0); TORRENT_ASSERT(bytes_transferred == 0); break; } // if the status code is not one of the accepted ones, abort if (!is_ok_status(m_parser.status_code())) { int retry_time = atoi(m_parser.header("retry-after").c_str()); if (retry_time <= 0) retry_time = 5 * 60; // temporarily unavailable, retry later t->retry_web_seed(this, retry_time); std::string error_msg = to_string(m_parser.status_code()).elems + (" " + m_parser.message()); if (m_ses.m_alerts.should_post<url_seed_alert>()) { m_ses.m_alerts.post_alert(url_seed_alert(t->get_handle(), url() , error_msg)); } m_statistics.received_bytes(0, bytes_transferred); disconnect(error_code(m_parser.status_code(), get_http_category()), 1); return; } if (!m_parser.header_finished()) { TORRENT_ASSERT(payload == 0); TORRENT_ASSERT(bytes_transferred == 0); break; } } // we just completed reading the header if (!header_finished) { if (is_redirect(m_parser.status_code())) { // this means we got a redirection request // look for the location header std::string location = m_parser.header("location"); m_statistics.received_bytes(0, bytes_transferred); if (location.empty()) { // we should not try this server again. t->remove_web_seed(this); disconnect(errors::missing_location, 2); return; } // add the redirected url and remove the current one t->add_web_seed(location, web_seed_entry::http_seed); t->remove_web_seed(this); disconnect(errors::redirecting, 2); return; } std::string const& server_version = m_parser.header("server"); if (!server_version.empty()) { m_server_string = "URL seed @ "; m_server_string += m_host; m_server_string += " ("; m_server_string += server_version; m_server_string += ")"; } m_response_left = atol(m_parser.header("content-length").c_str()); if (m_response_left == -1) { m_statistics.received_bytes(0, bytes_transferred); // we should not try this server again. t->remove_web_seed(this); disconnect(errors::no_content_length, 2); return; } if (m_response_left != front_request.length) { m_statistics.received_bytes(0, bytes_transferred); // we should not try this server again. t->remove_web_seed(this); disconnect(errors::invalid_range, 2); return; } m_body_start = m_parser.body_start(); } recv_buffer.begin += m_body_start; // ========================= // === CHUNKED ENCODING === // ========================= while (m_parser.chunked_encoding() && m_chunk_pos >= 0 && m_chunk_pos < recv_buffer.left()) { int header_size = 0; size_type chunk_size = 0; buffer::const_interval chunk_start = recv_buffer; chunk_start.begin += m_chunk_pos; TORRENT_ASSERT(chunk_start.begin[0] == '\r' || is_hex(chunk_start.begin, 1)); bool ret = m_parser.parse_chunk_header(chunk_start, &chunk_size, &header_size); if (!ret) { TORRENT_ASSERT(bytes_transferred >= size_t(chunk_start.left() - m_partial_chunk_header)); bytes_transferred -= chunk_start.left() - m_partial_chunk_header; m_statistics.received_bytes(0, chunk_start.left() - m_partial_chunk_header); m_partial_chunk_header = chunk_start.left(); if (bytes_transferred == 0) return; break; } else { #ifdef TORRENT_VERBOSE_LOGGING peer_log("*** parsed chunk: %d header_size: %d", chunk_size, header_size); #endif TORRENT_ASSERT(bytes_transferred >= size_t(header_size - m_partial_chunk_header)); bytes_transferred -= header_size - m_partial_chunk_header; m_statistics.received_bytes(0, header_size - m_partial_chunk_header); m_partial_chunk_header = 0; TORRENT_ASSERT(chunk_size != 0 || chunk_start.left() <= header_size || chunk_start.begin[header_size] == 'H'); // cut out the chunk header from the receive buffer TORRENT_ASSERT(m_chunk_pos + m_body_start < INT_MAX); cut_receive_buffer(header_size, t->block_size() + 1024, int(m_chunk_pos + m_body_start)); recv_buffer = receive_buffer(); recv_buffer.begin += m_body_start; m_chunk_pos += chunk_size; if (chunk_size == 0) { TORRENT_ASSERT(receive_buffer().left() < m_chunk_pos + m_body_start + 1 || receive_buffer()[int(m_chunk_pos + m_body_start)] == 'H' || (m_parser.chunked_encoding() && receive_buffer()[int(m_chunk_pos + m_body_start)] == '\r')); m_chunk_pos = -1; } } } int payload = bytes_transferred; if (payload > m_response_left) payload = int(m_response_left); if (payload > front_request.length) payload = front_request.length; m_statistics.received_bytes(payload, 0); incoming_piece_fragment(payload); m_response_left -= payload; if (m_parser.status_code() == 503) { if (!m_parser.finished()) return; int retry_time = atol(std::string(recv_buffer.begin, recv_buffer.end).c_str()); if (retry_time <= 0) retry_time = 60; #ifdef TORRENT_VERBOSE_LOGGING peer_log("*** retrying in %d seconds", retry_time); #endif m_statistics.received_bytes(0, bytes_transferred); // temporarily unavailable, retry later t->retry_web_seed(this, retry_time); disconnect(error_code(m_parser.status_code(), get_http_category()), 1); return; } // we only received the header, no data if (recv_buffer.left() == 0) break; if (recv_buffer.left() < front_request.length) break; // if the response is chunked, we need to receive the last // terminating chunk and the tail headers before we can proceed if (m_parser.chunked_encoding() && m_chunk_pos >= 0) break; m_requests.pop_front(); incoming_piece(front_request, recv_buffer.begin); if (associated_torrent().expired()) return; int size_to_cut = m_body_start + front_request.length; TORRENT_ASSERT(receive_buffer().left() < size_to_cut + 1 || receive_buffer()[size_to_cut] == 'H' || (m_parser.chunked_encoding() && receive_buffer()[size_to_cut] == '\r')); cut_receive_buffer(size_to_cut, t->block_size() + 1024); if (m_response_left == 0) m_chunk_pos = 0; else m_chunk_pos -= front_request.length; bytes_transferred -= payload; m_body_start = 0; if (m_response_left > 0) continue; TORRENT_ASSERT(m_response_left == 0); m_parser.reset(); } }
/* @param: sock: socket to read from buffer: internal buffer, just keep giving it back to us and don't screw with it bufp: we will point this to the start of your requested packet, excluding the header @return 0: Client disconnected or serious error. You should shut down the socket >0: length of packet (in bytes), excluding the header */ uint32_t get_packet(int sock, Buffer *buffer, char **bufp) { uint32_t pack_size = 0; //on first read, buf will be uninitialized if (buffer->buf == NULL) { printf("initializing buffer\n"); buffer->buf = calloc(BUF_ALLOC_SIZE,1); //init the space we'll need to read everything into buffer->next_boundary = NULL; //when NULL, means there isn't a partial packet to pull from buffer->buf_end = buffer->buf; //we haven't read anything, so the end is the beginning } printf("Buffer start addr: %p, Buffer next read addr: %p, Buffer next packet start: %p\n", buffer->buf, buffer->buf_end, buffer->next_boundary); //if there are pending packets existing in the buffer if (buffer->next_boundary != NULL) { printf("there may be cached packets\n"); //check length, download anything necessary to finish if (buffer->buf_end - buffer->next_boundary < PACK_HEAD_SIZE) { printf("don't know the size of cached packet, have to read more\n"); //not enough of packet read to determine size *bufp = recv_finish_packet(sock, buffer); } else { //we can read the size, see if we have the whole packet already pack_size = packet_size(buffer->next_boundary); printf("cached packet has size %zu bytes\n", pack_size); if ((uint32_t)(buffer->buf_end - buffer->next_boundary) < pack_size) { printf("but we only have %d read. reading more\n", (buffer->buf_end - buffer->next_boundary)); // didn't receive enough to match packet size, ask for more *bufp = recv_finish_packet(sock,buffer); } else { printf("cached packet is fully downloaded already.\n"); //it is fully downloaded already *bufp = buffer->next_boundary; //point to the start of it buffer->next_boundary += pack_size; // point to the following packet // if there *is* no following packet already downloaded, mark everything clean if (buffer->next_boundary >= buffer->buf_end) { printf("no cached packets after this, resetting end and boundary\n"); buffer->buf_end = buffer->buf; buffer->next_boundary = NULL; } } } } else { printf("no cached packets, reading new ones\n"); //no packets in the buffer, wait for more *bufp = recv_new_packet(sock, buffer); } if (*bufp == NULL) { return 0; //client disconnected, or fatal error happened. } pack_size = packet_size(*bufp); *bufp += PACK_HEAD_SIZE; printf("returning packet at %p with size %zu (%zu with header)\n", *bufp, (pack_size - PACK_HEAD_SIZE ),pack_size); return pack_size - PACK_HEAD_SIZE; }
static char *recv_new_packet(int sock, Buffer *buffer) { uint32_t pack_size; ssize_t n_recvd; printf("starting recv_new_packet, resetting read ptr to %p\n", buffer->buf); buffer->buf_end = buffer->buf; //reset "read up to here" pointer while ( (n_recvd = recv(sock, buffer->buf_end, (BUF_ALLOC_SIZE - (buffer->buf_end - buffer->buf)), 0)) > 0) { /*printf("<"); for (int i=0; i<n_recvd; i++){ printf("[%02X]", buffer->buf_end[i]); } printf(">\n");*/ buffer->buf_end += n_recvd; printf("read %zu raw bytes, moving read ptr to %p\n", n_recvd, buffer->buf_end); //check for oversized packets if ((buffer->buf_end - buffer->buf) >= BUF_ALLOC_SIZE) { fprintf(stderr, "packet is larger than buffer!\n"); return NULL; } //didn't even get full SIZE header, ask for more if ( buffer->buf_end - buffer->buf < PACK_HEAD_SIZE) { printf("wasn't enough to get header, repeating read\n"); continue; } //get the final packet size pack_size = packet_size(buffer->buf); printf("packet size header read as %zu\n", pack_size); //have we read enough to encompass the packet? if ( (uint32_t)(buffer->buf_end - buffer->buf) < pack_size) { printf("total read (%d) less than packet size (%zu). repeating read\n",(buffer->buf_end - buffer->buf),pack_size); continue; //not enough yet } else { printf("read enough for the packet. breaking read loop\n"); break; //got it! } } if (n_recvd == 0) { fprintf(stderr, "client disconnect\n"); return NULL; } else if (n_recvd < 0) { perror("recv (new packet)"); return NULL; } if ((uint32_t)(buffer->buf_end - buffer->buf) < pack_size) { printf("packet under sized. freaking out\n"); return NULL; //we never got the whole packet, and didn't catch it above. SHUT IT DOWN } else if ((uint32_t)(buffer->buf_end - buffer->buf) > pack_size) { printf("read more than one packet. Read: %d, packet is only %zu\n", (buffer->buf_end - buffer->buf),pack_size); buffer->next_boundary = buffer->buf + pack_size; //we started reading something else! } else { printf("read exactly packet length. resetting buf_end and boundary pointers\n"); //we matched packet length exactly. Next packet can start at buf start buffer->buf_end = buffer->buf; buffer->next_boundary = NULL; } //since this is a new packet, it should be placed at the start of the buffer return buffer->buf; }
static int send_generic(merlin_event *pkt, void *data) { int result = 0; uint i, ntable_stop = num_masters + num_peers; linked_item *li; if ((!num_nodes || pkt->hdr.code == MAGIC_NONET) && !daemon_wants(pkt->hdr.type)) { ldebug("ipcfilter: Not sending %s event. %s, and daemon doesn't want it", callback_name(pkt->hdr.type), pkt->hdr.code == MAGIC_NONET ? "No-net magic" : "No nodes"); return 0; } if (!pkt->hdr.code == MAGIC_NONET && !daemon_wants(pkt->hdr.type)) { ldebug("ipcfilter: Not sending %s event. No-net magic and daemon doesn't want it", callback_name(pkt->hdr.type)); return 0; } pkt->hdr.len = merlin_encode_event(pkt, data); if (!pkt->hdr.len) { lerr("Header len is 0 for callback %d. Update offset in hookinfo.h", pkt->hdr.type); return -1; } if (is_dupe(pkt)) { ldebug("ipcfilter: Not sending %s event: Duplicate packet", callback_name(pkt->hdr.type)); return 0; } if (daemon_wants(pkt->hdr.type)) { result = ipc_send_event(pkt); /* * preserve the event so we can check for dupes, * but only if we successfully sent it */ if (result < 0) memset(&last_pkt, 0, sizeof(last_pkt)); else memcpy(&last_pkt, pkt, packet_size(pkt)); } if (!num_nodes) return 0; if (pkt->hdr.code == MAGIC_NONET) return 0; /* * The module can mark certain packets with a magic destination. * Such packets avoid all other inspection and get sent to where * the module wants us to. */ if (magic_destination(pkt)) { if ((pkt->hdr.selection & DEST_MASTERS) == DEST_MASTERS) { for (i = 0; i < num_masters; i++) { net_sendto(node_table[i], pkt); } } if ((pkt->hdr.selection & DEST_PEERS) == DEST_PEERS) { for (i = 0; i < num_peers; i++) { net_sendto(peer_table[i], pkt); } } if ((pkt->hdr.selection & DEST_POLLERS) == DEST_POLLERS) { for (i = 0; i < num_pollers; i++) { net_sendto(poller_table[i], pkt); } } return 0; } /* * "normal" packets get sent to all peers and masters, and possibly * a group of, or all, pollers as well */ /* general control packets are for everyone */ if (pkt->hdr.selection == CTRL_GENERIC && pkt->hdr.type == CTRL_PACKET) { ntable_stop = num_nodes; } /* Send this to all who should have it */ for (i = 0; i < ntable_stop; i++) { net_sendto(node_table[i], pkt); } /* if we've already sent to everyone we return early */ if (ntable_stop == num_nodes || !num_pollers) return 0; li = nodes_by_sel_id(pkt->hdr.selection); if (!li) { lerr("No matching selection for id %d", pkt->hdr.selection); return -1; } for (; li; li = li->next_item) { net_sendto((merlin_node *)li->item, pkt); } return result; }
int node_send_binlog(merlin_node *node, merlin_event *pkt) { merlin_event *temp_pkt; uint len; ldebug("Emptying backlog for %s", node->name); while (io_write_ok(node->sock, 10) && !binlog_read(node->binlog, (void **)&temp_pkt, &len)) { int result; if (!temp_pkt || packet_size(temp_pkt) != (int)len || !len || !packet_size(temp_pkt) || packet_size(temp_pkt) > MAX_PKT_SIZE) { if (!temp_pkt) { lerr("BACKLOG: binlog returned 0 but presented no data"); } else { lerr("BACKLOG: binlog returned a packet claiming to be of size %d", packet_size(temp_pkt)); } lerr("BACKLOG: binlog claims the data length is %u", len); lerr("BACKLOG: wiping backlog. %s is now out of sync", node->name); binlog_wipe(node->binlog, BINLOG_UNLINK); return -1; } errno = 0; result = node_send(node, temp_pkt, packet_size(temp_pkt), MSG_DONTWAIT); /* keep going while we successfully send something */ if (result == packet_size(temp_pkt)) { node->stats.events.sent++; node->stats.events.logged--; node->stats.bytes.logged -= packet_size(temp_pkt); /* * binlog duplicates the memory, so we must release it * when we've sent and counted it */ free(temp_pkt); continue; } /* * we can recover from total failures by unread()'ing * the entry we just read and then adding the new entry * to the binlog in the hopes that we'll get a * connection up and running again before it's time to * send more data to this node */ if (result <= 0) { if (!binlog_unread(node->binlog, temp_pkt, len)) { if (pkt) return node_binlog_add(node, pkt); return 0; } else { free(temp_pkt); } } /* * we wrote a partial event or failed to unread the event, * so this node is now out of sync. We must wipe the binlog * and possibly mark this node as being out of sync. */ lerr("Wiping binlog for %s node %s", node_type(node), node->name); binlog_wipe(node->binlog, BINLOG_UNLINK); if (pkt) { node->stats.events.dropped += node->stats.events.logged + 1; node->stats.bytes.dropped += node->stats.bytes.logged + packet_size(pkt); } node_log_event_count(node, 0); return -1; } return 0; }