/* * The following function sends a new window event, which consists * of fields "change" and "container", the latter containing a dump * of the window's container. * */ static void ipc_send_window_new_event(Con *con) { setlocale(LC_NUMERIC, "C"); yajl_gen gen = ygenalloc(); y(map_open); ystr("change"); ystr("new"); ystr("container"); dump_node(gen, con, false); y(map_close); const unsigned char *payload; ylength length; y(get_buf, &payload, &length); ipc_send_event("window", I3_IPC_EVENT_WINDOW, (const char *)payload); y(free); setlocale(LC_NUMERIC, ""); }
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; }
/* * Passes an event from a remote node to the broker module, * any and all nocs and the database handling routines. The * exception to this rule is control packets from peers and * pollers, which never get forwarded to our masters. */ static int handle_network_event(merlin_node *node, merlin_event *pkt) { uint i; if (pkt->hdr.type == CTRL_PACKET) { /* * if this is a CTRL_ALIVE packet from a remote module, we * must take care to stash the start-time here so we can * forward it to our module later. It only matters for * peers, but we might as well set it for all modules */ if (pkt->hdr.code == CTRL_ACTIVE) { int result = handle_ctrl_active(node, pkt); /* * If the CTRL_ACTIVE packet shows compatibility * problems, we ignore it and move on */ if (result < 0) { return 0; } /* * If the info is new, we run the confsync check * for the recently activated node */ if (!result) { ldebug("Module @ %s is ACTIVE", node->name); csync_node_active(node); } } if (pkt->hdr.code == CTRL_INACTIVE) { memset(&node->info, 0, sizeof(node->info)); ldebug("Module @ %s is INACTIVE", node->name); db_mark_node_inactive(node); } } else if (node->type == MODE_POLLER && num_masters) { ldebug("Passing on event from poller %s to %d masters", node->name, num_masters); net_sendto_many(noc_table, num_masters, pkt); } else if (node->type == MODE_MASTER && num_pollers) { /* * @todo maybe we should also check if self.peer_id == 0 * before we forward events to our pollers. Hmm... */ if (pkt->hdr.type != NEBCALLBACK_PROGRAM_STATUS_DATA && pkt->hdr.type != NEBCALLBACK_CONTACT_NOTIFICATION_METHOD_DATA) { for (i = 0; i < num_pollers; i++) { merlin_node *node = poller_table[i]; net_sendto(node, pkt); } } } /* * let the various handler know which node sent the packet */ pkt->hdr.selection = node->id; /* not all packets get delivered to the merlin module */ switch (pkt->hdr.type) { case NEBCALLBACK_PROGRAM_STATUS_DATA: case NEBCALLBACK_CONTACT_NOTIFICATION_METHOD_DATA: /* * PROGRAM_STATUS_DATA can't sanely be transferred * CONTACT_NOTIFICATION_METHOD is left as-is, since we by * default want pollers to send notifications for their * respective contacts. This is by customer request, since * sending text-messages across country borders is a lot * more expensive than just buying a GSM device extra for * where one wants to place the poller */ mrm_db_update(node, pkt); return 0; /* and not all packets get sent to the database */ case CTRL_PACKET: case NEBCALLBACK_EXTERNAL_COMMAND_DATA: return ipc_send_event(pkt); case NEBCALLBACK_DOWNTIME_DATA: case NEBCALLBACK_COMMENT_DATA: /* * These two used to be handled specially here, but * we've moved it to the database update layer instead, * which will discard queries it can't run properly * without bouncing the data against the module. */ default: /* * IMPORTANT NOTE: * It's absolutely vital that we send the event to the * ipc socket *before* we ship it off to the db_update * function, since the db_update function merlin_decode()'s * the event, which makes unusable for sending to the * ipc (or, indeed, anywhere else) afterwards. */ ipc_send_event(pkt); mrm_db_update(node, pkt); return 0; } return 0; }