void tee_plugin(int pipe_fd, struct configuration *cfgptr, void *ptr) { struct pkt_msg *msg; unsigned char *pipebuf; struct pollfd pfd; int timeout, err; int ret, num, fd, pool_idx, recv_idx; struct ring *rg = &((struct channels_list_entry *)ptr)->rg; struct ch_status *status = ((struct channels_list_entry *)ptr)->status; u_int32_t bufsz = ((struct channels_list_entry *)ptr)->bufsize; char *dataptr, dest_addr[256], dest_serv[256]; struct tee_receiver *target = NULL; struct plugin_requests req; unsigned char *rgptr; int pollagain = TRUE; u_int32_t seq = 1, rg_err_count = 0; memcpy(&config, cfgptr, sizeof(struct configuration)); recollect_pipe_memory(ptr); pm_setproctitle("%s [%s]", "Tee Plugin", config.name); if (config.pidfile) write_pid_file_plugin(config.pidfile, config.type, config.name); if (config.logfile) { fclose(config.logfile_fd); config.logfile_fd = open_logfile(config.logfile, "a"); } if (config.proc_priority) { int ret; ret = setpriority(PRIO_PROCESS, 0, config.proc_priority); if (ret) Log(LOG_WARNING, "WARN ( %s/%s ): proc_priority failed (errno: %d)\n", config.name, config.type, errno); else Log(LOG_INFO, "INFO ( %s/%s ): proc_priority set to %d\n", config.name, config.type, getpriority(PRIO_PROCESS, 0)); } /* signal handling */ signal(SIGINT, Tee_exit_now); signal(SIGUSR1, SIG_IGN); signal(SIGUSR2, reload_maps); /* sets to true the reload_maps flag */ signal(SIGPIPE, SIG_IGN); signal(SIGCHLD, SIG_IGN); if (config.tee_transparent && getuid() != 0) { Log(LOG_ERR, "ERROR ( %s/%s ): Transparent mode requires super-user permissions. Exiting ...\n", config.name, config.type); exit_plugin(1); } if (config.nfprobe_receiver && config.tee_receivers) { Log(LOG_ERR, "ERROR ( %s/%s ): tee_receiver and tee_receivers are mutually exclusive. Exiting ...\n", config.name, config.type); exit_plugin(1); } else if (!config.nfprobe_receiver && !config.tee_receivers) { Log(LOG_ERR, "ERROR ( %s/%s ): No receivers specified: tee_receiver or tee_receivers is required. Exiting ...\n", config.name, config.type); exit_plugin(1); } memset(&receivers, 0, sizeof(receivers)); memset(&req, 0, sizeof(req)); reload_map = FALSE; /* Setting up pools */ if (!config.tee_max_receiver_pools) config.tee_max_receiver_pools = MAX_TEE_POOLS; receivers.pools = malloc((config.tee_max_receiver_pools+1)*sizeof(struct tee_receivers_pool)); if (!receivers.pools) { Log(LOG_ERR, "ERROR ( %s/%s ): unable to allocate receiver pools. Exiting ...\n", config.name, config.type); exit_plugin(1); } else memset(receivers.pools, 0, (config.tee_max_receiver_pools+1)*sizeof(struct tee_receivers_pool)); /* Setting up receivers per pool */ if (!config.tee_max_receivers) config.tee_max_receivers = MAX_TEE_RECEIVERS; for (pool_idx = 0; pool_idx < MAX_TEE_POOLS; pool_idx++) { receivers.pools[pool_idx].receivers = malloc(config.tee_max_receivers*sizeof(struct tee_receivers)); if (!receivers.pools[pool_idx].receivers) { Log(LOG_ERR, "ERROR ( %s/%s ): unable to allocate receivers for pool #%u. Exiting ...\n", config.name, config.type, pool_idx); exit_plugin(1); } else memset(receivers.pools[pool_idx].receivers, 0, config.tee_max_receivers*sizeof(struct tee_receivers)); } if (config.nfprobe_receiver) { pool_idx = 0; recv_idx = 0; target = &receivers.pools[pool_idx].receivers[recv_idx]; target->dest_len = sizeof(target->dest); if (Tee_parse_hostport(config.nfprobe_receiver, (struct sockaddr *) &target->dest, &target->dest_len)) { Log(LOG_ERR, "ERROR ( %s/%s ): Invalid receiver %s . ", config.name, config.type, config.nfprobe_receiver); exit_plugin(1); } else { recv_idx++; receivers.pools[pool_idx].num = recv_idx; pool_idx++; receivers.num = pool_idx; } } else if (config.tee_receivers) { int recvs_allocated = FALSE; req.key_value_table = (void *) &receivers; load_id_file(MAP_TEE_RECVS, config.tee_receivers, NULL, &req, &recvs_allocated); } config.sql_refresh_time = DEFAULT_TEE_REFRESH_TIME; timeout = config.sql_refresh_time*1000; pipebuf = (unsigned char *) Malloc(config.buffer_size); pfd.fd = pipe_fd; pfd.events = POLLIN; setnonblocking(pipe_fd); memset(pipebuf, 0, config.buffer_size); err_cant_bridge_af = 0; /* Arrange send socket */ Tee_init_socks(); /* plugin main loop */ for (;;) { poll_again: status->wakeup = TRUE; ret = poll(&pfd, 1, timeout); if (ret < 0) goto poll_again; if (reload_map) { int recvs_allocated = FALSE; Tee_destroy_recvs(); load_id_file(MAP_TEE_RECVS, config.tee_receivers, NULL, &req, &recvs_allocated); Tee_init_socks(); reload_map = FALSE; } switch (ret) { case 0: /* timeout */ /* reserved for future since we don't currently cache/batch/etc */ break; default: /* we received data */ read_data: if (!pollagain) { seq++; seq %= MAX_SEQNUM; if (seq == 0) rg_err_count = FALSE; } else { if ((ret = read(pipe_fd, &rgptr, sizeof(rgptr))) == 0) exit_plugin(1); /* we exit silently; something happened at the write end */ } if ((rg->ptr + bufsz) > rg->end) rg->ptr = rg->base; if (((struct ch_buf_hdr *)rg->ptr)->seq != seq) { if (!pollagain) { pollagain = TRUE; goto poll_again; } else { rg_err_count++; if (config.debug || (rg_err_count > MAX_RG_COUNT_ERR)) { Log(LOG_ERR, "ERROR ( %s/%s ): We are missing data.\n", config.name, config.type); Log(LOG_ERR, "If you see this message once in a while, discard it. Otherwise some solutions follow:\n"); Log(LOG_ERR, "- increase shared memory size, 'plugin_pipe_size'; now: '%u'.\n", config.pipe_size); Log(LOG_ERR, "- increase buffer size, 'plugin_buffer_size'; now: '%u'.\n", config.buffer_size); Log(LOG_ERR, "- increase system maximum socket size.\n\n"); } seq = ((struct ch_buf_hdr *)rg->ptr)->seq; } } pollagain = FALSE; memcpy(pipebuf, rg->ptr, bufsz); rg->ptr += bufsz; msg = (struct pkt_msg *) (pipebuf+sizeof(struct ch_buf_hdr)); Log(LOG_DEBUG, "DEBUG ( %s/%s ): buffer received seq=%u num_entries=%u\n", config.name, config.type, seq, ((struct ch_buf_hdr *)pipebuf)->num); while (((struct ch_buf_hdr *)pipebuf)->num > 0) { for (pool_idx = 0; pool_idx < receivers.num; pool_idx++) { if (!evaluate_tags(&receivers.pools[pool_idx].tag_filter, msg->tag)) { if (!receivers.pools[pool_idx].balance.func) { for (recv_idx = 0; recv_idx < receivers.pools[pool_idx].num; recv_idx++) { target = &receivers.pools[pool_idx].receivers[recv_idx]; Tee_send(msg, (struct sockaddr *) &target->dest, target->fd); } } else { target = receivers.pools[pool_idx].balance.func(&receivers.pools[pool_idx], msg); Tee_send(msg, (struct sockaddr *) &target->dest, target->fd); } } } ((struct ch_buf_hdr *)pipebuf)->num--; if (((struct ch_buf_hdr *)pipebuf)->num) { dataptr = (unsigned char *) msg; dataptr += PmsgSz; msg = (struct pkt_msg *) dataptr; } } goto read_data; } } }
void tee_plugin(int pipe_fd, struct configuration *cfgptr, void *ptr) { struct pkt_msg *msg; unsigned char *pipebuf; struct pollfd pfd; int timeout, err; int ret, num, fd; struct ring *rg = &((struct channels_list_entry *)ptr)->rg; struct ch_status *status = ((struct channels_list_entry *)ptr)->status; u_int32_t bufsz = ((struct channels_list_entry *)ptr)->bufsize; char *dataptr, dest_addr[256], dest_serv[256]; struct sockaddr dest; socklen_t dest_len; unsigned char *rgptr; int pollagain = TRUE; u_int32_t seq = 1, rg_err_count = 0; /* XXX: glue */ memcpy(&config, cfgptr, sizeof(struct configuration)); recollect_pipe_memory(ptr); pm_setproctitle("%s [%s]", "Tee Plugin", config.name); if (config.pidfile) write_pid_file_plugin(config.pidfile, config.type, config.name); /* signal handling */ signal(SIGINT, Tee_exit_now); signal(SIGUSR1, SIG_IGN); signal(SIGUSR2, SIG_IGN); signal(SIGPIPE, SIG_IGN); #if !defined FBSD4 signal(SIGCHLD, SIG_IGN); #else signal(SIGCHLD, ignore_falling_child); #endif if (config.tee_transparent && getuid() != 0) { Log(LOG_ERR, "ERROR ( %s/%s ): Transparent mode requires super-user permissions. Exiting ...\n", config.name, config.type); exit_plugin(1); } if (!config.nfprobe_receiver) { Log(LOG_ERR, "ERROR ( %s/%s ): tee_receiver is not specified. Exiting ...\n", config.name, config.type); exit_plugin(1); } memset(&dest, 0, sizeof(dest)); dest_len = sizeof(dest); Tee_parse_hostport(config.nfprobe_receiver, (struct sockaddr *)&dest, &dest_len); config.print_refresh_time = DEFAULT_TEE_REFRESH_TIME; timeout = config.print_refresh_time*1000; pipebuf = (unsigned char *) Malloc(config.buffer_size); pfd.fd = pipe_fd; pfd.events = POLLIN; setnonblocking(pipe_fd); memset(pipebuf, 0, config.buffer_size); /* Arrange send socket */ if (dest.sa_family != 0) { if ((err = getnameinfo((struct sockaddr *) &dest, dest_len, dest_addr, sizeof(dest_addr), dest_serv, sizeof(dest_serv), NI_NUMERICHOST)) == -1) { Log(LOG_ERR, "ERROR ( %s/%s ): getnameinfo: %d\n", config.name, config.type, err); exit_plugin(1); } fd = Tee_prepare_sock(&dest, dest_len); } /* plugin main loop */ for (;;) { poll_again: status->wakeup = TRUE; ret = poll(&pfd, 1, timeout); if (ret < 0) goto poll_again; switch (ret) { case 0: /* timeout */ /* reserved for future since we don't currently cache/batch/etc */ break; default: /* we received data */ read_data: if (!pollagain) { seq++; seq %= MAX_SEQNUM; if (seq == 0) rg_err_count = FALSE; } else { if ((ret = read(pipe_fd, &rgptr, sizeof(rgptr))) == 0) exit_plugin(1); /* we exit silently; something happened at the write end */ } if (((struct ch_buf_hdr *)rg->ptr)->seq != seq) { if (!pollagain) { pollagain = TRUE; goto poll_again; } else { rg_err_count++; if (config.debug || (rg_err_count > MAX_RG_COUNT_ERR)) { Log(LOG_ERR, "ERROR ( %s/%s ): We are missing data.\n", config.name, config.type); Log(LOG_ERR, "If you see this message once in a while, discard it. Otherwise some solutions follow:\n"); Log(LOG_ERR, "- increase shared memory size, 'plugin_pipe_size'; now: '%u'.\n", config.pipe_size); Log(LOG_ERR, "- increase buffer size, 'plugin_buffer_size'; now: '%u'.\n", config.buffer_size); Log(LOG_ERR, "- increase system maximum socket size.\n\n"); } seq = ((struct ch_buf_hdr *)rg->ptr)->seq; } } pollagain = FALSE; memcpy(pipebuf, rg->ptr, bufsz); if ((rg->ptr+bufsz) >= rg->end) rg->ptr = rg->base; else rg->ptr += bufsz; msg = (struct pkt_msg *) (pipebuf+sizeof(struct ch_buf_hdr)); while (((struct ch_buf_hdr *)pipebuf)->num) { Tee_send(msg, &dest, fd); ((struct ch_buf_hdr *)pipebuf)->num--; if (((struct ch_buf_hdr *)pipebuf)->num) { dataptr = (unsigned char *) msg; dataptr += PmsgSz; msg = (struct pkt_msg *) dataptr; } } goto read_data; } } }