void *serve_loop(void *listenFD) { Request req = {0}; int connectionFD; while (1) { pthread_mutex_lock(&lock); if ((connectionFD = accept_connection((long) listenFD)) == -1) { pthread_mutex_unlock(&lock); continue; } pthread_mutex_unlock(&lock); if (client_request(connectionFD, &req) != 3) goto FREE; respond_to_client(connectionFD, &req); FREE: close(connectionFD); free(req.method); req.method = NULL; free(req.resource); req.resource = NULL; free(req.protocol); req.protocol = NULL; } }
/* Read the request from the socket, returning in a nice binary format. * The return value should be subject to NRVO, so it will be fast */ static Request read_request(int fd) { Request retval; std::unique_ptr<char[]> client_request(new char[client_request_size+1]); int amount_read; /* Get the request from the socket. */ if ((amount_read = read(fd,client_request.get(),client_request_size))==-1) { server_error(fd,500); throw; // TODO: choose a good exception to throw } else { client_request[amount_read]=0; // Make sure we have a valid C string } main_log << DEBUG << "Read Client Request:" << client_request.get(); /* Parse the request header */ std::stringstream request_stream(client_request.get());; request_stream >> retval.method; request_stream >> retval.URI; request_stream >> retval.http_version; if (request_stream.fail()) { main_log << WARNING << "Received a bad request:\n" << client_request.get(); server_error(fd,400); throw; // TODO: throw a proper exception } else { main_log << DEBUG << "Method: " << retval.method << '\n'; main_log << "Request URI: " << retval.URI << '\n'; main_log << "HTTP Version: " << retval.http_version << '\n'; } std::swap(retval.raw,client_request); return retval; }
int main(int argc, char **argv) { int ch, i, s; void *nc_handle; char *endptr, **hosts_bak; struct sigaction sigalarm; int grace_period = 30; struct netconfig *nconf; int have_v6 = 1; int maxrec = RPC_MAXDATASIZE; in_port_t svcport = 0; int attempt_cnt, port_len, port_pos, ret; char **port_list; while ((ch = getopt(argc, argv, "d:g:h:p:")) != (-1)) { switch (ch) { case 'd': debug_level = atoi(optarg); if (!debug_level) { usage(); /* NOTREACHED */ } break; case 'g': grace_period = atoi(optarg); if (!grace_period) { usage(); /* NOTREACHED */ } break; case 'h': ++nhosts; hosts_bak = hosts; hosts_bak = realloc(hosts, nhosts * sizeof(char *)); if (hosts_bak == NULL) { if (hosts != NULL) { for (i = 0; i < nhosts; i++) free(hosts[i]); free(hosts); out_of_mem(); } } hosts = hosts_bak; hosts[nhosts - 1] = strdup(optarg); if (hosts[nhosts - 1] == NULL) { for (i = 0; i < (nhosts - 1); i++) free(hosts[i]); free(hosts); out_of_mem(); } break; case 'p': endptr = NULL; svcport = (in_port_t)strtoul(optarg, &endptr, 10); if (endptr == NULL || *endptr != '\0' || svcport == 0 || svcport >= IPPORT_MAX) usage(); svcport_str = strdup(optarg); break; default: case '?': usage(); /* NOTREACHED */ } } if (geteuid()) { /* This command allowed only to root */ fprintf(stderr, "Sorry. You are not superuser\n"); exit(1); } kernel_lockd = FALSE; kernel_lockd_client = FALSE; if (modfind("nfslockd") < 0) { if (kldload("nfslockd") < 0) { fprintf(stderr, "Can't find or load kernel support for rpc.lockd - using non-kernel implementation\n"); } else { kernel_lockd = TRUE; } } else { kernel_lockd = TRUE; } if (kernel_lockd) { if (getosreldate() >= 800040) kernel_lockd_client = TRUE; } (void)rpcb_unset(NLM_PROG, NLM_SM, NULL); (void)rpcb_unset(NLM_PROG, NLM_VERS, NULL); (void)rpcb_unset(NLM_PROG, NLM_VERSX, NULL); (void)rpcb_unset(NLM_PROG, NLM_VERS4, NULL); /* * Check if IPv6 support is present. */ s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); if (s < 0) have_v6 = 0; else close(s); rpc_control(RPC_SVC_CONNMAXREC_SET, &maxrec); /* * If no hosts were specified, add a wildcard entry to bind to * INADDR_ANY. Otherwise make sure 127.0.0.1 and ::1 are added to the * list. */ if (nhosts == 0) { hosts = malloc(sizeof(char**)); if (hosts == NULL) out_of_mem(); hosts[0] = "*"; nhosts = 1; } else { hosts_bak = hosts; if (have_v6) { hosts_bak = realloc(hosts, (nhosts + 2) * sizeof(char *)); if (hosts_bak == NULL) { for (i = 0; i < nhosts; i++) free(hosts[i]); free(hosts); out_of_mem(); } else hosts = hosts_bak; nhosts += 2; hosts[nhosts - 2] = "::1"; } else { hosts_bak = realloc(hosts, (nhosts + 1) * sizeof(char *)); if (hosts_bak == NULL) { for (i = 0; i < nhosts; i++) free(hosts[i]); free(hosts); out_of_mem(); } else { nhosts += 1; hosts = hosts_bak; } } hosts[nhosts - 1] = "127.0.0.1"; } if (kernel_lockd) { if (!kernel_lockd_client) { /* * For the case where we have a kernel lockd but it * doesn't provide client locking, we run a cut-down * RPC service on a local-domain socket. The kernel's * RPC server will pass what it can't handle (mainly * client replies) down to us. */ struct sockaddr_un sun; int fd, oldmask; SVCXPRT *xprt; memset(&sun, 0, sizeof sun); sun.sun_family = AF_LOCAL; unlink(_PATH_RPCLOCKDSOCK); strcpy(sun.sun_path, _PATH_RPCLOCKDSOCK); sun.sun_len = SUN_LEN(&sun); fd = socket(AF_LOCAL, SOCK_STREAM, 0); if (!fd) { err(1, "Can't create local lockd socket"); } oldmask = umask(S_IXUSR|S_IRWXG|S_IRWXO); if (bind(fd, (struct sockaddr *) &sun, sun.sun_len) < 0) { err(1, "Can't bind local lockd socket"); } umask(oldmask); if (listen(fd, SOMAXCONN) < 0) { err(1, "Can't listen on local lockd socket"); } xprt = svc_vc_create(fd, RPC_MAXDATASIZE, RPC_MAXDATASIZE); if (!xprt) { err(1, "Can't create transport for local lockd socket"); } if (!svc_reg(xprt, NLM_PROG, NLM_VERS4, nlm_prog_4, NULL)) { err(1, "Can't register service for local lockd socket"); } } /* * We need to look up the addresses so that we can * hand uaddrs (ascii encoded address+port strings) to * the kernel. */ nc_handle = setnetconfig(); while ((nconf = getnetconfig(nc_handle))) { /* We want to listen only on udp6, tcp6, udp, tcp transports */ if (nconf->nc_flag & NC_VISIBLE) { /* Skip if there's no IPv6 support */ if (have_v6 == 0 && strcmp(nconf->nc_protofmly, "inet6") == 0) { /* DO NOTHING */ } else { lookup_addresses(nconf); } } } endnetconfig(nc_handle); } else { attempt_cnt = 1; sock_fdcnt = 0; sock_fd = NULL; port_list = NULL; port_len = 0; nc_handle = setnetconfig(); while ((nconf = getnetconfig(nc_handle))) { /* We want to listen only on udp6, tcp6, udp, tcp transports */ if (nconf->nc_flag & NC_VISIBLE) { /* Skip if there's no IPv6 support */ if (have_v6 == 0 && strcmp(nconf->nc_protofmly, "inet6") == 0) { /* DO NOTHING */ } else { ret = create_service(nconf); if (ret == 1) /* Ignore this call */ continue; if (ret < 0) { /* * Failed to bind port, so close * off all sockets created and * try again if the port# was * dynamically assigned via * bind(2). */ clearout_service(); if (mallocd_svcport != 0 && attempt_cnt < GETPORT_MAXTRY) { free(svcport_str); svcport_str = NULL; mallocd_svcport = 0; } else { errno = EADDRINUSE; syslog(LOG_ERR, "bindresvport_sa: %m"); exit(1); } /* * Start over at the first * service. */ free(sock_fd); sock_fdcnt = 0; sock_fd = NULL; nc_handle = setnetconfig(); attempt_cnt++; } else if (mallocd_svcport != 0 && attempt_cnt == GETPORT_MAXTRY) { /* * For the last attempt, allow * different port #s for each * nconf by saving the * svcport_str and setting it * back to NULL. */ port_list = realloc(port_list, (port_len + 1) * sizeof(char *)); if (port_list == NULL) out_of_mem(); port_list[port_len++] = svcport_str; svcport_str = NULL; mallocd_svcport = 0; } } } } /* * Successfully bound the ports, so call complete_service() to * do the rest of the setup on the service(s). */ sock_fdpos = 0; port_pos = 0; nc_handle = setnetconfig(); while ((nconf = getnetconfig(nc_handle))) { /* We want to listen only on udp6, tcp6, udp, tcp transports */ if (nconf->nc_flag & NC_VISIBLE) { /* Skip if there's no IPv6 support */ if (have_v6 == 0 && strcmp(nconf->nc_protofmly, "inet6") == 0) { /* DO NOTHING */ } else if (port_list != NULL) { if (port_pos >= port_len) { syslog(LOG_ERR, "too many port#s"); exit(1); } complete_service(nconf, port_list[port_pos++]); } else complete_service(nconf, svcport_str); } } endnetconfig(nc_handle); free(sock_fd); if (port_list != NULL) { for (port_pos = 0; port_pos < port_len; port_pos++) free(port_list[port_pos]); free(port_list); } } /* * Note that it is NOT sensible to run this program from inetd - the * protocol assumes that it will run immediately at boot time. */ if (daemon(0, debug_level > 0)) { err(1, "cannot fork"); /* NOTREACHED */ } openlog("rpc.lockd", 0, LOG_DAEMON); if (debug_level) syslog(LOG_INFO, "Starting, debug level %d", debug_level); else syslog(LOG_INFO, "Starting"); sigalarm.sa_handler = (sig_t) sigalarm_handler; sigemptyset(&sigalarm.sa_mask); sigalarm.sa_flags = SA_RESETHAND; /* should only happen once */ sigalarm.sa_flags |= SA_RESTART; if (sigaction(SIGALRM, &sigalarm, NULL) != 0) { syslog(LOG_WARNING, "sigaction(SIGALRM) failed: %s", strerror(errno)); exit(1); } if (kernel_lockd) { if (!kernel_lockd_client) { init_nsm(); client_pid = client_request(); /* * Create a child process to enter the kernel and then * wait for RPCs on our local domain socket. */ if (!fork()) nlm_syscall(debug_level, grace_period, naddrs, addrs); else svc_run(); } else { /* * The kernel lockd implementation provides * both client and server so we don't need to * do anything else. */ nlm_syscall(debug_level, grace_period, naddrs, addrs); } } else { grace_expired = 0; alarm(grace_period); init_nsm(); client_pid = client_request(); svc_run(); /* Should never return */ } exit(1); }
TEST(http_client_request, DISABLED_construct_from_invalid_uri) { ASSERT_THROW(client_request("I am not a valid URI"), std::exception); }
TEST(http_client_request, construct_from_uri) { ASSERT_NO_THROW(client_request("http://cpp-netlib.org/")); }
int main(int argc, char *argv[]) { struct sockaddr_in sockname, client; struct sigaction sa; struct tm* time_struct; FILE * logfile; socklen_t clientlen; int sd; char timec[80]; char dircopy[80]; char *ep; time_t rawtime; u_short port; pid_t pid; u_long p; /* * first, figure out what port we will listen on - it should * be our first parameter. */ if (argc != 4) { usage(); errno = 0; } p = strtoul(argv[1], &ep, 10); if (*argv[1] == '\0' || *ep != '\0') { /* parameter wasn't a number, or was empty */ fprintf(stderr, "%s - not a number\n", argv[1]); usage(); } if ((errno == ERANGE && p == ULONG_MAX) || (p > USHRT_MAX)) { /* It's a number, but it either can't fit in an unsigned * long, or is too big for an unsigned short */ fprintf(stderr, "%s - value out of range\n", argv[1]); usage(); } strncpy(dircopy, argv[2], sizeof(dircopy)); /* Checking if the directory exists. * adapted from * http://stackoverflow.com/a/12510903 */ if (opendir(dircopy) == NULL) { fprintf(stderr, "Directory does not exist.\n"); usage(); } /* * Check to make sure logfile can open and does exist */ logfile = fopen(argv[3], "a"); if (logfile == NULL) { fprintf(stderr, "Error opening logfile.\n"); usage(); } fclose(logfile); /* used strncpy as I found out assignment is not possible */ strncpy(docdir, argv[2], sizeof(docdir)); strncpy(logdir, argv[3], sizeof(logdir)); /* now safe to do this */ if (daemon(1, 0) == -1) { fprintf(stderr, "Could not daemonize.\n"); usage(); } port = p; memset(&sockname, 0, sizeof(sockname)); sockname.sin_family = AF_INET; sockname.sin_port = htons(port); sockname.sin_addr.s_addr = htonl(INADDR_ANY); sd=socket(AF_INET,SOCK_STREAM,0); if ( sd == -1) err(1, "socket failed"); if (bind(sd, (struct sockaddr *) &sockname, sizeof(sockname)) == -1) err(1, "bind failed"); if (listen(sd,3) == -1) err(1, "listen failed"); /* * we're now bound, and listening for connections on "sd" - * each call to "accept" will return us a descriptor talking to * a connected client */ /* * first, let's make sure we can have children without leaving * zombies around when they die - we can do this by catching * SIGCHLD. */ sa.sa_handler = kidhandler; sigemptyset(&sa.sa_mask); /* * we want to allow system calls like accept to be restarted if they * get interrupted by a SIGCHLD */ sa.sa_flags = SA_RESTART; if (sigaction(SIGCHLD, &sa, NULL) == -1) err(1, "sigaction failed"); /* * finally - the main loop. accept connections and deal with 'em */ for(;;) { int clientsd; clientlen = sizeof(&client); clientsd = accept(sd, (struct sockaddr *)&client, &clientlen); if (clientsd == -1) err(1, "accept failed"); /* * We fork child to deal with each connection, this way more * than one client can connect to us and get served at any one * time. */ pid = fork(); if (pid == -1) err(1, "fork failed"); if(pid == 0) { /* * Using INET to determine client ip * code adapted from * http://stackoverflow.com/a/3060988 */ char clientip[INET_ADDRSTRLEN]; inet_ntop(AF_INET, &(client.sin_addr), clientip, INET_ADDRSTRLEN); /* * Getting current time using time library * code adapted from * http://stackoverflow.com/a/10332099 */ time(&rawtime); time_struct = localtime(&rawtime); strftime(timec, 80, "%a, %d %b %Y %X %Z", time_struct); client_request(clientsd, timec, clientip); exit(0); } close(clientsd); } }