void rq_blacklist_init(rq_blacklist_t *blacklist, rq_t *rq, const char *queue, int expires) { assert(blacklist); assert(rq); assert(queue); assert(expires > 0); blacklist->rq = rq; blacklist->queue = (char *) queue; blacklist->expires = expires; blacklist->cache = (list_t *) malloc(sizeof(list_t)); ll_init(blacklist->cache); blacklist->waiting = (list_t *) malloc(sizeof(list_t)); ll_init(blacklist->waiting); blacklist->risp = risp_init(); assert(blacklist->risp != NULL); risp_add_invalid(blacklist->risp, cmdInvalid); risp_add_command(blacklist->risp, BL_CMD_CLEAR, &cmdClear); risp_add_command(blacklist->risp, BL_CMD_ACCEPT, &cmdAccept); risp_add_command(blacklist->risp, BL_CMD_DENY, &cmdDeny); }
rq_http_t * rq_http_new (rq_t *rq, char *queue, void (*handler)(rq_http_req_t *req), void *arg) { rq_http_t *http; assert(rq); assert(queue); assert(handler); assert((arg && handler) || (arg == NULL)); // create http object. http = malloc(sizeof(*http)); http->rq = rq; http->queue = strdup(queue); assert(strlen(queue) < 256); http->handler = handler; http->arg = arg; http->req_list = ll_init(NULL); assert(http->req_list); http->safe_buffer = NULL; http->safe_len = 0; // create RISP object http->risp = risp_init(NULL); assert(http->risp); risp_add_command(http->risp, HTTP_CMD_CLEAR, &cmdClear); risp_add_command(http->risp, HTTP_CMD_EXECUTE, &cmdExecute); risp_add_command(http->risp, HTTP_CMD_METHOD_GET, &cmdMethodGet); risp_add_command(http->risp, HTTP_CMD_METHOD_POST, &cmdMethodPost); risp_add_command(http->risp, HTTP_CMD_METHOD_HEAD, &cmdMethodHead); risp_add_command(http->risp, HTTP_CMD_HOST, &cmdHost); risp_add_command(http->risp, HTTP_CMD_PATH, &cmdPath); risp_add_command(http->risp, HTTP_CMD_PARAMS, &cmdParams); risp_add_command(http->risp, HTTP_CMD_CODE, &cmdCode); // risp_add_command(http->risp, HTTP_CMD_SET_HEADER, &cmdHeader); // risp_add_command(http->risp, HTTP_CMD_LENGTH, &cmdLength); // risp_add_command(http->risp, HTTP_CMD_REMOTE_HOST, &cmdRemoteHost); // risp_add_command(http->risp, HTTP_CMD_LANGUAGE, &cmdLanguage); // risp_add_command(http->risp, HTTP_CMD_FILE, &cmdParams); // risp_add_command(http->risp, HTTP_CMD_KEY, &cmdKey); // risp_add_command(http->risp, HTTP_CMD_VALUE, &cmdValue); // risp_add_command(http->risp, HTTP_CMD_FILENAME, &cmdFilename); rq_consume(rq, http->queue, 200, RQ_PRIORITY_NORMAL, 0, message_handler, NULL, NULL, http); return(http); }
int main(int argc, char **argv) { // parameters that are provided. char *srv = "127.0.0.1"; int port = DEFAULT_PORT; char *cafile = NULL; char *certfile = NULL; char *keyfile = NULL; data_t data; data.stream = NULL; data.session = NULL; data.name = NULL; data.message = NULL; int c; while ((c = getopt(argc, argv, "s:" /* server hostname or ip */ "p:" /* port to connect to */ "a:" /* CA file */ "c:" /* Certificate Chain */ "k:" /* Private Key file */ "n:" /* name of the message sender */ "m:" /* message to send */ "h" /* command usage */ )) != -1) { switch (c) { case 'p': port = atoi(optarg); assert(port > 0); break; case 's': srv = strdup(optarg); assert(srv); break; case 'a': assert(cafile == NULL); cafile = optarg; assert(cafile); break; case 'c': assert(certfile == NULL); certfile = optarg; assert(certfile); break; case 'k': assert(keyfile == NULL); keyfile = optarg; assert(keyfile); break; case 'n': data.name = strdup(optarg); assert(data.name); break; case 'm': data.message = strdup(optarg); assert(data.message); break; case 'h': printf("Usage: ./risp_chat_send -s [server] -p [port] -n \"name of sender\" -m \"Message\"\n\n"); exit(1); break; default: fprintf(stderr, "Illegal argument \"%c\"\n", c); return 1; } } // get an initialised risp structure. RISP risp = risp_init(); assert(risp); // add the callback routines for the commands we are going to receive. risp_add_command(risp, CMD_NOP, cmdNop); risp_add_command(risp, CMD_HELLO_ACK, cmdHelloAck); // add a handler to let us know if we receive a command we aren't expecting. risp_add_invalid(risp, &cmdInvalid); // initialise the RISP stream library. This will also initialise libevent (which we verify with an assert). data.stream = rispstream_init(NULL); assert(data.stream); struct event_base *evbase = rispstream_get_eventbase(data.stream); assert(evbase); // Attach our RISP handlers to the stream. rispstream_attach_risp(data.stream, risp); // The stream can use the event system to trap signals, so we will use that. rispstream_break_on_signal(data.stream, SIGINT, break_cb); // if the keys are encrypted, they will need the passphrase. Set a callback routine to Ask the user for this password. if (keyfile) { rispstream_set_passphrase_callback(data.stream, passphrase_cb); } // if the user has specified to use certificates, then they needed to be loaded into the // rispstream instance. Once certificates are applied, all client connections must also // be secure. if (certfile && keyfile) { fprintf(stderr, "Loading Certificate and Private Keys\n"); int result = rispstream_add_client_certs(data.stream, cafile, certfile, keyfile); if (result != 0) { fprintf(stderr, "Unable to load Certificate and Private Key files.\n"); exit(1); } assert(result == 0); printf("Certificate files loaded.\n"); } // Initiate a connection. Note that it will only QUEUE the request, and will not actually attempt // the connection until the stream is being processed (rispstream_process). assert(srv); assert(port > 0); rispstream_connect(data.stream, srv, port, &data, connect_cb, close_cb); // this function will process the stream (assuming the connection succeeds). // When there are no more events, it will exit. // When the socket closes, this function should exit. rispstream_process(data.stream); fprintf(stderr, "FINISHED. SHUTTING DOWN\n"); // Not really needed, but good to do it out of habbit before actually cleaning up the risp object itself. rispstream_detach_risp(data.stream); // since the connect has completed, it either failed to do anything, or it connected, processing completed, // and the socket was closed. So now we shutdown the stream. rispstream_shutdown(data.stream); // clean up the risp structure. risp_shutdown(risp); risp = NULL; return 0; }
int main(int argc, char **argv) { int c; risp_t *risp; int sent; char *srv = "127.0.0.1"; char *filename = NULL; int port = DEFAULT_PORT; int avail; int processed; int len; int done = 0, t; node_t node; // initialise the node data. node.handle = INVALID_HANDLE; node.verbose = 0; node.finished = 0; expbuf_init(&node.in, 1024); expbuf_init(&node.out, 1024); expbuf_init(&node.data.file, 0); expbuf_init(&node.data.data, 0); node.data.op = CMD_NOP; node.data.size = 0; node.data.offset = 0; node.filehandle = INVALID_HANDLE; node.size = 0; node.offset = 0; while ((c = getopt(argc, argv, "f:p:s:v")) != -1) { switch (c) { case 'f': filename = optarg; assert(filename != NULL); break; case 'p': port = atoi(optarg); assert(port > 0); break; case 's': srv = optarg; assert(srv != NULL); break; case 'v': node.verbose ++; break; default: fprintf(stderr, "Illegal argument \"%c\"\n", c); return 1; } } if (filename == NULL) { fprintf(stderr, "Need a filename.\n\n"); exit(1); } // get an initialised risp structure. risp = risp_init(); if (risp == NULL) { printf("Unable to initialise RISP library.\n"); } else { risp_add_command(risp, CMD_CLEAR, &cmdClear); risp_add_command(risp, CMD_EXECUTE, &cmdExecute); risp_add_command(risp, CMD_OFFSET, &cmdOffset); risp_add_command(risp, CMD_SIZE, &cmdSize); risp_add_command(risp, CMD_FILE, &cmdFile); risp_add_command(risp, CMD_DATA, &cmdData); risp_add_command(risp, CMD_PUT, &cmdPut); risp_add_command(risp, CMD_GET, &cmdGet); len = strlen(filename); assert(len < 256); assert(node.out.length == 0); addCmd(&node.out, CMD_CLEAR); addCmd(&node.out, CMD_GET); addCmdShortStr(&node.out, CMD_FILE, len, filename); addCmd(&node.out, CMD_EXECUTE); // and process it a lot of time. printf("Sending request for: %s\n", filename); // connect to the remote socket. node.handle = sock_connect(srv, port); if (node.handle <= 0) { printf("Unable to connect to %s:%d\n", srv, port); } else { while (sigtrap == 0 && node.finished == 0) { // continue to send data to the socket over and over as quickly as possible. while (node.out.length > 0) { assert(node.handle > 0); sent = sock_send(node.handle, node.out.data, node.out.length); if (sent < 0) { sigtrap ++; } else { assert(sent > 0); assert(sent <= node.out.length); if (sent == node.out.length) { expbuf_clear(&node.out); } else { expbuf_purge(&node.out, sent); } } } // if we didn't generate a fail during the write, then we do a read. if (sigtrap == 0) { avail = node.in.max - node.in.length; if (avail < 1024) { expbuf_shrink(&node.in, 1024); avail = 1024; } sent = sock_receive(node.handle, node.in.data + node.in.length, avail); if (sent < 0) { sigtrap ++; } else { assert(sent > 0); node.in.length += sent; assert(node.in.length <= node.in.max); if (sent == avail) { // we filled the incoming buffer, so we need to double it. expbuf_shrink(&node.in, node.in.max * 2); } processed = risp_process(risp, &node, node.in.length, (unsigned char *) node.in.data); // printf("Processed %d.\n", processed); if (processed > 0) { expbuf_purge(&node.in, processed); if (node.offset > 0 && node.size > 0) { t = (node.offset / (node.size/100)); if (t > done) { done = t; printf("Done - %c%d\n", '%', done); } } } } } } // close the socket. if (node.handle >= 0) { close(node.handle); } } // clean up the risp structure. risp_shutdown(risp); } return 0; }
int main(int argc, char **argv) { // parameters that are provided. char *srv = "127.0.0.1"; int port = DEFAULT_PORT; // this data object will be passed to all the callback routines. Initialise it. data_t data; data.handle = -1; data.msg_id = 0; data.latest_msg_id = 0; data.name = NULL; // get the command line options. int c; while ((c = getopt(argc, argv, "p:s:h")) != -1) { switch (c) { case 'p': port = atoi(optarg); assert(port > 0); break; case 's': srv = strdup(optarg); assert(srv != NULL); break; case 'h': printf("usage:\n\nrisp_chat_stream2 [-s server] [-p port] [-h]\n"); exit(1); break; default: fprintf(stderr, "Illegal argument \"%c\"\n", c); return 1; } } // set the signal trap, so we can break out of the loop when user presses Ctrl-C. signal(SIGINT, sig_handler); // get an initialised risp structure. RISP_PTR risp = risp_init(); assert(risp); // add the callback routines for the commands we are going to receive. risp_add_command(risp, CMD_NOP, &cmdNop); risp_add_command(risp, CMD_HELLO_ACK, &cmdHelloAck); risp_add_command(risp, CMD_MSG_ID, &cmdMsgID); risp_add_command(risp, CMD_LATEST_MSG_ID, &cmdLatestMsgID); risp_add_command(risp, CMD_NAME, &cmdName); risp_add_command(risp, CMD_MESSAGE, &cmdMessage); risp_add_invalid(risp, &cmdInvalid); // connect to the remote socket. We will leave it in blocking mode. When we do the recv, we // will specify that the recv operation is non-blocking. assert(srv && port > 0); data.handle = sock_connect(srv, port); if (data.handle <= 0) { printf("Unable to connect to %s:%d\n", srv, port); } else { // now that we are connected, first we need to send the HELLO and NO_FOLLOW commands. // These commands could have been lumped together in a single send, but for the purpose of // demonstrating RISP, this code does each operationg specifically. if (sendInit(data.handle) != 0) { // couldn't send the command, close the handle, and exit. close(data.handle); data.handle = -1; } // setup the initial buffer. Since we dont really know how much data we will receive from // the server, we will grow the buffer as needed. int max = 0; char *buffer = NULL; int used = 0; int goodbye_sent = 0; // if we have sent a GOODBYE, we dont want to // we will loop until the socket is closed. If the user presses Ctrl-C, we will send a // GOODBYE command to the server, which will then close the socket. If the user presses // Ctrl-C more than once, we will not wait for the server, and will close the socket // directly. Every time the user presses Ctrl-C, it should break out of the sleep, so it // should respond pretty quickly. while (data.handle >= 0) { // printf("."); assert(used <= max); if (max-used < CHUNK_SIZE) { max += CHUNK_SIZE; buffer = realloc(buffer, max); assert(buffer); // fprintf(stderr, "Increased Max Buffer to %d\n", max); } // check for data on the socket. We will do the receive in non-blocking mode, so if // there is no data, it will return immediately. If we received no data, we will wait for // 1 second before trying again. If we have waited for 5 seconds, then we need to // send a NOP to keep the connection alive. char *ptr = buffer + used; int avail = max - used; // fprintf(stderr, "About to recv. avail=%d\n", avail); int result = recv(data.handle, ptr, avail, MSG_DONTWAIT); // printf("Recv: result=%d, used=%d, max=%d\n", result, used, max); if (result < 0) { assert(result == -1); if (errno == EWOULDBLOCK || errno == EAGAIN) { // there was no data to read from the socket. // we will now sleep for 1 second. If the user pressed Ctrl-C, then the sleep // function will exit immediately. Only do the sleep if Ctrl-C hasn't been hit. if (_sigtrap == 0) { sleep(1); } } else { fprintf(stderr, "Unexpected result received from socket. errno=%d '%s'\n", errno, strerror(errno)); } } else if (result == 0) { // socket has closed. close(data.handle); data.handle = -1; } else { assert(result > 0); assert(result <= avail); assert(used >= 0); used += result; assert(used <= max); // if we have some data received, then we need to process it. // fprintf(stderr, "Processing: %d\n", used); risp_length_t processed = risp_process(risp, &data, used, buffer); // fprintf(stderr, "Processed: %ld\n", processed); assert(processed >= 0); assert(processed <= used); if (processed < used) { // Our commands have probably been fragmented. // fprintf(stderr, "Fragmented commands: processed=%ld, used=%d, max=%d\n", processed, used, max); fflush(stdout); if (processed > 0) { // we need to remove from the buffer the data that we have processed. // This is a simple approach, but not the most efficient. assert(sizeof(*buffer) == 1); char *ptr = buffer+processed; size_t length = used-processed; assert((processed + length) == used); // fprintf(stderr, "Moving data. length=%ld\n", length); memmove(buffer, ptr, length); used -= processed; assert(used > 0); assert(used < max); // fprintf(stderr, "After move. used=%d, max=%d\n", used, max); } } else { used = 0; } assert(used >= 0 && used <= max); } if (data.handle >= 0) { if (_sigtrap == 1 && goodbye_sent == 0) { fprintf(stderr, "Closing...\n"); // TODO: shouldn't just close the socket. Should instead send GOODBYE command and wait for socket to close. if (sendGoodbye(data.handle) != 0) { close(data.handle); data.handle = -1; } goodbye_sent ++; } else if (_sigtrap > 1) { close(data.handle); data.handle = -1; } } } } // clean up the risp structure. risp_shutdown(risp); risp = NULL; return 0; }
//----------------------------------------------------------------------------- // 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; }
//----------------------------------------------------------------------------- // Main... process command line parameters, and then setup our listening // sockets and event loop. int main(int argc, char **argv) { char *interface = "0.0.0.0"; char *cafile = NULL; char *certfile = NULL; char *keyfile = NULL; char *userfile = NULL; int port = DEFAULT_PORT; bool verbose = false; // set stderr non-buffering (for running under, say, daemontools) setbuf(stderr, NULL); while (1) { int option_index = 0; static struct option long_options[] = { {"interface", required_argument, 0, 'l' }, {"port", required_argument, 0, 'p' }, {"client-ca", required_argument, 0, 'c' }, {"cert", required_argument, 0, 's' }, {"key", required_argument, 0, 'k' }, {"userfile", required_argument, 0, 'u' }, {"help", no_argument, 0, 'h' }, {"verbose", no_argument, 0, 'v' }, {0, 0, 0, 0 } }; int c = getopt_long(argc, argv, "l:" /* listening interface (IP) */ "p:" /* port to listen on */ "c:" /* Client Certificate Chain */ "s:" /* Server Certificate */ "k:" /* Private Key file for Server Certificate */ "u:" /* Userfile for authentication */ "h" /* help... show usage info */ "v" /* verbosity */ , long_options, &option_index); if (c == -1) break; switch (c) { case 0: fprintf(stderr, "Unknown option %s", long_options[option_index].name); if (optarg) { fprintf(stderr, " with arg %s", optarg); } printf("\n"); break; case 'h': usage(); exit(EXIT_SUCCESS); case 'v': verbose++; break; case 'p': assert(optarg); port = atoi(optarg); assert(port > 0); break; case 'l': interface = optarg; assert(interface); break; case 'c': assert(cafile == NULL); cafile = optarg; assert(cafile); break; case 's': assert(certfile == NULL); certfile = optarg; assert(certfile); break; case 'k': assert(keyfile == NULL); keyfile = optarg; assert(keyfile); break; case 'u': assert(userfile == NULL); userfile = optarg; assert(userfile); break; default: fprintf(stderr, "Illegal argument \"%c\"\n", c); return 1; } } if (verbose > 1) { fprintf(stderr, "Interface: %s\n", interface); } if (verbose > 1) { fprintf(stderr, "Listening Port: %d\n", port); } if (verbose > 1) { fprintf(stderr, "CA File: %s\n", cafile); } if (verbose > 1) { fprintf(stderr, "Cert File: %s\n", certfile); } if (verbose > 1) { fprintf(stderr, "Key File: %s\n", keyfile); } if (verbose) fprintf(stderr, "Finished processing command-line args\n"); // initialise the rispstream. We dont pass any parameters in, we build up functionality after. RISPSTREAM stream = rispstream_init(NULL); assert(stream); // Initialise the risp system. RISP risp = risp_init(); assert(risp); risp_add_invalid(risp, cmdInvalid); risp_add_command(risp, CMD_NOP, &cmdNop); risp_add_command(risp, CMD_HELLO, &cmdHello); risp_add_command(risp, CMD_GOODBYE, &cmdGoodbye); risp_add_command(risp, CMD_ECHO, &cmdEcho); risp_add_command(risp, CMD_NOECHO, &cmdNoEcho); risp_add_command(risp, CMD_FOLLOW, &cmdFollow); risp_add_command(risp, CMD_NOFOLLOW, &cmdNoFollow); risp_add_command(risp, CMD_NOUPDATE, &cmdNoUpdate); risp_add_command(risp, CMD_GET_LATEST_MDG_ID, &cmdGetLatestMsgID); risp_add_command(risp, CMD_SEND_MSG, &cmdSendMsg); risp_add_command(risp, CMD_SEND_SINCE, &cmdSendSince); risp_add_command(risp, CMD_NAME, &cmdName); risp_add_command(risp, CMD_MESSAGE, &cmdMessage); // there are some commands that are illegal to be received from the client. // If we receive them, then we should close the session risp_add_command(risp, CMD_HELLO_ACK, &cmdIllegal); risp_add_command(risp, CMD_MSG_ID, &cmdIllegal); risp_add_command(risp, CMD_LATEST_MSG_ID, &cmdIllegal); // attach our RISP object (which has all the commands added) to the stream. // It will use this object to decode the stream of data as it arrives. assert(stream && risp); rispstream_attach_risp(stream, risp); // create the object that will be tracking the sessions and the data that needs to flow // between them, and let the stream sub-system know. maindata_t *data = maindata_init(); assert(data); rispstream_set_userdata(stream, data); // if the user specified a userfile, it will load the contents into the maindata structure. This will be used to validate client connections. if (userfile) { load_userfile(userfile, data); assert(data->users); if (verbose > 0) { int u=0; while (data->users[u]) { fprintf(stderr, "User: '******'\n", data->users[u]); u++; } } } else { assert(data->users == NULL); } // if the user has specified to use certificates, then they needed to be loaded into the // rispstream instance. Once certificates are applied, all client connections must also // be secure. if (cafile && certfile && keyfile) { if (verbose > 1) { fprintf(stderr, "Loading CA, Certificate and Private Keys\n"); } int result = rispstream_add_server_certs(stream, cafile, certfile, keyfile); if (result != 0) { fprintf(stderr, "Unable to load Certificate and Private Key files.\n"); exit(1); } assert(result == 0); assert(stream); assert(cafile); rispstream_require_client_certs(stream, cafile); if (verbose) { fprintf(stderr, "Certificate files loaded.\n"); } } // When the user presses Ctrl-C, we want the service to exit (cleanly). // We can tell rispstream to handle that (since the stream will be handling libevent). // When a user presses Ctrl-C, rispstream will detect, and will execute a callback routine. // In this case, our callback routine is break_cb(). assert(stream); rispstream_break_on_signal(stream, SIGINT, break_cb); // Now we want to tell rispstream to listen on a socket for new connections. // When a new connection comes in, a callback function is called. // The callback function will return with a pointer to a base data object. // That object will be passed to the risp callback routines when commands are received. // It essentially allows you to have some data specific to that session. assert(stream); rispstream_listen(stream, interface, port, newconn_cb, connclosed_cb); // Now that the listen socket and event is created, we need to process the streams that result. // This function will continue to run until one of the callbacks tells rispstream to shutdown. // This is a blocking function. rispstream_process(stream); //-------- // Shutting Down. // When the above function exits, it means we are shutting down. // Since rispstream did not create the risp object, we should detach it, to make it clear that risp is being cleaned up elsewhere. // If it was still attached when rispstream_shutdown() is called, it will generate an assert. rispstream_detach_risp(stream); // shutdown rispstream.. it should be fairly empty and idle at this point though. rispstream_shutdown(stream); stream = NULL; // cleanup risp library. assert(risp); risp_shutdown(risp); risp = NULL; if (verbose) fprintf(stderr, "\n\nExiting.\n"); return 0; }
static void timeout_handler(const int fd, const short which, void *arg) { struct timeval t = {.tv_sec = 1, .tv_usec = 0}; timeout_t *ptr; unsigned int inmem, outmem, filemem; int i; ptr = (timeout_t *) arg; assert(ptr != NULL); assert(ptr->clockevent.ev_base != NULL); // reset the timer to go off again in 1 second. evtimer_del(&ptr->clockevent); evtimer_set(&ptr->clockevent, timeout_handler, arg); event_base_set(ptr->clockevent.ev_base, &ptr->clockevent); evtimer_add(&ptr->clockevent, &t); assert(fd == INVALID_HANDLE); assert(ptr->server != NULL); assert(ptr->stats != NULL); if (ptr->stats->in_bytes || ptr->stats->out_bytes || ptr->stats->commands || ptr->stats->operations) { inmem=0; outmem=0; filemem = 0; for(i=0; i<ptr->server->maxconns; i++) { if (ptr->server->nodes[i] != NULL) { inmem += ptr->server->nodes[i]->in.length; outmem += ptr->server->nodes[i]->out.length; filemem += ptr->server->nodes[i]->filebuf.length; } } if (inmem > 0) { inmem /= 1024; } if (outmem > 0) { outmem /= 1024; } if (filemem > 0) { filemem /= 1024; } printf("Bytes [%u/%u], Commands [%u], Operations[%u], Mem[%uk/%uk/%uk], Cycles[%u], Undone[%u], RW[%u/%u]\n", ptr->stats->in_bytes, ptr->stats->out_bytes, ptr->stats->commands, ptr->stats->operations, inmem, outmem, filemem, ptr->stats->cycles, ptr->stats->undone, ptr->stats->reads, ptr->stats->writes); ptr->stats->in_bytes = 0; ptr->stats->out_bytes = 0; ptr->stats->commands = 0; ptr->stats->operations = 0; ptr->stats->cycles = 0; ptr->stats->undone = 0; ptr->stats->reads = 0; ptr->stats->writes = 0; } } void timeout_init(timeout_t *ptr, struct event_base *base) { struct timeval t = {.tv_sec = 1, .tv_usec = 0}; assert(ptr != NULL); assert(ptr->clockevent.ev_base == NULL); evtimer_set(&ptr->clockevent, timeout_handler, (void *) ptr); event_base_set(ptr->clockevent.ev_base, &ptr->clockevent); evtimer_add(&ptr->clockevent, &t); assert(ptr->clockevent.ev_base != NULL); } //----------------------------------------------------------------------------- // Main... process command line parameters, and then setup our listening // sockets and event loop. int main(int argc, char **argv) { int c; settings_t *settings = NULL; server_t *server = NULL; timeout_t *timeout = NULL; stats_t *stats = NULL; risp_t *risp = NULL; // handle SIGINT signal(SIGINT, sig_handler); // init settings settings = (settings_t *) malloc(sizeof(settings_t)); assert(settings != NULL); settings_init(settings); // set stderr non-buffering (for running under, say, daemontools) setbuf(stderr, NULL); // process arguments /// Need to check the options in here, there're possibly ones that we dont need. while ((c = getopt(argc, argv, "p:k:c:hvd:u:P:l:s:")) != -1) { switch (c) { case 'p': settings->port = atoi(optarg); assert(settings->port > 0); break; case 'c': settings->maxconns = atoi(optarg); assert(settings->maxconns > 0); break; case 'h': usage(); exit(EXIT_SUCCESS); case 'v': settings->verbose++; break; case 'd': assert(settings->daemonize == false); settings->daemonize = true; break; case 's': assert(settings->storepath == NULL); settings->storepath = optarg; assert(settings->storepath != NULL); assert(settings->storepath[0] != '\0'); break; case 'u': assert(settings->username == NULL); settings->username = optarg; assert(settings->username != NULL); assert(settings->username[0] != '\0'); break; case 'P': assert(settings->pid_file == NULL); settings->pid_file = optarg; assert(settings->pid_file != NULL); assert(settings->pid_file[0] != '\0'); break; case 'l': assert(settings->interface == NULL); settings->interface = strdup(optarg); assert(settings->interface != NULL); assert(settings->interface[0] != '\0'); break; default: fprintf(stderr, "Illegal argument \"%c\"\n", c); return 1; } } if (settings->verbose) printf("Finished processing command-line args\n"); // If needed, increase rlimits to allow as many connections as needed. if (settings->verbose) printf("Settings Max connections: %d\n", settings->maxconns); assert(settings->maxconns > 0); set_maxconns(settings->maxconns); // if we are supplied with a username, drop privs to it. This will only // work if we are running as root, and is really only needed when running as // a daemon. if (settings->username != NULL) { if (settings->verbose) printf("Dropping privs and changing username: '******'\n", settings->username); if (drop_privs(settings->username) != 0) { usage(); exit(EXIT_FAILURE); } } // daemonize if requested // if we want to ensure our ability to dump core, don't chdir to / if (settings->daemonize) { int res; if (settings->verbose) printf("Daemonising\n"); res = daemon(0, settings->verbose); if (res == -1) { fprintf(stderr, "failed to daemon() in order to daemonize\n"); exit(EXIT_FAILURE); } } // initialize main thread libevent instance if (settings->verbose) printf("Initialising the event system.\n"); main_event_base = event_init(); if (settings->verbose) printf("Ignoring SIGPIPE interrupts\n"); ignore_sigpipe(); // save the PID in if we're a daemon, do this after thread_init due to a // file descriptor handling bug somewhere in libevent if (settings->daemonize && settings->pid_file) { if (settings->verbose) printf("Saving Pid file: %s\n", settings->pid_file); save_pid(getpid(), settings->pid_file); } // create and init the 'server' structure. if (settings->verbose) printf("Starting server listener on port %d.\n", settings->port); server = server_new(settings->port, settings->maxconns, settings->interface); if (server == NULL) { fprintf(stderr, "Failed to listen on port %d\n", settings->port); exit(EXIT_FAILURE); } assert(server != NULL); server->verbose = settings->verbose; server->storepath = settings->storepath; // add the server to the event base assert(main_event_base != NULL); server_add_event(server, main_event_base); // initialise clock event. The clock event is used to keep up our node // network. If we dont have enough connections, we will need to make some // requests. // create the timeout structure, and the timeout event. This is used to // perform certain things spread over time. Such as indexing the // 'complete' paths that we have, and ensuring that the 'chunks' parts are // valid. if (settings->verbose) printf("Setting up Timeout event.\n"); timeout = (timeout_t *) malloc(sizeof(timeout_t)); assert(timeout != NULL); assert(main_event_base != NULL); if (settings->verbose) printf("Initialising timeout.\n"); timeout_init(timeout, main_event_base); timeout->server = server; stats = (stats_t *) malloc(sizeof(stats_t)); stats->out_bytes = 0; stats->in_bytes = 0; stats->commands = 0; stats->operations = 0; server->stats = stats; timeout->stats = stats; // Initialise the risp system. risp = risp_init(); assert(risp != NULL); risp_add_invalid(risp, cmdInvalid); risp_add_command(risp, CMD_CLEAR, &cmdClear); risp_add_command(risp, CMD_EXECUTE, &cmdExecute); risp_add_command(risp, CMD_LIST, &cmdList); risp_add_command(risp, CMD_LISTING, &cmdListing); risp_add_command(risp, CMD_LISTING_DONE, &cmdListingDone); risp_add_command(risp, CMD_PUT, &cmdPut); risp_add_command(risp, CMD_GET, &cmdGet); risp_add_command(risp, CMD_SIZE, &cmdSize); risp_add_command(risp, CMD_OFFSET, &cmdOffset); risp_add_command(risp, CMD_FILE, &cmdFile); risp_add_command(risp, CMD_DATA, &cmdData); assert(server->risp == NULL); server->risp = risp; // enter the event loop. if (settings->verbose) printf("Starting Event Loop\n\n"); event_base_loop(main_event_base, 0); // cleanup risp library. risp_shutdown(risp); risp = NULL; // cleanup 'server', which should cleanup all the 'nodes' if (settings->verbose) printf("\n\nExiting.\n"); // remove the PID file if we're a daemon if (settings->daemonize && settings->pid_file != NULL) { if (settings->verbose) printf("Removing pid file: %s\n", settings->pid_file); remove_pidfile(settings->pid_file); } assert(settings != NULL); settings_cleanup(settings); settings = NULL; return 0; }
void command_init(risp_t *risp) { assert(risp); risp_add_command(risp, RQ_CMD_CLEAR, &cmdClear); risp_add_command(risp, RQ_CMD_PING, &cmdPing); risp_add_command(risp, RQ_CMD_PONG, &cmdPong); risp_add_command(risp, RQ_CMD_REQUEST, &cmdRequest); risp_add_command(risp, RQ_CMD_REPLY, &cmdReply); risp_add_command(risp, RQ_CMD_DELIVERED, &cmdDelivered); risp_add_command(risp, RQ_CMD_BROADCAST, &cmdBroadcast); risp_add_command(risp, RQ_CMD_NOREPLY, &cmdNoReply); risp_add_command(risp, RQ_CMD_CONSUME, &cmdConsume); risp_add_command(risp, RQ_CMD_CANCEL_QUEUE, &cmdCancelQueue); risp_add_command(risp, RQ_CMD_CONSUMING, &cmdConsuming); risp_add_command(risp, RQ_CMD_CLOSING, &cmdClosing); risp_add_command(risp, RQ_CMD_EXCLUSIVE, &cmdExclusive); risp_add_command(risp, RQ_CMD_QUEUEID, &cmdQueueID); risp_add_command(risp, RQ_CMD_ID, &cmdId); risp_add_command(risp, RQ_CMD_TIMEOUT, &cmdTimeout); risp_add_command(risp, RQ_CMD_MAX, &cmdMax); risp_add_command(risp, RQ_CMD_PRIORITY, &cmdPriority); risp_add_command(risp, RQ_CMD_QUEUE, &cmdQueue); risp_add_command(risp, RQ_CMD_PAYLOAD, &cmdPayload); }
//----------------------------------------------------------------------------- // Main... process command line parameters, and if we have enough information, then create an empty stash. int main(int argc, char **argv) { int c; master_t master; storage_t *storage; const char *filename = NULL; assert(argc >= 0); assert(argv); // initialise the master structure that we will be passing through the risp process. master.risp_top = NULL; master.risp_op = NULL; master.risp_payload = NULL; master.risp_data = NULL; // process arguments /// Need to check the options in here, there're possibly ones that we dont need. while ((c = getopt(argc, argv, "hvf:")) != -1) { switch (c) { case 'h': usage(); exit(EXIT_SUCCESS); case 'v': verbose++; break; case 'f': filename = optarg; break; default: fprintf(stderr, "Illegal argument \"%c\"\n", c); exit(1); } } // check that our required params are there: if (filename == NULL) { fprintf(stderr, "requires: -f <filename>\n"); exit(1); } // create the top-level risp interface. master.risp_top = risp_init(NULL); assert(master.risp_top != NULL); risp_add_command(master.risp_top, STASH_CMD_CLEAR, &cmdClear); risp_add_command(master.risp_top, STASH_CMD_FILE_SEQ, &cmdFileSeq); risp_add_command(master.risp_top, STASH_CMD_OPERATION, &cmdOperation); risp_add_command(master.risp_top, STASH_CMD_NEXT_VOLUME, &cmdNextVolume); master.risp_op = risp_init(NULL); assert(master.risp_op); master.risp_payload = risp_init(NULL); assert(master.risp_payload); risp_add_command(master.risp_payload, STASH_CMD_CREATE_USER, &cmdCreateUser); risp_add_command(master.risp_payload, STASH_CMD_CREATE_NAMESPACE, &cmdCreateNamespace); risp_add_command(master.risp_payload, STASH_CMD_SET_PASSWORD, &cmdSetPassword); risp_add_command(master.risp_payload, STASH_CMD_GRANT, &cmdGrant); risp_add_command(master.risp_payload, STASH_CMD_CREATE_TABLE, &cmdCreateTable); risp_add_command(master.risp_payload, STASH_CMD_CREATE_KEY, &cmdCreateKey); risp_add_command(master.risp_payload, STASH_CMD_CREATE_NAME, &cmdCreateName); risp_add_command(master.risp_payload, STASH_CMD_CREATE_ROW, &cmdCreateRow); risp_add_command(master.risp_payload, STASH_CMD_SET, &cmdSet); risp_add_command(master.risp_payload, STASH_CMD_DELETE, &cmdDelete); // risp_add_command(master.risp_payload, STASH_CMD_DROP_USER, &cmdDropUser); master.risp_data = risp_init(NULL); assert(master.risp_data); storage = storage_init(NULL); assert(storage); if (storage_lock_file(storage, filename) == 0) { fprintf(stderr, "Unable to open file, it appears to be locked.\n"); exit(1); } else { // we were able to lock the file, so we can continue. From this point on, we cannot exit without unlocking the file. // TODO: We should intercept the signals at this point to ensure that the lock gets released. // process the main meta file; storage_process_file(storage, filename, master.risp_top, &master); storage_unlock_file(storage, filename); } // cleanup the risp interface. assert(master.risp_top); risp_shutdown(master.risp_top); master.risp_top = NULL; assert(master.risp_op); risp_shutdown(master.risp_op); master.risp_op = NULL; assert(master.risp_payload); risp_shutdown(master.risp_payload); master.risp_payload = NULL; assert(master.risp_data); risp_shutdown(master.risp_data); master.risp_data = NULL; assert(storage); storage_free(storage); storage = NULL; assert(master.risp_top == NULL); return 0; }