// local declarations: #include "debug.h" #include "socketserver.h" #include "blogxmlrpc.h" #include "processmanagement.h" #include "codes.h" #include "utils.h" int main (int argc, char **argv) { // variables int _fstat; int pid; FILE *pidfile; // open pid pidfile = fopen(PID_FILE, "w"); if (pidfile == NULL) { perror("bad open"); } // write my pid pid = getpid(); fprintf(pidfile, "%d", pid); fflush(pidfile); // close pid _fstat = fclose (pidfile); if (_fstat < 0) { perror("bad close"); } init_logging(); init_process_management(); start_socket_listener(); server_shutdown(); } void start_socket_listener() { fd_set readfds; int listener, acceptedsocket, pid; struct sockaddr_in serin, serfrom; int fromlen; char *servbuffer; char *newline; char *tmpcolon; // listen on localhost: if ((listener = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) { perror("socket listener failed"); return; } // bind bzero((char *)& serin, sizeof(struct sockaddr_in)); serin.sin_port = htons(SERVER_PORT); serin.sin_family = AF_INET; serin.sin_addr.s_addr = inet_addr("127.0.0.1"); if((bind(listener, (struct sockaddr *)& serin, sizeof(struct sockaddr_in))) < 0) { perror("listener bind error: probably SocketServer is already running, so this is ok :)"); log_message(1, "SocketServer probably already running, which is AOK -- discontinuing local startup and releasing my handle on the log"); // tell the existing server to add a client server_add_client(); return; } clients++; listen(listener, TCP_BACKLOG); log_message(5, "Listening, waiting on accept..."); while (acceptedsocket = accept(listener, (struct sockaddr *) &serfrom, &fromlen)) { log_message(1, "Accepted! Receiving..."); servbuffer = (char *)calloc(SERV_BUFFER_SIZE, sizeof(char)); if (recv(acceptedsocket, servbuffer, SERV_BUFFER_SIZE - 1, 0) < 0) { perror("receive error"); } // truncate buffer at newline \r or \n newline = index(servbuffer, 13); if (newline != NULL) newline[0] = 0; newline = index(servbuffer, 10); if (newline != NULL) newline[0] = 0; if (servbuffer == NULL) { perror("failure in ip in serverlisten buffer"); close (acceptedsocket); return; } else if ((strcmp(servbuffer, "SHUTDOWN") == 0) || (strstr(servbuffer, "/stopserver/") != NULL)) { free (servbuffer); clients--; if (clients > 0) { send(acceptedsocket, "DECREMENT", 9, 0); close (acceptedsocket); log_message(1, "client decremented, not shutting down server"); } else { send(acceptedsocket, "SHUTDOWN", 8, 0); close (acceptedsocket); log_message(1, "client decremented, shutting down server"); return; } } else if (strcmp(servbuffer, "ADDCLIENT") == 0) { free (servbuffer); clients++; send(acceptedsocket, "CLIENTADDED", 11, 0); close (acceptedsocket); } else { log_message(5, "servbuffer is"); log_message(5, servbuffer); // throttle fork on MAX_CHILDREN while (existing_children >= MAX_CHILDREN) { // wait for a child to free up } existing_children++; // fork: pid = fork(); forks++; if (pid == 0) { // child log_message(9, "I'm the child :)"); process_request_and_respond(acceptedsocket, servbuffer); free(servbuffer); child_shutdown(); } else if (pid > 0) { // parent log_message_pid(9, "I'm the parent, and I spawned the child", pid); } else if (pid < 0) { // error perror("fork error"); } close(acceptedsocket); } // else message to handle } // while accept close(listener); server_shutdown(); } void process_request_and_respond(int acceptedsocket, char *servbuffer) { char *responsebuffer; // parse request: // formulate response: log_message_pid(9, "process_request_and_respond begins", getpid()); responsebuffer = parse_reply(servbuffer); // send response: send(acceptedsocket, responsebuffer, strlen(responsebuffer), 0); close(acceptedsocket); } char *parse_reply(char *servbuffer) { char *method, *uri, *protocol, *command, *commanddata; char *bloghost, *blogurlenc, *blogurl, *blogserverip, *blogserverportstr; int blogserverport; method = strsep(&servbuffer, " "); uri = strsep(&servbuffer, " "); protocol = strsep(&servbuffer, " "); log_message_pid(9, "parse_reply begins", getpid()); if ((method == NULL) || (strlen(method) < 2)) { log_message_pid(5, "not known method -- return empty response", getpid()); return(NOKNOWNMETHOD_CODE); } log_message_pid(9, "Method:", getpid()); log_message_pid(9, method, getpid()); if ((strcmp(method, "GET") == 0) || (strcmp(method, "get") == 0)) { // here we branch out to the various implementations that we support: // /command/host-header-if-URL/urlencoded-if-URL/serverip-to-contact/port-to-contact/?commanddata // -if- ones can be the string NULL command = strsep(&uri, "/"); // leaves "" in command log_message_pid(9, "Command:", getpid()); log_message_pid(9, command, getpid()); command = strsep(&uri, "/"); // sets command log_message_pid(9, "Command:", getpid()); log_message_pid(9, command, getpid()); bloghost = strsep(&uri, "/"); // sets bloghost log_message_pid(9, "Bloghost:", getpid()); log_message_pid(9, bloghost, getpid()); blogurlenc = strsep(&uri, "/"); // sets blogurlenc log_message_pid(9, "Blogurlenc:", getpid()); log_message_pid(9, blogurlenc, getpid()); if (blogurlenc != NULL) { blogurl = (char *)calloc(strlen(blogurlenc), sizeof(char)); unescapeString(blogurlenc, blogurl); } else { blogurl = NULL; } blogserverip = strsep(&uri, "/"); // sets blogserverip log_message_pid(9, "Blogserverip:", getpid()); log_message_pid(9, blogserverip, getpid()); blogserverportstr = strsep(&uri, "/"); // sets blogserverport log_message_pid(9, "Blogserverportstr:", getpid()); log_message_pid(9, blogserverportstr, getpid()); if (blogserverportstr != NULL) { blogserverport = (int)strtol(blogserverportstr, (char **)NULL, 10); //atoi(blogserverportstr); } else { blogserverport = 0; } commanddata = strsep(&uri, "/"); // sets commanddata log_message_pid(9, "Commanddata:", getpid()); log_message_pid(9, commanddata, getpid()); // branch to function implementations of commands: if ((command == NULL) || (strlen(command) < 2)) { log_message_pid(5, "not known command -- return empty response", getpid()); return(NOCOMMAND_CODE); } else if (strcmp(command, "blog-xmlrpc-post") == 0) { if ((commanddata == NULL) || (strlen(commanddata) < 2)) { log_message_pid(5, "no commanddata -- ret empty resp", getpid()); return(NOCOMMANDDATA_CODE); } return blog_xmlrpc_post(commanddata, bloghost, blogurl, blogserverip, blogserverport, BLOGGER_API); } else if (strcmp(command, "metablog-xmlrpc-post") == 0) { if ((commanddata == NULL) || (strlen(commanddata) < 2)) { log_message_pid(5, "no commanddata -- ret empty resp", getpid()); return(NOCOMMANDDATA_CODE); } return blog_xmlrpc_post(commanddata, bloghost, blogurl, blogserverip, blogserverport, METAWEBLOG_API); } else { // no known command log_message_pid(5, "not known command -- return empty response", getpid()); return(NOKNOWNCOMMAND_CODE); } } else { // no known URL comment log_message_pid(5, "not URL GET method -- return empty response", getpid()); return(NOKNOWNMETHOD_CODE); } }