static void cleanup_service(VSTREAM *src, char *unused_service, char **argv) { VSTRING *buf = vstring_alloc(100); CLEANUP_STATE *state; int flags; int type = 0; int status; /* * Sanity check. This service takes no command-line arguments. */ if (argv[0]) msg_fatal("unexpected command-line argument: %s", argv[0]); /* * Open a queue file and initialize state. */ state = cleanup_open(src); /* * Send the queue id to the client. Read client processing options. If we * can't read the client processing options we can pretty much forget * about the whole operation. */ attr_print(src, ATTR_FLAG_NONE, ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, state->queue_id, ATTR_TYPE_END); if (attr_scan(src, ATTR_FLAG_STRICT, ATTR_TYPE_INT, MAIL_ATTR_FLAGS, &flags, ATTR_TYPE_END) != 1) { state->errs |= CLEANUP_STAT_BAD; flags = 0; } cleanup_control(state, flags); /* * XXX Rely on the front-end programs to enforce record size limits. * * First, copy the envelope records to the queue file. Then, copy the * message content (headers and body). Finally, attach any information * extracted from message headers. */ while (CLEANUP_OUT_OK(state)) { if ((type = rec_get_raw(src, buf, 0, REC_FLAG_NONE)) < 0) { state->errs |= CLEANUP_STAT_BAD; break; } if (REC_GET_HIDDEN_TYPE(type)) { msg_warn("%s: record type %d not allowed - discarding this message", state->queue_id, type); state->errs |= CLEANUP_STAT_BAD; break; } CLEANUP_RECORD(state, type, vstring_str(buf), VSTRING_LEN(buf)); if (type == REC_TYPE_END) break; } /* * Keep reading in case of problems, until the sender is ready to receive * our status report. */ if (CLEANUP_OUT_OK(state) == 0 && type > 0) { while (type != REC_TYPE_END && (type = rec_get(src, buf, 0)) > 0) /* void */ ; } /* * Log something to make timeout errors easier to debug. */ if (vstream_ftimeout(src)) msg_warn("%s: read timeout on %s", state->queue_id, VSTREAM_PATH(src)); /* * Finish this message, and report the result status to the client. */ status = cleanup_flush(state); /* in case state is modified */ attr_print(src, ATTR_FLAG_NONE, ATTR_TYPE_INT, MAIL_ATTR_STATUS, status, ATTR_TYPE_STR, MAIL_ATTR_WHY, (state->flags & CLEANUP_FLAG_SMTP_REPLY) && state->smtp_reply ? state->smtp_reply : state->reason ? state->reason : "", ATTR_TYPE_END); cleanup_free(state); /* * Cleanup. */ vstring_free(buf); }
//----------------------------------------------------------------------------- // Main... process command line parameters, and then setup our listening // sockets and event loop. int main(int argc, char **argv) { rq_service_t *service; control_t *control = NULL; char *queue; ///============================================================================ /// Initialization. ///============================================================================ // create the 'control' object that will be passed to all the handlers so // that they have access to the information that they require. control = (control_t *) malloc(sizeof(control_t)); init_control(control); // create new service object. service = rq_svc_new(); control->rqsvc = service; // add the command-line options that are specific to this service. rq_svc_setname(service, PACKAGE " " VERSION); rq_svc_setoption(service, 'f', "filename", "blacklist .csv file."); rq_svc_setoption(service, 'q', "queue", "Queue to listen on for requests."); rq_svc_process_args(service, argc, argv); rq_svc_initdaemon(service); assert(control->evbase == NULL); control->evbase = event_base_new(); assert(control->evbase); rq_svc_setevbase(service, control->evbase); // initialise the risp system for processing what we receive on the queue. assert(control); assert(control->risp == NULL); control->risp = risp_init(NULL); assert(control->risp != NULL); risp_add_command(control->risp, BL_CMD_NOP, &cmdNop); risp_add_command(control->risp, BL_CMD_CLEAR, &cmdClear); risp_add_command(control->risp, BL_CMD_CHECK, &cmdCheck); risp_add_command(control->risp, BL_CMD_IP, &cmdIP); // initialise signal handlers. assert(control); assert(control->evbase); assert(control->sigint_event == NULL); control->sigint_event = evsignal_new(control->evbase, SIGINT, sigint_handler, control); assert(control->sigint_event); event_add(control->sigint_event, NULL); assert(control->sighup_event == NULL); control->sighup_event = evsignal_new(control->evbase, SIGHUP, sighup_handler, control); assert(control->sighup_event); event_add(control->sighup_event, NULL); // load the config file that we assume is supplied. assert(control->configfile == NULL); control->configfile = rq_svc_getoption(service, 'f'); if (control->configfile == NULL) { fprintf(stderr, "Configfile is required\n"); exit(EXIT_FAILURE); } else { if (config_load(control) < 0) { fprintf(stderr, "Errors loading config file: %s\n", control->configfile); exit(EXIT_FAILURE); } } // Tell the rq subsystem to connect to the rq servers. It gets its info // from the common paramaters that it expects. rq_svc_connect(service, NULL, NULL, NULL); // initialise the queue that we are consuming, provide callback handler. queue = rq_svc_getoption(service, 'q'); assert(queue); assert(service->rq); rq_consume(service->rq, queue, 200, RQ_PRIORITY_NORMAL, 0, message_handler, NULL, NULL, control); // we also want to make sure that when we lose the connection to the // controller, we indicate that we lost connection to the queue, unless we // have already established another controller connection. ///============================================================================ /// Main Event Loop. ///============================================================================ // enter the processing loop. This function will not return until there is // nothing more to do and the service has shutdown. Therefore everything // needs to be setup and running before this point. Once inside the // rq_process function, everything is initiated by the RQ event system. assert(control != NULL); assert(control->evbase); event_base_loop(control->evbase, 0); ///============================================================================ /// Shutdown ///============================================================================ assert(control); assert(control->evbase); event_base_free(control->evbase); control->evbase = NULL; // the rq service sub-system has no real way of knowing when the event-base // has been cleared, so we need to tell it. rq_svc_setevbase(service, NULL); control->rqsvc = NULL; // unload the config entries. assert(control); if (control->entries) { config_unload(control); } assert(control->entries == NULL); // make sure signal handlers have been cleared. assert(control); assert(control->sigint_event == NULL); assert(control->sighup_event == NULL); // cleanup risp library. assert(control); assert(control->risp); control->risp = risp_shutdown(control->risp); assert(control->risp == NULL); // we are done, cleanup what is left in the control structure. cleanup_control(control); free(control); rq_svc_cleanup(service); return 0; }