main(int argc, char *argv[]) { int fileSize = 0, fd = 0, n =0; char *hostname; char line[MAX], buff[256], functionName = 0, pathName[256] = {0}, fileName[256] = {0}; if (argc < 2) hostname = "localhost"; else hostname = argv[1]; chdir("../ServerRoot"); getcwd(buff, 256); //chroot(buff); server_init(hostname); initializeFunctionList(); // Try to accept a client request while(1) { printf("server: accepting new connection ....\n"); // Try to accept a client connection as descriptor newsock length = sizeof(client_addr); newsock = accept(sock, (struct sockaddr *)&client_addr, &length); if (newsock < 0) { printf("server: accept error\n"); exit(1); } printf("server: accepted a client connection from\n"); printf("-----------------------------------------------\n"); printf(" IP=%s port=%d\n", (char*)inet_ntoa(client_addr.sin_addr.s_addr), ntohs(client_addr.sin_port)); printf("-----------------------------------------------\n"); // Processing loop while(1) { printf("@> "); n = read(newsock, line, MAX); if (n==0) { printf("server: client died, server loops\n"); close(newsock); break; } //grab function number and pathname from the client input if(line[0] == 'P') //Server receives a put command from client { strtok(line, " "); fileSize = atoi(strtok(NULL, " ")); strcpy(fileName, strtok(NULL, " ")); fd = open(fileName, O_WRONLY | O_CREAT, 0644); if(fd == 0) { write(newsock, "F", 2); } else { write(newsock, "S", 2); printf("Reading file from client...\n"); while(fileSize > 0) { n = read(newsock, returnString, 4096); write(fd, returnString, n); fileSize -= n; } printf("@> File '%s' from client uploaded...\n", fileName); close (fd); } } else if(line[0] == 'G') //Server receives a get command from client { int fd = 0, i = 0, n = 0; struct stat fileStatus; char buff[16]; char fileName[256] = {0}; strtok(line, " "); strcpy(fileName, strtok(NULL, " ")); fd = open(fileName, O_RDONLY); if(fd == 0) { printf("Server File Not Found."); write(newsock, "F", 2); } else { fstat(fd, &fileStatus); sprintf(buff, "S %d", 74); write(newsock, buff, 16); printf("Sending %s to client...\n", fileName); i = fileStatus.st_size; while(i > 0) { n = read(fd, returnString, 4096); write(newsock, returnString, strlen(returnString)); i -= n; } printf("@> Transmission of %d bytes complete...\n", (int) fileStatus.st_size); } } else { functionName = atoi(&line[0]); if(line[1] == ' ') { strcpy(pathName, &line[2]); } else { pathName[0] = '\0'; } printf("Server: client sent func: %d | path: %s\n", functionName, pathName); executeServerCommand(functionName, pathName, newsock); } bzero(line, MAX); } } }
int main (int argc, char **argv) { server *srv = NULL; int print_config = 0; int test_config = 0; int i_am_root; int o; int num_childs = 0; int pid_fd = -1, fd; size_t i; #ifdef HAVE_SIGACTION struct sigaction act; #endif #ifdef HAVE_GETRLIMIT struct rlimit rlim; #endif #ifdef USE_ALARM struct itimerval interval; interval.it_interval.tv_sec = 1; interval.it_interval.tv_usec = 0; interval.it_value.tv_sec = 1; interval.it_value.tv_usec = 0; #endif /* for nice %b handling in strfime() */ setlocale(LC_TIME, "C"); if (NULL == (srv = server_init())) { fprintf(stderr, "did this really happen?\n"); return -1; } /* init structs done */ srv->srvconf.port = 0; #ifdef HAVE_GETUID i_am_root = (getuid() == 0); #else i_am_root = 0; #endif srv->srvconf.dont_daemonize = 0; while(-1 != (o = getopt(argc, argv, "f:m:hvVDpt"))) { switch(o) { case 'f': if (config_read(srv, optarg)) { server_free(srv); return -1; } break; case 'm': buffer_copy_string(srv->srvconf.modules_dir, optarg); break; case 'p': print_config = 1; break; case 't': test_config = 1; break; case 'D': srv->srvconf.dont_daemonize = 1; break; case 'v': show_version(); return 0; case 'V': show_features(); return 0; case 'h': show_help(); return 0; default: show_help(); server_free(srv); return -1; } } if (!srv->config_storage) { log_error_write(srv, __FILE__, __LINE__, "s", "No configuration available. Try using -f option."); server_free(srv); return -1; } if (print_config) { data_unset *dc = srv->config_context->data[0]; if (dc) { dc->print(dc, 0); fprintf(stdout, "\n"); } else { /* shouldn't happend */ fprintf(stderr, "global config not found\n"); } } if (test_config) { printf("Syntax OK\n"); } if (test_config || print_config) { server_free(srv); return 0; } /* close stdin and stdout, as they are not needed */ openDevNull(STDIN_FILENO); openDevNull(STDOUT_FILENO); if (0 != config_set_defaults(srv)) { log_error_write(srv, __FILE__, __LINE__, "s", "setting default values failed"); server_free(srv); return -1; } /* UID handling */ #ifdef HAVE_GETUID if (!i_am_root && issetugid()) { /* we are setuid-root */ log_error_write(srv, __FILE__, __LINE__, "s", "Are you nuts ? Don't apply a SUID bit to this binary"); server_free(srv); return -1; } #endif /* check document-root */ if (srv->config_storage[0]->document_root->used <= 1) { log_error_write(srv, __FILE__, __LINE__, "s", "document-root is not set\n"); server_free(srv); return -1; } if (plugins_load(srv)) { log_error_write(srv, __FILE__, __LINE__, "s", "loading plugins finally failed"); plugins_free(srv); server_free(srv); return -1; } /* open pid file BEFORE chroot */ if (srv->srvconf.pid_file->used) { if (-1 == (pid_fd = open(srv->srvconf.pid_file->ptr, O_WRONLY | O_CREAT | O_EXCL | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH))) { struct stat st; if (errno != EEXIST) { log_error_write(srv, __FILE__, __LINE__, "sbs", "opening pid-file failed:", srv->srvconf.pid_file, strerror(errno)); return -1; } if (0 != stat(srv->srvconf.pid_file->ptr, &st)) { log_error_write(srv, __FILE__, __LINE__, "sbs", "stating existing pid-file failed:", srv->srvconf.pid_file, strerror(errno)); } if (!S_ISREG(st.st_mode)) { log_error_write(srv, __FILE__, __LINE__, "sb", "pid-file exists and isn't regular file:", srv->srvconf.pid_file); return -1; } if (-1 == (pid_fd = open(srv->srvconf.pid_file->ptr, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH))) { log_error_write(srv, __FILE__, __LINE__, "sbs", "opening pid-file failed:", srv->srvconf.pid_file, strerror(errno)); return -1; } } } if (srv->event_handler == FDEVENT_HANDLER_SELECT) { /* select limits itself * * as it is a hard limit and will lead to a segfault we add some safety * */ srv->max_fds = FD_SETSIZE - 200; } else { srv->max_fds = 4096; } if (i_am_root) { struct group *grp = NULL; struct passwd *pwd = NULL; int use_rlimit = 1; #ifdef HAVE_VALGRIND_VALGRIND_H if (RUNNING_ON_VALGRIND) use_rlimit = 0; #endif #ifdef HAVE_GETRLIMIT if (0 != getrlimit(RLIMIT_NOFILE, &rlim)) { log_error_write(srv, __FILE__, __LINE__, "ss", "couldn't get 'max filedescriptors'", strerror(errno)); return -1; } if (use_rlimit && srv->srvconf.max_fds) { /* set rlimits */ rlim.rlim_cur = srv->srvconf.max_fds; rlim.rlim_max = srv->srvconf.max_fds; if (0 != setrlimit(RLIMIT_NOFILE, &rlim)) { log_error_write(srv, __FILE__, __LINE__, "ss", "couldn't set 'max filedescriptors'", strerror(errno)); return -1; } } if (srv->event_handler == FDEVENT_HANDLER_SELECT) { srv->max_fds = rlim.rlim_cur < ((int)FD_SETSIZE) - 200 ? rlim.rlim_cur : FD_SETSIZE - 200; } else { srv->max_fds = rlim.rlim_cur; } /* set core file rlimit, if enable_cores is set */ if (use_rlimit && srv->srvconf.enable_cores && getrlimit(RLIMIT_CORE, &rlim) == 0) { rlim.rlim_cur = rlim.rlim_max; setrlimit(RLIMIT_CORE, &rlim); } #endif if (srv->event_handler == FDEVENT_HANDLER_SELECT) { /* don't raise the limit above FD_SET_SIZE */ if (srv->max_fds > ((int)FD_SETSIZE) - 200) { log_error_write(srv, __FILE__, __LINE__, "sd", "can't raise max filedescriptors above", FD_SETSIZE - 200, "if event-handler is 'select'. Use 'poll' or something else or reduce server.max-fds."); return -1; } } #ifdef HAVE_PWD_H /* set user and group */ if (srv->srvconf.username->used) { if (NULL == (pwd = getpwnam(srv->srvconf.username->ptr))) { log_error_write(srv, __FILE__, __LINE__, "sb", "can't find username", srv->srvconf.username); return -1; } if (pwd->pw_uid == 0) { log_error_write(srv, __FILE__, __LINE__, "s", "I will not set uid to 0\n"); return -1; } } if (srv->srvconf.groupname->used) { if (NULL == (grp = getgrnam(srv->srvconf.groupname->ptr))) { log_error_write(srv, __FILE__, __LINE__, "sb", "can't find groupname", srv->srvconf.groupname); return -1; } if (grp->gr_gid == 0) { log_error_write(srv, __FILE__, __LINE__, "s", "I will not set gid to 0\n"); return -1; } } #endif /* we need root-perms for port < 1024 */ if (0 != network_init(srv)) { plugins_free(srv); server_free(srv); return -1; } #ifdef HAVE_PWD_H /* * Change group before chroot, when we have access * to /etc/group * */ if (NULL != grp) { setgid(grp->gr_gid); setgroups(0, NULL); if (srv->srvconf.username->used) { initgroups(srv->srvconf.username->ptr, grp->gr_gid); } } #endif #ifdef HAVE_CHROOT if (srv->srvconf.changeroot->used) { tzset(); if (-1 == chroot(srv->srvconf.changeroot->ptr)) { log_error_write(srv, __FILE__, __LINE__, "ss", "chroot failed: ", strerror(errno)); return -1; } if (-1 == chdir("/")) { log_error_write(srv, __FILE__, __LINE__, "ss", "chdir failed: ", strerror(errno)); return -1; } } #endif #ifdef HAVE_PWD_H /* drop root privs */ if (NULL != pwd) { setuid(pwd->pw_uid); } #endif #if defined(HAVE_SYS_PRCTL_H) && defined(PR_SET_DUMPABLE) /** * on IRIX 6.5.30 they have prctl() but no DUMPABLE */ if (srv->srvconf.enable_cores) { prctl(PR_SET_DUMPABLE, 1, 0, 0, 0); } #endif } else { #ifdef HAVE_GETRLIMIT if (0 != getrlimit(RLIMIT_NOFILE, &rlim)) { log_error_write(srv, __FILE__, __LINE__, "ss", "couldn't get 'max filedescriptors'", strerror(errno)); return -1; } /** * we are not root can can't increase the fd-limit, but we can reduce it */ if (srv->srvconf.max_fds && srv->srvconf.max_fds < rlim.rlim_cur) { /* set rlimits */ rlim.rlim_cur = srv->srvconf.max_fds; if (0 != setrlimit(RLIMIT_NOFILE, &rlim)) { log_error_write(srv, __FILE__, __LINE__, "ss", "couldn't set 'max filedescriptors'", strerror(errno)); return -1; } } if (srv->event_handler == FDEVENT_HANDLER_SELECT) { srv->max_fds = rlim.rlim_cur < ((int)FD_SETSIZE) - 200 ? rlim.rlim_cur : FD_SETSIZE - 200; } else { srv->max_fds = rlim.rlim_cur; } /* set core file rlimit, if enable_cores is set */ if (srv->srvconf.enable_cores && getrlimit(RLIMIT_CORE, &rlim) == 0) { rlim.rlim_cur = rlim.rlim_max; setrlimit(RLIMIT_CORE, &rlim); } #endif if (srv->event_handler == FDEVENT_HANDLER_SELECT) { /* don't raise the limit above FD_SET_SIZE */ if (srv->max_fds > ((int)FD_SETSIZE) - 200) { log_error_write(srv, __FILE__, __LINE__, "sd", "can't raise max filedescriptors above", FD_SETSIZE - 200, "if event-handler is 'select'. Use 'poll' or something else or reduce server.max-fds."); return -1; } } if (0 != network_init(srv)) { plugins_free(srv); server_free(srv); return -1; } } /* set max-conns */ if (srv->srvconf.max_conns > srv->max_fds/2) { /* we can't have more connections than max-fds/2 */ log_error_write(srv, __FILE__, __LINE__, "sdd", "can't have more connections than fds/2: ", srv->srvconf.max_conns, srv->max_fds); srv->max_conns = srv->max_fds/2; } else if (srv->srvconf.max_conns) { /* otherwise respect the wishes of the user */ srv->max_conns = srv->srvconf.max_conns; } else { /* or use the default: we really don't want to hit max-fds */ srv->max_conns = srv->max_fds/3; } if (HANDLER_GO_ON != plugins_call_init(srv)) { log_error_write(srv, __FILE__, __LINE__, "s", "Initialization of plugins failed. Going down."); plugins_free(srv); network_close(srv); server_free(srv); return -1; } #ifdef HAVE_FORK /* network is up, let's deamonize ourself */ if (srv->srvconf.dont_daemonize == 0) daemonize(); #endif srv->gid = getgid(); srv->uid = getuid(); /* write pid file */ if (pid_fd != -1) { buffer_copy_long(srv->tmp_buf, getpid()); buffer_append_string_len(srv->tmp_buf, CONST_STR_LEN("\n")); write(pid_fd, srv->tmp_buf->ptr, srv->tmp_buf->used - 1); close(pid_fd); pid_fd = -1; } /* Close stderr ASAP in the child process to make sure that nothing * is being written to that fd which may not be valid anymore. */ if (-1 == log_error_open(srv)) { log_error_write(srv, __FILE__, __LINE__, "s", "Opening errorlog failed. Going down."); plugins_free(srv); network_close(srv); server_free(srv); return -1; } if (HANDLER_GO_ON != plugins_call_set_defaults(srv)) { log_error_write(srv, __FILE__, __LINE__, "s", "Configuration of plugins failed. Going down."); plugins_free(srv); network_close(srv); server_free(srv); return -1; } /* dump unused config-keys */ for (i = 0; i < srv->config_context->used; i++) { array *config = ((data_config *)srv->config_context->data[i])->value; size_t j; for (j = 0; config && j < config->used; j++) { data_unset *du = config->data[j]; /* all var.* is known as user defined variable */ if (strncmp(du->key->ptr, "var.", sizeof("var.") - 1) == 0) { continue; } if (NULL == array_get_element(srv->config_touched, du->key->ptr)) { log_error_write(srv, __FILE__, __LINE__, "sbs", "WARNING: unknown config-key:", du->key, "(ignored)"); } } } if (srv->config_unsupported) { log_error_write(srv, __FILE__, __LINE__, "s", "Configuration contains unsupported keys. Going down."); } if (srv->config_deprecated) { log_error_write(srv, __FILE__, __LINE__, "s", "Configuration contains deprecated keys. Going down."); } if (srv->config_unsupported || srv->config_deprecated) { plugins_free(srv); network_close(srv); server_free(srv); return -1; } #ifdef HAVE_SIGACTION memset(&act, 0, sizeof(act)); act.sa_handler = SIG_IGN; sigaction(SIGPIPE, &act, NULL); sigaction(SIGUSR1, &act, NULL); # if defined(SA_SIGINFO) act.sa_sigaction = sigaction_handler; sigemptyset(&act.sa_mask); act.sa_flags = SA_SIGINFO; # else act.sa_handler = signal_handler; sigemptyset(&act.sa_mask); act.sa_flags = 0; # endif sigaction(SIGINT, &act, NULL); sigaction(SIGTERM, &act, NULL); sigaction(SIGHUP, &act, NULL); sigaction(SIGALRM, &act, NULL); sigaction(SIGCHLD, &act, NULL); #elif defined(HAVE_SIGNAL) /* ignore the SIGPIPE from sendfile() */ signal(SIGPIPE, SIG_IGN); signal(SIGUSR1, SIG_IGN); signal(SIGALRM, signal_handler); signal(SIGTERM, signal_handler); signal(SIGHUP, signal_handler); signal(SIGCHLD, signal_handler); signal(SIGINT, signal_handler); #endif #ifdef USE_ALARM signal(SIGALRM, signal_handler); /* setup periodic timer (1 second) */ if (setitimer(ITIMER_REAL, &interval, NULL)) { log_error_write(srv, __FILE__, __LINE__, "s", "setting timer failed"); return -1; } getitimer(ITIMER_REAL, &interval); #endif #ifdef HAVE_FORK /* start watcher and workers */ num_childs = srv->srvconf.max_worker; if (num_childs > 0) { int child = 0; while (!child && !srv_shutdown && !graceful_shutdown) { if (num_childs > 0) { switch (fork()) { case -1: return -1; case 0: child = 1; break; default: num_childs--; break; } } else { int status; if (-1 != wait(&status)) { /** * one of our workers went away */ num_childs++; } else { switch (errno) { case EINTR: /** * if we receive a SIGHUP we have to close our logs ourself as we don't * have the mainloop who can help us here */ if (handle_sig_hup) { handle_sig_hup = 0; log_error_cycle(srv); /** * forward to all procs in the process-group * * we also send it ourself */ if (!forwarded_sig_hup) { forwarded_sig_hup = 1; kill(0, SIGHUP); } } break; default: break; } } } } /** * for the parent this is the exit-point */ if (!child) { /** * kill all children too */ if (graceful_shutdown) { kill(0, SIGINT); } else if (srv_shutdown) { kill(0, SIGTERM); } log_error_close(srv); network_close(srv); connections_free(srv); plugins_free(srv); server_free(srv); return 0; } } #endif if (NULL == (srv->ev = fdevent_init(srv->max_fds + 1, srv->event_handler))) { log_error_write(srv, __FILE__, __LINE__, "s", "fdevent_init failed"); return -1; } /* * kqueue() is called here, select resets its internals, * all server sockets get their handlers * * */ if (0 != network_register_fdevents(srv)) { plugins_free(srv); network_close(srv); server_free(srv); return -1; } /* might fail if user is using fam (not gamin) and famd isn't running */ if (NULL == (srv->stat_cache = stat_cache_init())) { log_error_write(srv, __FILE__, __LINE__, "s", "stat-cache could not be setup, dieing."); return -1; } #ifdef HAVE_FAM_H /* setup FAM */ if (srv->srvconf.stat_cache_engine == STAT_CACHE_ENGINE_FAM) { if (0 != FAMOpen2(srv->stat_cache->fam, "lighttpd")) { log_error_write(srv, __FILE__, __LINE__, "s", "could not open a fam connection, dieing."); return -1; } #ifdef HAVE_FAMNOEXISTS FAMNoExists(srv->stat_cache->fam); #endif srv->stat_cache->fam_fcce_ndx = -1; fdevent_register(srv->ev, FAMCONNECTION_GETFD(srv->stat_cache->fam), stat_cache_handle_fdevent, NULL); fdevent_event_add(srv->ev, &(srv->stat_cache->fam_fcce_ndx), FAMCONNECTION_GETFD(srv->stat_cache->fam), FDEVENT_IN); } #endif /* get the current number of FDs */ srv->cur_fds = open("/dev/null", O_RDONLY); close(srv->cur_fds); for (i = 0; i < srv->srv_sockets.used; i++) { server_socket *srv_socket = srv->srv_sockets.ptr[i]; if (-1 == fdevent_fcntl_set(srv->ev, srv_socket->fd)) { log_error_write(srv, __FILE__, __LINE__, "ss", "fcntl failed:", strerror(errno)); return -1; } } /* main-loop */ while (!srv_shutdown) { int n; int timeout; size_t ndx; time_t min_ts; if (handle_sig_hup) { handler_t r; /* reset notification */ handle_sig_hup = 0; /* cycle logfiles */ switch(r = plugins_call_handle_sighup(srv)) { case HANDLER_GO_ON: break; default: log_error_write(srv, __FILE__, __LINE__, "sd", "sighup-handler return with an error", r); break; } if (-1 == log_error_cycle(srv)) { log_error_write(srv, __FILE__, __LINE__, "s", "cycling errorlog failed, dying"); return -1; } else { #ifdef HAVE_SIGACTION log_error_write(srv, __FILE__, __LINE__, "sdsd", "logfiles cycled UID =", last_sighup_info.si_uid, "PID =", last_sighup_info.si_pid); #else log_error_write(srv, __FILE__, __LINE__, "s", "logfiles cycled"); #endif } } if (handle_sig_alarm) { /* a new second */ #ifdef USE_ALARM /* reset notification */ handle_sig_alarm = 0; #endif /* get current time */ min_ts = time(NULL); if (min_ts != srv->cur_ts) { int cs = 0; connections *conns = srv->conns; handler_t r; switch(r = plugins_call_handle_trigger(srv)) { case HANDLER_GO_ON: break; case HANDLER_ERROR: log_error_write(srv, __FILE__, __LINE__, "s", "one of the triggers failed"); break; default: log_error_write(srv, __FILE__, __LINE__, "d", r); break; } /* trigger waitpid */ srv->cur_ts = min_ts; /* cleanup stat-cache */ stat_cache_trigger_cleanup(srv); /** * check all connections for timeouts * */ for (ndx = 0; ndx < conns->used; ndx++) { int changed = 0; connection *con; int t_diff; con = conns->ptr[ndx]; if (con->state == CON_STATE_READ || con->state == CON_STATE_READ_POST) { if (con->request_count == 1) { if (srv->cur_ts - con->read_idle_ts > con->conf.max_read_idle) { /* time - out */ #if 0 log_error_write(srv, __FILE__, __LINE__, "sd", "connection closed - read-timeout:", con->fd); #endif connection_set_state(srv, con, CON_STATE_ERROR); changed = 1; } } else { if (srv->cur_ts - con->read_idle_ts > con->keep_alive_idle) { /* time - out */ #if 0 log_error_write(srv, __FILE__, __LINE__, "sd", "connection closed - read-timeout:", con->fd); #endif connection_set_state(srv, con, CON_STATE_ERROR); changed = 1; } } } if ((con->state == CON_STATE_WRITE) && (con->write_request_ts != 0)) { #if 0 if (srv->cur_ts - con->write_request_ts > 60) { log_error_write(srv, __FILE__, __LINE__, "sdd", "connection closed - pre-write-request-timeout:", con->fd, srv->cur_ts - con->write_request_ts); } #endif if (srv->cur_ts - con->write_request_ts > con->conf.max_write_idle) { /* time - out */ if (con->conf.log_timeouts) { log_error_write(srv, __FILE__, __LINE__, "sbsosds", "NOTE: a request for", con->request.uri, "timed out after writing", con->bytes_written, "bytes. We waited", (int)con->conf.max_write_idle, "seconds. If this a problem increase server.max-write-idle"); } connection_set_state(srv, con, CON_STATE_ERROR); changed = 1; } } if (con->state == CON_STATE_CLOSE && (srv->cur_ts - con->close_timeout_ts > HTTP_LINGER_TIMEOUT)) { changed = 1; } /* we don't like div by zero */ if (0 == (t_diff = srv->cur_ts - con->connection_start)) t_diff = 1; if (con->traffic_limit_reached && (con->conf.kbytes_per_second == 0 || ((con->bytes_written / t_diff) < con->conf.kbytes_per_second * 1024))) { /* enable connection again */ con->traffic_limit_reached = 0; changed = 1; } if (changed) { connection_state_machine(srv, con); } con->bytes_written_cur_second = 0; *(con->conf.global_bytes_per_second_cnt_ptr) = 0; #if 0 if (cs == 0) { fprintf(stderr, "connection-state: "); cs = 1; } fprintf(stderr, "c[%d,%d]: %s ", con->fd, con->fcgi.fd, connection_get_state(con->state)); #endif } if (cs == 1) fprintf(stderr, "\n"); } } if (srv->sockets_disabled) { /* our server sockets are disabled, why ? */ if ((srv->cur_fds + srv->want_fds < srv->max_fds * 8 / 10) && /* we have enough unused fds */ (srv->conns->used <= srv->max_conns * 9 / 10) && (0 == graceful_shutdown)) { for (i = 0; i < srv->srv_sockets.used; i++) { server_socket *srv_socket = srv->srv_sockets.ptr[i]; fdevent_event_add(srv->ev, &(srv_socket->fde_ndx), srv_socket->fd, FDEVENT_IN); } log_error_write(srv, __FILE__, __LINE__, "s", "[note] sockets enabled again"); srv->sockets_disabled = 0; } } else { if ((srv->cur_fds + srv->want_fds > srv->max_fds * 9 / 10) || /* out of fds */ (srv->conns->used >= srv->max_conns) || /* out of connections */ (graceful_shutdown)) { /* graceful_shutdown */ /* disable server-fds */ for (i = 0; i < srv->srv_sockets.used; i++) { server_socket *srv_socket = srv->srv_sockets.ptr[i]; fdevent_event_del(srv->ev, &(srv_socket->fde_ndx), srv_socket->fd); if (graceful_shutdown) { /* we don't want this socket anymore, * * closing it right away will make it possible for * the next lighttpd to take over (graceful restart) * */ fdevent_unregister(srv->ev, srv_socket->fd); close(srv_socket->fd); srv_socket->fd = -1; /* network_close() will cleanup after us */ if (srv->srvconf.pid_file->used && srv->srvconf.changeroot->used == 0) { if (0 != unlink(srv->srvconf.pid_file->ptr)) { if (errno != EACCES && errno != EPERM) { log_error_write(srv, __FILE__, __LINE__, "sbds", "unlink failed for:", srv->srvconf.pid_file, errno, strerror(errno)); } } } } } if (graceful_shutdown) { log_error_write(srv, __FILE__, __LINE__, "s", "[note] graceful shutdown started"); } else if (srv->conns->used >= srv->max_conns) { log_error_write(srv, __FILE__, __LINE__, "s", "[note] sockets disabled, connection limit reached"); } else { log_error_write(srv, __FILE__, __LINE__, "s", "[note] sockets disabled, out-of-fds"); } srv->sockets_disabled = 1; } } if (graceful_shutdown && srv->conns->used == 0) { /* we are in graceful shutdown phase and all connections are closed * we are ready to terminate without harming anyone */ srv_shutdown = 1; } /* we still have some fds to share */ if (srv->want_fds) { /* check the fdwaitqueue for waiting fds */ int free_fds = srv->max_fds - srv->cur_fds - 16; connection *con; for (; free_fds > 0 && NULL != (con = fdwaitqueue_unshift(srv, srv->fdwaitqueue)); free_fds--) { connection_state_machine(srv, con); srv->want_fds--; } } if(srv->joblist->used > 0) { timeout = 500; } else { timeout = 1000; } if ((n = fdevent_poll(srv->ev, timeout)) > 0) { /* n is the number of events */ int revents; int fd_ndx; #if 0 if (n > 0) { log_error_write(srv, __FILE__, __LINE__, "sd", "polls:", n); } #endif fd_ndx = -1; do { fdevent_handler handler; void *context; handler_t r; fd_ndx = fdevent_event_next_fdndx (srv->ev, fd_ndx); revents = fdevent_event_get_revent (srv->ev, fd_ndx); fd = fdevent_event_get_fd (srv->ev, fd_ndx); handler = fdevent_get_handler(srv->ev, fd); context = fdevent_get_context(srv->ev, fd); /* connection_handle_fdevent needs a joblist_append */ #if 0 log_error_write(srv, __FILE__, __LINE__, "sdd", "event for", fd, revents); #endif switch (r = (*handler)(srv, context, revents)) { case HANDLER_FINISHED: case HANDLER_GO_ON: case HANDLER_WAIT_FOR_EVENT: case HANDLER_WAIT_FOR_FD: break; case HANDLER_ERROR: /* should never happen */ SEGFAULT(); break; default: log_error_write(srv, __FILE__, __LINE__, "d", r); break; } } while (--n > 0); } else if (n < 0 && errno != EINTR) { log_error_write(srv, __FILE__, __LINE__, "ss", "fdevent_poll failed:", strerror(errno)); } if(srv->joblist->used > 0) { connections *joblist = srv->joblist; /* switch joblist queues. */ srv->joblist = srv->joblist_prev; srv->joblist_prev = joblist; for (ndx = 0; ndx < joblist->used; ndx++) { connection *con = joblist->ptr[ndx]; handler_t r; con->in_joblist = 0; connection_state_machine(srv, con); switch(r = plugins_call_handle_joblist(srv, con)) { case HANDLER_FINISHED: case HANDLER_GO_ON: break; default: log_error_write(srv, __FILE__, __LINE__, "d", r); break; } } joblist->used = 0; } } if (srv->srvconf.pid_file->used && srv->srvconf.changeroot->used == 0 && 0 == graceful_shutdown) { if (0 != unlink(srv->srvconf.pid_file->ptr)) { if (errno != EACCES && errno != EPERM) { log_error_write(srv, __FILE__, __LINE__, "sbds", "unlink failed for:", srv->srvconf.pid_file, errno, strerror(errno)); } } } #ifdef HAVE_SIGACTION log_error_write(srv, __FILE__, __LINE__, "sdsd", "server stopped by UID =", last_sigterm_info.si_uid, "PID =", last_sigterm_info.si_pid); #else log_error_write(srv, __FILE__, __LINE__, "s", "server stopped"); #endif /* clean-up */ log_error_close(srv); network_close(srv); connections_free(srv); plugins_free(srv); server_free(srv); return 0; }
int main(int argc, char *argv[]) { Server server; int r = EXIT_FAILURE, n; if (getppid() != 1) { log_error("This program should be invoked by init only."); return EXIT_FAILURE; } if (argc > 1) { log_error("This program does not take arguments."); return EXIT_FAILURE; } log_set_target(LOG_TARGET_AUTO); log_parse_environment(); log_open(); umask(0022); if ((n = sd_listen_fds(true)) < 0) { log_error("Failed to read listening file descriptors from environment: %s", strerror(-r)); return EXIT_FAILURE; } if (n <= 0 || n > SERVER_FD_MAX) { log_error("No or too many file descriptors passed."); return EXIT_FAILURE; } if (server_init(&server, (unsigned) n) < 0) return EXIT_FAILURE; log_debug("systemd-initctl running as pid "PID_FMT, getpid()); sd_notify(false, "READY=1\n" "STATUS=Processing requests..."); while (!server.quit) { struct epoll_event event; int k; if ((k = epoll_wait(server.epoll_fd, &event, 1, TIMEOUT_MSEC)) < 0) { if (errno == EINTR) continue; log_error("epoll_wait() failed: %m"); goto fail; } if (k <= 0) break; if (process_event(&server, &event) < 0) goto fail; } r = EXIT_SUCCESS; log_debug("systemd-initctl stopped as pid "PID_FMT, getpid()); fail: sd_notify(false, "STATUS=Shutting down..."); server_done(&server); return r; }
int main ( int argc, char ** argv ) { MPI_Comm intercomm, intracomm; MPI_Request request; MPI_Status status; int ibuffer; int neighbor_rank, rank, size; int *usize, aflag; MPI_Init(&argc, &argv); #if 1 /* temporary hack for MPICH2: if we inquire about MPI_UNIVERSE_SIZE, * MPICH2 will promote our singleton init into a full-fleged MPI * environment */ MPI_Comm_get_attr(MPI_COMM_WORLD, MPI_UNIVERSE_SIZE, &usize, &aflag); #endif intercomm = MPI_COMM_NULL; #if defined( SERVER ) is_server = 1; intercomm = server_init( MPI_COMM_WORLD ); #elif defined( CLIENT ) is_client = 1; intercomm = client_init( MPI_COMM_WORLD ); #else parse_args( argc, argv ); if ( is_server ) { intercomm = server_init( MPI_COMM_WORLD ); } else if ( is_client ) { intercomm = client_init( MPI_COMM_WORLD ); } #endif if ( intercomm == MPI_COMM_NULL ) { if ( is_server ) { fprintf( stderr, "Server returns NULL intercommunicator!" ); } else if ( is_client ) { fprintf( stderr, "Client returns NULL intercommunicator!" ); } else { fprintf( stderr, "Unknown server/client: NULL intercommunicator!" ); } return -1; } MPI_Comm_rank( intercomm, &rank ); if ( rank == 0 ) { MPI_Irecv( &ibuffer, 1, MPI_INT, 0, 9999, intercomm, &request ); MPI_Send( &rank, 1, MPI_INT, 0, 9999, intercomm ); MPI_Wait( &request, &status ); } MPI_Intercomm_merge( intercomm, 0, &intracomm ); MPI_Comm_rank( intracomm, &rank ); MPI_Comm_size( intracomm, &size ); fprintf( stdout, "[%d/%d] after Intercomm_merge()\n", rank, size ); if ( rank == size - 1 ) neighbor_rank = 0; else neighbor_rank = rank + 1; MPI_Irecv( &ibuffer, 1, MPI_INT, MPI_ANY_SOURCE, 999, intracomm, &request ); MPI_Send( &rank, 1, MPI_INT, neighbor_rank, 999, intracomm ); MPI_Wait( &request, &status ); MPI_Comm_free( &intracomm ); MPI_Comm_disconnect( &intercomm ); MPI_Finalize(); return 0; }
int main(){ system("clear"); tiempoEjec=time(NULL); listaEjecutando = list_create(); listaCpuLibres = list_create(); listaInicializando = list_create(); listaAfinalizar = list_create(); listaPorcentajeCpus = list_create(); listaCpus = list_create(); colaListos = queue_create(); colaIO = queue_create(); sem_init(&hayProgramas,0,0); sem_init(&hayCPU,0,0); sem_init(&hayIO,0,0); pthread_mutex_init(&mutexProcesoListo,NULL); pthread_mutex_init(&mutexInicializando,NULL); pthread_mutex_init(&mutexListaCpusLibres,NULL); pthread_mutex_init(&mutexIO,NULL); pthread_mutex_init(&mutexListaEjecutando,NULL); pthread_mutex_init(&mutexSwitchProc,NULL); pthread_mutex_init(&mutexFinalizarPid,NULL); pthread_mutex_init(&mutexListasCpu,NULL); pthread_mutex_init(&mutexListasPorcentajes,NULL); //creacion de la instancia de log logPlanificador = log_create("../src/log.txt", "planificador.c", false, LOG_LEVEL_INFO); //leemos el archivo de configuracion configPlanificador = leerConfiguracion(); //Inicia el socket para escuchar int serverSocket; server_init(&serverSocket, configPlanificador->puertoEscucha); printf("Planificador listo...\n"); tParametroSelector sel; sel.socket = serverSocket; sel.listaCpus = listaCpuLibres; pthread_t enviarAlCpu,selectorCpu,consumidorIO; pthread_attr_t attr; pthread_attr_init(&attr); /*creacion de hilos*/ pthread_create(&selectorCpu,&attr,selector,(void*)&sel); pthread_create(&enviarAlCpu,&attr,enviar,NULL); pthread_create(&consumidorIO,&attr,consumidor,NULL); int enviar = 1; int cantProc = 1; int lng = 0; char * message = 0; while(enviar){ /*reemplaza a fgets*/ while(1){ int c ; if ((c = getchar()) == EOF) break; message = realloc(message,lng + 1); message[lng] = c; lng++; if (c == '\n') break; } message = realloc(message,lng + 1); message[lng] = '\0'; if (!strcmp(message,"exit\n")) { enviar = 0; llegoexit = true; sem_post(&hayCPU); sem_post(&hayProgramas); sem_post(&hayIO); } else procesarComando(clasificarComando(message),message,&cantProc); /*reinicio*/ free(message); message = 0; lng = 0; } /*espero la terminacion de enviar*/ pthread_join(enviarAlCpu,NULL); pthread_join(consumidorIO,NULL); sem_destroy(&hayCPU); sem_destroy(&hayIO); sem_destroy(&hayProgramas); pthread_mutex_destroy(&mutexIO); pthread_mutex_destroy(&mutexInicializando); pthread_mutex_destroy(&mutexListaCpusLibres); pthread_mutex_destroy(&mutexListaEjecutando); pthread_mutex_destroy(&mutexProcesoListo); pthread_mutex_destroy(&mutexSwitchProc); pthread_mutex_destroy(&mutexFinalizarPid); pthread_mutex_destroy(&mutexListasCpu); pthread_mutex_destroy(&mutexListasPorcentajes); /*destruyo la lista y sus elementos*/ list_destroy_and_destroy_elements(listaCpuLibres,free); list_destroy_and_destroy_elements(listaEjecutando,free); list_destroy_and_destroy_elements(listaInicializando,free); list_destroy_and_destroy_elements(listaAfinalizar,free); list_destroy_and_destroy_elements(listaCpus,free); list_destroy_and_destroy_elements(listaPorcentajeCpus,free); /*destruyo la cola y sus elementos*/ queue_destroy_and_destroy_elements(colaListos,free); close(serverSocket); logTpoTotal(); return 0; }
int main(int argc, char* argv[]) { //---------------------- #ifndef DEBUG srand(time(NULL)); srand_sse(time(NULL)); #else srand(1); srand_sse(1111); #endif if (argc < 3) { printf("Usage: %s <scd file name> <port> \n", argv[0]); return -1; } int port = atoi(argv[2]); int connfd = server_init(port); if (connfd == -1) { printf("Something's wrong with the socket!\n"); return -1; } #define GARBLING #ifndef GARBLING server_close(connfd); return 0; #else //----------------------------------------- Garbling GarbledCircuit garbledCircuit; long i, j, cid; readCircuitFromFile(&garbledCircuit, argv[1]); printf("garbledCircuit.I[0] = %d\n", garbledCircuit.I[0]); int n = garbledCircuit.n; int g = garbledCircuit.g; int p = garbledCircuit.p; int m = garbledCircuit.m; int c = garbledCircuit.c; int e = n - g; int *garbler_inputs = (int *) malloc(sizeof(int) * (g) * c); block *inputLabels = (block *) malloc(sizeof(block) * 2 * n * c); block *initialDFFLable = (block *) malloc(sizeof(block) * 2 * p); block *outputLabels = (block *) malloc(sizeof(block) * 2 * m * c); printf("\n\ninputs:\n"); for (cid = 0; cid < c; cid++) { for (j = 0; j < g; j++) { garbler_inputs[cid * g + j] = rand() % 2; printf("%d ", garbler_inputs[cid * g + j]); } } printf("\n\n"); #ifndef DEBUG block R = randomBlock(); *((short *) (&R)) |= 1; #else block R = makeBlock((long )(-1), (long )(-1)); #endif uint8_t * rptr = (uint8_t*) &R; for (int i = 0; i < 16; i++) rptr[i] = 0xff; // *((short *) (&R)) |= 1; rptr[0] |= 1; createInputLabels(inputLabels, R, n * c); createInputLabels(initialDFFLable, R, p); ///--------------------------------------------------------------- OT Extension //Parameters int numOTs = c * e; int bitlength = 128; m_nSecParam = 128; m_nNumOTThreads = 1; BYTE version; crypto *crypt = new crypto(m_nSecParam, (uint8_t*) m_vSeed); InitOTSender(connfd, crypt); CBitVector delta, X1, X2; delta.Create(numOTs, bitlength, crypt); m_fMaskFct = new XORMasking(bitlength, delta); for (int i=0;i<numOTs;i++) delta.SetBytes(rptr, i*16, 16); printf("Delta: "); for (int i = 0; i < 16; i++) { printf("%02x", delta.GetByte(i)); } printf("\n"); printf("R: "); print__m128i(R); printf("\n"); X1.Create(numOTs, bitlength); X1.Reset(); X2.Create(numOTs, bitlength); X2.Reset(); uint8_t* b = new BYTE[16]; BYTE* b2 = new BYTE[16]; cout << "Sender performing " << numOTs << " C_OT extensions on " << bitlength << " bit elements" << endl; version = C_OT; ObliviouslySend(X1, X2, numOTs, bitlength, version, crypt); //putting X1 & X2 into inputLabels printf("printing inputLabels after copy from X1 and X2:\n\n"); uint8_t* inputLabelsptr; for (cid = 0; cid < c; cid++) { for (j = 0; j < e; j++) { inputLabelsptr = (uint8_t*) &inputLabels[2 * (cid * n + g + j)]; X1.GetBytes(inputLabelsptr, 16*(cid * e + j), 16); print__m128i(inputLabels[2 * (cid * n + g + j)]); inputLabelsptr = (uint8_t*) &inputLabels[2 * (cid * n + g + j) + 1]; X2.GetBytes(inputLabelsptr, 16*(cid * e + j), 16); print__m128i(inputLabels[2 * (cid * n + g + j) + 1]); } } //print printf("Printing X1:\n"); for (int j = 0; j < numOTs; j++) { for (int i = 0; i < 16; i++) { b[i] = X1.GetByte(i + j * 16); printf("%02x", b[i]); } printf("\n"); } printf("\n\n"); printf("Printing X2:\n"); for (int j = 0; j < numOTs; j++) { for (int i = 0; i < 16; i++) { b[i] = X2.GetByte(i + j * 16); printf("%02x", b[i]); } printf("\n"); } printf("\n\n"); printf("Printing delta:\t"); for (int i = 0; i < 16; i++) { b[i] = delta.GetByte(i); printf("%02x", b[i]); } printf("\n"); //----------------------------------------------------end of OT Extension for (cid = 0; cid < c; cid++) { for (j = 0; j < g; j++) { if (garbler_inputs[cid * g + j] == 0) send_block(connfd, inputLabels[2 * (cid * n + j)]); else send_block(connfd, inputLabels[2 * (cid * n + j) + 1]); printf("i(%ld, %ld, %d)\n", cid, j, garbler_inputs[cid * g + j]); print__m128i(inputLabels[2 * (cid * n + j)]); print__m128i(inputLabels[2 * (cid * n + j) + 1]); } //------------------------------------------------------------------------------------------ CHANGE 1 for (j = 0; j < e; j++) { // int ev_input; // read(connfd, &ev_input, sizeof(int)); // if (!ev_input) // send_block(connfd, inputLabels[2 * (cid * n + g + j)]); // else // send_block(connfd, inputLabels[2 * (cid * n + g + j) + 1]); printf("evaluator : i(%ld, %ld, ?)\n", cid, j); print__m128i(inputLabels[2 * (cid * n + g + j)]); print__m128i(inputLabels[2 * (cid * n + g + j) + 1]); } printf("Compare to: "); printf("\n"); //----------------------------------------------------------------------end } printf("\n\n"); for (j = 0; j < p; j++) //p:#DFF { printf("garbledCircuit.I[j] = %d\n", garbledCircuit.I[j]); if (garbledCircuit.I[j] == CONST_ZERO) // constant zero { send_block(connfd, initialDFFLable[2 * j]); printf("dffi(%ld, %ld, %d)\n", cid, j, 0); print__m128i(initialDFFLable[2 * j]); print__m128i(initialDFFLable[2 * j + 1]); } else if (garbledCircuit.I[j] == CONST_ONE) // constant zero { send_block(connfd, initialDFFLable[2 * j + 1]); printf("dffi(%ld, %ld, %d)\n", cid, j, 0); print__m128i(inputLabels[2 * j]); print__m128i(inputLabels[2 * j + 1]); } else if (garbledCircuit.I[j] < g) //belongs to Alice (garbler) { int index = garbledCircuit.I[j]; if (garbler_inputs[index] == 0) send_block(connfd, initialDFFLable[2 * j]); else send_block(connfd, initialDFFLable[2 * j + 1]); printf("dffi(%ld, %ld, %d)\n", cid, j, garbler_inputs[index]); print__m128i(initialDFFLable[2 * j]); print__m128i(initialDFFLable[2 * j + 1]); } //------------------------------------------------------------------------------------------ CHANGE 2 else //**** belongs to Bob { // int ev_input; // read(connfd, &ev_input, sizeof(int)); // if (!ev_input) // send_block(connfd, initialDFFLable[2 * j]); // else // send_block(connfd, initialDFFLable[2 * j + 1]); // printf("dffi(%ld, %ld, %d)\n", cid, j, ev_input); print__m128i(initialDFFLable[2 * j]); print__m128i(initialDFFLable[2 * j + 1]); printf("\n"); } //----------------------------------------------------------------------end } printf("\n\n"); ///--------------------------------------------------------------- OT Extension //Parameters numOTs = p; delta.Create(numOTs, bitlength, crypt); m_fMaskFct = new XORMasking(bitlength, delta); for (int i=0;i<numOTs;i++) delta.SetBytes(rptr, i*16, 16); printf("Delta: "); for (int i = 0; i < 16; i++) { printf("%02x", delta.GetByte(i)); } printf("\n"); printf("R: "); print__m128i(R); printf("\n"); X1.Create(numOTs, bitlength); X1.Reset(); X2.Create(numOTs, bitlength); X2.Reset(); cout << "Sender performing " << numOTs << " C_OT extensions on " << bitlength << " bit elements" << endl; version = C_OT; ObliviouslySend(X1, X2, numOTs, bitlength, version, crypt); //putting X1 & X2 into inputLabels printf("printing inputLabels after copy from X1 and X2:\n\n"); for (j = 0; j < p; j++) { inputLabelsptr = (uint8_t*) &initialDFFLable[2 * j]; X1.GetBytes(inputLabelsptr, 16*(j), 16); inputLabelsptr = (uint8_t*) &initialDFFLable[2 * j +1]; X2.GetBytes(inputLabelsptr, 16*( j), 16); } delete crypt; //----------------------------------------------------end of OT Extension garbledCircuit.globalKey = randomBlock(); send_block(connfd, garbledCircuit.globalKey); // send DKC key printf("R: "); print__m128i(R); printf("\n"); garble(&garbledCircuit, inputLabels, initialDFFLable, outputLabels, &R, connfd); printf("***************** InputLabels\n"); for (int i=0;i<n*c*2;i++) print__m128i(inputLabels[i]); for (cid = 0; cid < c; cid++) { for (i = 0; i < m; i++) { short outputType = getLSB(outputLabels[2 * (m * cid + i) + 0]); send_type(connfd, outputType); } } server_close(connfd); removeGarbledCircuit(&garbledCircuit); return 0; #endif }
/* ****************** * 程序的入口点 ***************** */ int main(int argc, char **argv) { server *srv = NULL; int print_config = 0; int test_config = 0; int i_am_root; int o; int num_childs = 0; int pid_fd = -1, fd; size_t i; #ifdef HAVE_SIGACTION struct sigaction act; #endif #ifdef HAVE_GETRLIMIT struct rlimit rlim; #endif #ifdef USE_ALARM struct itimerval interval; interval.it_interval.tv_sec = 1; interval.it_interval.tv_usec = 0; interval.it_value.tv_sec = 1; interval.it_value.tv_usec = 0; #endif /* * for nice %b handling in strfime() */ setlocale(LC_TIME, "C"); if (NULL == (srv = server_init())) { fprintf(stderr, "did this really happen?\n"); return -1; } /* * init structs done */ srv->srvconf.port = 0; // #ifdef HAVE_GETUID i_am_root = (getuid() == 0); #else i_am_root = 0; #endif //程序将被设置为守护进程。 srv->srvconf.dont_daemonize = 0; //处理参数。 while (-1 != (o = getopt(argc, argv, "f:m:hvVDpt"))) { switch (o) { case 'f': if (config_read(srv, optarg)) { server_free(srv); return -1; } break; case 'm': buffer_copy_string(srv->srvconf.modules_dir, optarg); break; case 'p': print_config = 1; break; case 't': test_config = 1; break; case 'D': srv->srvconf.dont_daemonize = 1; break; case 'v': show_version(); return 0; case 'V': show_features(); return 0; case 'h': show_help(); return 0; default: show_help(); server_free(srv); return -1; } } if (!srv->config_storage) { log_error_write(srv, __FILE__, __LINE__, "s", "No configuration available. Try using -f option."); server_free(srv); return -1; } if (print_config) { data_unset *dc = srv->config_context->data[0]; if (dc) { dc->print(dc, 0); fprintf(stdout, "\n"); } else { /* * shouldn't happend */ fprintf(stderr, "global config not found\n"); } } if (test_config) //没有进行任何测试。。。 { printf("Syntax OK\n"); } if (test_config || print_config) { server_free(srv); return 0; } /* * close stdin and stdout, as they are not needed * 关闭标准输入和标准输出。 */ openDevNull(STDIN_FILENO); openDevNull(STDOUT_FILENO); //设置为默认的配置。 if (0 != config_set_defaults(srv)) { log_error_write(srv, __FILE__, __LINE__, "s", "setting default values failed"); server_free(srv); return -1; } /* * UID handling */ #ifdef HAVE_GETUID //检查有效用户ID和有效组ID是否是0(root)。 if (!i_am_root && (geteuid() == 0 || getegid() == 0)) { /* * we are setuid-root * 程序的实际用户ID不是0,也就是程序不是由超级用户运行的,但是程序的有效用户ID * 或者有效组ID是超级用户(组),因此,程序可以访问任何文件而不受限制!这样很 * 不安全。因此程序退出并提示用户。 */ log_error_write(srv, __FILE__, __LINE__, "s", "Are you nuts ? Don't apply a SUID bit to this binary"); server_free(srv); return -1; } #endif /* * check document-root */ if (srv->config_storage[0]->document_root->used <= 1) { log_error_write(srv, __FILE__, __LINE__, "s", "document-root is not set\n"); server_free(srv); return -1; } /* * 加载插件 * * 插件是以动态链接库的形式存在的。在配置文件中,要配置好插件的链接库的 * 路径位置和库中函数的名称。在这个函数中,通过这些配置,获得函数的入口 * 地址。 * 可以看到,这个函数的调用是在整个程序的初始化阶段,而且只调用了这一次, * 因此,在服务器运行之前,要配置好所有的插件。 * 如果想增加插件,只能重启服务器。 * * 在实现plugins_load函数的时候,同时也有一个用于加载静态链接库的版本, * 但函数并没有什么实质性的实现。 * */ if (plugins_load(srv)) { log_error_write(srv, __FILE__, __LINE__, "s", "loading plugins finally failed"); plugins_free(srv); server_free(srv); return -1; } /* * open pid file BEFORE chroot * 打开pid文件,并将进程号写入pid文件。 */ if (srv->srvconf.pid_file->used) { if (-1 == (pid_fd = open(srv->srvconf.pid_file->ptr, O_WRONLY | O_CREAT | O_EXCL | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH))) /** * O_EXCL和O_CREAT同时使用,测试文件是否存在,如果存在 * 则报错。 */ { //pid文件打开失败。。。 struct stat st; if (errno != EEXIST) //不是报文件已经存在的错误。 { log_error_write(srv, __FILE__, __LINE__, "sbs", "opening pid-file failed:", srv->srvconf.pid_file, strerror(errno)); return -1; } //pid文件已经存在,测试文件的状态。 if (0 != stat(srv->srvconf.pid_file->ptr, &st)) { log_error_write(srv, __FILE__, __LINE__, "sbs", "stating existing pid-file failed:", srv->srvconf.pid_file, strerror(errno)); } if (!S_ISREG(st.st_mode)) //pid文件是普通文件。 { log_error_write(srv, __FILE__, __LINE__, "sb", "pid-file exists and isn't regular file:", srv->srvconf.pid_file); return -1; } //重新打开pid文件。 //这里不在使用O_EXCL参数,由于pid文件已经存在且是普通文件,则覆盖原先的文件。 if (-1 == (pid_fd = open(srv->srvconf.pid_file->ptr, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH))) { log_error_write(srv, __FILE__, __LINE__, "sbs", "opening pid-file failed:", srv->srvconf.pid_file, strerror(errno)); return -1; } } } if (srv->event_handler == FDEVENT_HANDLER_SELECT) { /* * select limits itself as it is a hard limit and will lead to a segfault * we add some safety * select的硬限制。减去200是为了增加安全性,防止出现段错误。 */ srv->max_fds = FD_SETSIZE - 200; } else { srv->max_fds = 4096; } //程序是在超级用户模式下运行的。 if (i_am_root) { struct group *grp = NULL; struct passwd *pwd = NULL; int use_rlimit = 1; #ifdef HAVE_VALGRIND_VALGRIND_H if (RUNNING_ON_VALGRIND) use_rlimit = 0; #endif #ifdef HAVE_GETRLIMIT /** * getrlimit和setrlimit函数用于查询和修改进程的资源限制。 * * include <sys/resource.h> * int getrlimit(int resource, struct rlimit *rlim); * int setrlimit(int resource, const struct rlimit *rlim); * 返回:若成功为0,出错为非0 * * 对这两个函数的每一次调用都指定一个资源以及一个指向下列结构的指针。 * * struct rlimit * { * rlim_t rlim_cur; //软限制:当前限制 * rlim_t rlim_max; //硬限制:rlimcur的最大值 * }; * * 这两个函数不属于POSIX.1,但SVR4和4.3+BSD提供它们。SVR4在上面的结构中使用基本系统数据类型rlim_t。 * 其它系统则将这两个成员定义为整型或长整型。 * * 程序中使用的参数RLIMIT_NOFILE:Specifies a value one greater than the maximum file descriptor * number that can be opened by this process. 设置最大的文件打开数,且实际打开的文件数要比这个数 * 小一。 * * 详细使用:man getrlimit */ if (0 != getrlimit(RLIMIT_NOFILE, &rlim)) //获得当前的文件打开数限制。 { log_error_write(srv, __FILE__, __LINE__, "ss", "couldn't get 'max filedescriptors'", strerror(errno)); return -1; } if (use_rlimit && srv->srvconf.max_fds) { /* * set rlimits. 设置限制。 */ rlim.rlim_cur = srv->srvconf.max_fds; //软限制。 rlim.rlim_max = srv->srvconf.max_fds; //硬限制。 if (0 != setrlimit(RLIMIT_NOFILE, &rlim)) { log_error_write(srv, __FILE__, __LINE__, "ss", "couldn't set 'max filedescriptors'", strerror(errno)); return -1; } } //根据实际设置情况,重新设置max_fds。 if (srv->event_handler == FDEVENT_HANDLER_SELECT) { srv->max_fds = rlim.rlim_cur < FD_SETSIZE - 200 ? rlim.rlim_cur : FD_SETSIZE - 200; } else { srv->max_fds = rlim.rlim_cur; } /* * set core file rlimit, if enable_cores is set * 设置core文件的限制。如果设置了enable_cores。 */ if (use_rlimit && srv->srvconf.enable_cores && getrlimit(RLIMIT_CORE, &rlim) == 0) { rlim.rlim_cur = rlim.rlim_max; setrlimit(RLIMIT_CORE, &rlim); } #endif if (srv->event_handler == FDEVENT_HANDLER_SELECT) { /* * don't raise the limit above FD_SET_SIZE */ if (srv->max_fds > FD_SETSIZE - 200) { log_error_write(srv, __FILE__, __LINE__, "sd", "can't raise max filedescriptors above", FD_SETSIZE - 200, "if event-handler is 'select'. Use 'poll' or something else or reduce server.max-fds."); return -1; } } #ifdef HAVE_PWD_H /* * set user and group 设置用户和组。 */ if (srv->srvconf.username->used) { //根据配置中的用户名获取用户信息。 if (NULL == (pwd = getpwnam(srv->srvconf.username->ptr))) { log_error_write(srv, __FILE__, __LINE__, "sb", "can't find username", srv->srvconf.username); return -1; } if (pwd->pw_uid == 0) { log_error_write(srv, __FILE__, __LINE__, "s", "I will not set uid to 0\n"); return -1; } } if (srv->srvconf.groupname->used) { //根据上面得到的用户所在的组的组名,获得组的信息。 if (NULL == (grp = getgrnam(srv->srvconf.groupname->ptr))) { log_error_write(srv, __FILE__, __LINE__, "sb", "can't find groupname", srv->srvconf.groupname); return -1; } if (grp->gr_gid == 0) { log_error_write(srv, __FILE__, __LINE__, "s", "I will not set gid to 0\n"); return -1; } } #endif /* * we need root-perms for port < 1024 * 使用超级用户模式获得小于1024的端口。初始化网络。 * 创建监听socket,绑定地址并开始监听。 */ if (0 != network_init(srv)) { plugins_free(srv); server_free(srv); return -1; } #ifdef HAVE_PWD_H /* * Change group before chroot, when we have access * to /etc/group * */ if (srv->srvconf.groupname->used) { setgid(grp->gr_gid); setgroups(0, NULL); //返回用户组的数目。 if (srv->srvconf.username->used) { //Initialize the group access list by reading the group database /etc/group and using all groups of which //user is a member. The additional group group is also added to the list. initgroups(srv->srvconf.username->ptr, grp->gr_gid); } } #endif #ifdef HAVE_CHROOT if (srv->srvconf.changeroot->used) { //The tzset() function initializes the tzname variable from the TZ environment variable. //This function is automatically called by the other time conversion functions that depend //on the time zone. //In a SysV-like environment it will also set the variables time-zone (seconds West of GMT) //and daylight //(0 if this time zone does not have any daylight saving time rules, nonzero if there is a //time during the year when daylight saving time applies). tzset(); //设置程序所参考的根目录,将被所有的子进程继承。 //也就是对于本程序而言,"/"并不是系统的根目录,而是这设置的目录。 if (-1 == chroot(srv->srvconf.changeroot->ptr)) { log_error_write(srv, __FILE__, __LINE__, "ss", "chroot failed: ", strerror(errno)); return -1; } //修改工作目录. /* * 注意: * 由于前面已经设置了根目录。因此这里将工作目录切换到"/"并不是系统的根目录,而是 * 上面通过函数chroot设置的根目录。 */ if (-1 == chdir("/")) { log_error_write(srv, __FILE__, __LINE__, "ss", "chdir failed: ", strerror(errno)); return -1; } } #endif #ifdef HAVE_PWD_H /* * drop root privs 放弃超级管理员权限。 */ if (srv->srvconf.username->used) { setuid(pwd->pw_uid); } #endif #if defined(HAVE_SYS_PRCTL_H) && defined(PR_SET_DUMPABLE) /** * on IRIX 6.5.30 they have prctl() but no DUMPABLE */ if (srv->srvconf.enable_cores) { prctl(PR_SET_DUMPABLE, 1, 0, 0, 0); } #endif } /* * 下面的是程序在非root用户下执行的设置。 */ else { #ifdef HAVE_GETRLIMIT if (0 != getrlimit(RLIMIT_NOFILE, &rlim)) { log_error_write(srv, __FILE__, __LINE__, "ss", "couldn't get 'max filedescriptors'", strerror(errno)); return -1; } /** * we are not root can can't increase the fd-limit, but we can reduce it * 我们不是root,不能增加fd-limit,但我们可以减少。 */ if (srv->srvconf.max_fds && srv->srvconf.max_fds < rlim.rlim_cur) { /* * set rlimits */ rlim.rlim_cur = srv->srvconf.max_fds; //只能设置软限制。 if (0 != setrlimit(RLIMIT_NOFILE, &rlim)) { log_error_write(srv, __FILE__, __LINE__, "ss", "couldn't set 'max filedescriptors'", strerror(errno)); return -1; } } if (srv->event_handler == FDEVENT_HANDLER_SELECT) { srv->max_fds = rlim.rlim_cur < FD_SETSIZE - 200 ? rlim.rlim_cur : FD_SETSIZE - 200; } else { srv->max_fds = rlim.rlim_cur; } /* * set core file rlimit, if enable_cores is set */ if (srv->srvconf.enable_cores && getrlimit(RLIMIT_CORE, &rlim) == 0) { rlim.rlim_cur = rlim.rlim_max; setrlimit(RLIMIT_CORE, &rlim); } #endif if (srv->event_handler == FDEVENT_HANDLER_SELECT) { /* * don't raise the limit above FD_SET_SIZE */ if (srv->max_fds > FD_SETSIZE - 200) { log_error_write(srv, __FILE__, __LINE__, "sd", "can't raise max filedescriptors above", FD_SETSIZE - 200, "if event-handler is 'select'. Use 'poll' or something else or reduce server.max-fds."); return -1; } } if (0 != network_init(srv)) { plugins_free(srv); server_free(srv); return -1; } } /* * set max-conns 设置最大连接数。 */ if (srv->srvconf.max_conns > srv->max_fds) { /* * we can't have more connections than max-fds * 最大连接数要小于最大文件打开数(max-fds) */ srv->max_conns = srv->max_fds; } else if (srv->srvconf.max_conns) { /* * otherwise respect the wishes of the user * 根据用户设置。 */ srv->max_conns = srv->srvconf.max_conns; } else { /* * or use the default 默认。 */ srv->max_conns = srv->max_fds; } /* * 在前面的plugins_load函数中,已经所有的插件读入到系统中,并对插件中含有 * 的各种函数,确定入口地址。 * 在这里,程序对所有插件进行登记造册,确定插件中含有的功能,并计入表中(srv->plugins_slot) * */ if (HANDLER_GO_ON != plugins_call_init(srv)) { log_error_write(srv, __FILE__, __LINE__, "s", "Initialization of plugins failed. Going down."); plugins_free(srv); network_close(srv); server_free(srv); return -1; } #ifdef HAVE_FORK /* * network is up, let's deamonize ourself * 设置为守护进程。 */ if (srv->srvconf.dont_daemonize == 0) daemonize(); #endif srv->gid = getgid(); srv->uid = getuid(); /* * write pid file 写pid文件。 */ if (pid_fd != -1) { buffer_copy_long(srv->tmp_buf, getpid()); buffer_append_string_len(srv->tmp_buf, CONST_STR_LEN("\n")); write(pid_fd, srv->tmp_buf->ptr, srv->tmp_buf->used - 1); close(pid_fd); pid_fd = -1; } /* * Close stderr ASAP in the child process to make sure that nothing is * being written to that fd which may not be valid anymore. * 关闭向标准输出的输出,打开日志文件。 */ if (-1 == log_error_open(srv)) { log_error_write(srv, __FILE__, __LINE__, "s", "Opening errorlog failed. Going down."); plugins_free(srv); network_close(srv); server_free(srv); return -1; } //将插件设置为默认配置 if (HANDLER_GO_ON != plugins_call_set_defaults(srv)) { log_error_write(srv, __FILE__, __LINE__, "s", "Configuration of plugins failed. Going down."); plugins_free(srv); network_close(srv); server_free(srv); return -1; } /* * dump unused config-keys */ for (i = 0; i < srv->config_context->used; i++) { array *config = ((data_config *) srv->config_context->data[i])->value; size_t j; for (j = 0; config && j < config->used; j++) { data_unset *du = config->data[j]; /* * all var.* is known as user defined variable */ if (strncmp(du->key->ptr, "var.", sizeof("var.") - 1) == 0) { continue; } if (NULL == array_get_element(srv->config_touched, du->key->ptr)) { log_error_write(srv, __FILE__, __LINE__, "sbs", "WARNING: unknown config-key:", du->key, "(ignored)"); } } } if (srv->config_unsupported) { log_error_write(srv, __FILE__, __LINE__, "s", "Configuration contains unsupported keys. Going down."); } if (srv->config_deprecated) { log_error_write(srv, __FILE__, __LINE__, "s", "Configuration contains deprecated keys. Going down."); } if (srv->config_unsupported || srv->config_deprecated) { plugins_free(srv); network_close(srv); server_free(srv); return -1; } //设置一些信号的处理方法。 //SIGPIPE:在写管道时,读管道的进程终止,产生此信号。 #ifdef HAVE_SIGACTION memset(&act, 0, sizeof(act)); act.sa_handler = SIG_IGN; sigaction(SIGPIPE, &act, NULL); sigaction(SIGUSR1, &act, NULL); # if defined(SA_SIGINFO) act.sa_sigaction = sigaction_handler; sigemptyset(&act.sa_mask); act.sa_flags = SA_SIGINFO; # else act.sa_handler = signal_handler; sigemptyset(&act.sa_mask); act.sa_flags = 0; # endif sigaction(SIGINT, &act, NULL); sigaction(SIGTERM, &act, NULL); sigaction(SIGHUP, &act, NULL); sigaction(SIGALRM, &act, NULL); sigaction(SIGCHLD, &act, NULL); #elif defined(HAVE_SIGNAL) /* * ignore the SIGPIPE from sendfile() */ signal(SIGPIPE, SIG_IGN); signal(SIGUSR1, SIG_IGN); signal(SIGALRM, signal_handler); signal(SIGTERM, signal_handler); signal(SIGHUP, signal_handler); signal(SIGCHLD, signal_handler); signal(SIGINT, signal_handler); #endif #ifdef USE_ALARM signal(SIGALRM, signal_handler); /* * setup periodic timer (1 second) * The system provides each process with three interval timers, each decrementing in a distinct time domain. * When any timer expires a signal is sent to the process, and the timer (potentially) restarts. * * ITIMER_REAL decrements in real time, and delivers SIGALRM upon expiration. * ITIMER_VIRTUAL decrements only when the process is executing, and delivers SIGVTALRM upon expiration. * ITIMER_PROF decrements both when the process executes and when the system is executing on * behalf of the process. * Coupled with ITIMER_VIRTUAL, this timer is usually used to profile the time spent * by the application in user and kernel space. * SIGPROF is delivered upon expiration. * Timer values are defined by the following structures: * struct itimerval * { * struct timeval it_interval; //next value * struct timeval it_value; //current value * }; * struct timeval * { * long tv_sec; // seconds * long tv_usec; //microseconds * }; * The function getitimer() fills the structure indicated by value with the current setting for the timer * indicated by which (one of ITIMER_REAL, ITIMER_VIRTUAL, or ITIMER_PROF). The element it_value is * set to the amount of time remaining on the timer, or zero ifthe timer is disabled. * Similarly, it_interval is set to the reset value. The function setitimer() sets the indicated timer to the * value in value. If ovalue is nonzero, the old value of the timer is stored there. */ if (setitimer(ITIMER_REAL, &interval, NULL)) { log_error_write(srv, __FILE__, __LINE__, "s", "setting timer failed"); return -1; } getitimer(ITIMER_REAL, &interval); #endif #ifdef HAVE_FORK /* * ************************* * start watcher and workers * ************************* * * 下面程序将产生多个子进程。这些子进程成为worker,也就是用于接受处理用户的连接的进程。而当前的主进程将 * 成为watcher,主要工作就是监视workers的工作状态,当有worker因为意外而退出时,产生新的worker。 * 在程序退出时,watcher负责停止所有的workers并清理资源。 */ num_childs = srv->srvconf.max_worker;//最大worker数。 if (num_childs > 0) { int child = 0; while (!child && !srv_shutdown && !graceful_shutdown) { if (num_childs > 0) //继续产生worker { switch (fork()) { case -1: return -1; case 0: child = 1; break; default: num_childs--; break; } } else //watcher { /** * 当产生了足够的worker时,watcher就在这个while中不断的循环。 * 一但发现有worker退出(进程死亡),立即产生新的worker。 * 如果发生错误并接受到SIGHUP信号,向所有的进程(父进程及其子进程)包括自己发送SIGHUP信号。 * 并退出。 */ int status; if (-1 != wait(&status)) { /** * one of our workers went away */ num_childs++; } else { switch (errno) { case EINTR: /** * if we receive a SIGHUP we have to close our logs ourself as we don't * have the mainloop who can help us here */ if (handle_sig_hup) { handle_sig_hup = 0; log_error_cycle(srv); /** * forward to all procs in the process-group * 向所有进程发送SIGHUP信号。(父进程及其子进程) * we also send it ourself */ if (!forwarded_sig_hup) { forwarded_sig_hup = 1; kill(0, SIGHUP); } } break; default: break; } } } } /** * for the parent this is the exit-point * ***************************************************** * 父进程,也就是watcher在执行完这个if语句中就直接退出了。 * 后面是worker执行的代码。 * ***************************************************** */ if (!child) { /** * kill all children too 。杀死所有的子进程。 */ if (graceful_shutdown) { kill(0, SIGINT); } else if (srv_shutdown) { kill(0, SIGTERM); } log_error_close(srv); network_close(srv); connections_free(srv); plugins_free(srv); server_free(srv); return 0; } } #endif /* * ************************** * 从这开始是worker执行的代码。 * ************************** */ if (NULL == (srv->ev = fdevent_init(srv->max_fds + 1, srv->event_handler))) { log_error_write(srv, __FILE__, __LINE__, "s", "fdevent_init failed"); return -1; } /* * kqueue() is called here, select resets its internals, * all server sockets get their handlers * 将监听socket注册到fd events系统中。 * 在注册的时候为每个socket都同时注册了一个处理函数,用来处理这个socket的IO事件。 * 对于在这次调用中注册的监听socket,注册的处理函数是:network_server_handle_fdevent。 * 这个处理函数用来建立socket连接。 * */ if (0 != network_register_fdevents(srv)) { plugins_free(srv); network_close(srv); server_free(srv); return -1; } /* * might fail if user is using fam (not gamin) and famd isn't running * famd没有运行,则运行失败。。。 */ if (NULL == (srv->stat_cache = stat_cache_init())) { log_error_write(srv, __FILE__, __LINE__, "s", "stat-cache could not be setup, dieing."); return -1; } #ifdef HAVE_FAM_H /* * setup FAM 设置FAM。 */ if (srv->srvconf.stat_cache_engine == STAT_CACHE_ENGINE_FAM) { if (0 != FAMOpen2(srv->stat_cache->fam, "lighttpd")) { log_error_write(srv, __FILE__, __LINE__, "s", "could not open a fam connection, dieing."); return -1; } #ifdef HAVE_FAMNOEXISTS FAMNoExists(srv->stat_cache->fam); #endif srv->stat_cache->fam_fcce_ndx = -1; fdevent_register(srv->ev, FAMCONNECTION_GETFD(srv->stat_cache->fam), stat_cache_handle_fdevent, NULL); fdevent_event_add(srv->ev, &(srv->stat_cache->fam_fcce_ndx), FAMCONNECTION_GETFD(srv->stat_cache->fam), FDEVENT_IN); } #endif /* * get the current number of FDs 获得当前可用的fd值 */ srv->cur_fds = open("/dev/null", O_RDONLY); close(srv->cur_fds); for (i = 0; i < srv->srv_sockets.used; i++) { server_socket *srv_socket = srv->srv_sockets.ptr[i]; /* * close fd on exec (cgi) */ if (-1 == fdevent_fcntl_set(srv->ev, srv_socket->fd)) { log_error_write(srv, __FILE__, __LINE__, "ss", "fcntl failed:", strerror(errno)); return -1; } } /* * main-loop * ******************* * worker工作的主循环。 * ******************* */ while (!srv_shutdown) { int n; size_t ndx; time_t min_ts; /** * 收到SIGHUP信号。主要是重新开始日志的周期并提示插件。 * 这个信号表示连接已经断开,通常是做一些清理和准备工作,等待下一次的连接。 */ if (handle_sig_hup) { handler_t r; /* * reset notification 重置 */ handle_sig_hup = 0; /* * cycle logfiles * 重新开始新一轮日志。 * 这里使用了switch而不是if语句,有意思。。。 * 调用插件关于SIGHUP信号的处理函数。 * 这个函数貌似也没实现。。。 */ switch (r = plugins_call_handle_sighup(srv)) { case HANDLER_GO_ON: break; default: log_error_write(srv, __FILE__, __LINE__, "sd", "sighup-handler return with an error", r); break; } if (-1 == log_error_cycle(srv)) { log_error_write(srv, __FILE__, __LINE__, "s", "cycling errorlog failed, dying"); return -1; } else { #ifdef HAVE_SIGACTION log_error_write(srv, __FILE__, __LINE__, "sdsd", "logfiles cycled UID =", last_sighup_info.si_uid, "PID =", last_sighup_info.si_pid); #else log_error_write(srv, __FILE__, __LINE__, "s", "logfiles cycled"); #endif } } /** * alarm函数发出的信号,表示一秒钟已经过去了。 */ if (handle_sig_alarm) { /* * a new second 新的一秒开始了。。。 */ #ifdef USE_ALARM /* * reset notification 重置 */ handle_sig_alarm = 0; #endif /* * get current time 当前时间。精确到一秒 */ min_ts = time(NULL); /** * 这里判断和服务器记录的当前时间是否相同。 * 相同,则表示服务器还在这一秒中,继续处理请求等。 * 如果不相同,则进入了一个新的周期(当然周期是一秒)。这就要做一些触发和检查以及清理的动作。 * 如插件的触发连接的超时清理状态缓存等。 * 其中,最主要的工作是检查连接的超时。 */ if (min_ts != srv->cur_ts) { int cs = 0; connections *conns = srv->conns; handler_t r; switch (r = plugins_call_handle_trigger(srv)) { case HANDLER_GO_ON: break; case HANDLER_ERROR: log_error_write(srv, __FILE__, __LINE__, "s", "one of the triggers failed"); break; default: log_error_write(srv, __FILE__, __LINE__, "d", r); break; } /* * trigger waitpid 么意思?? */ srv->cur_ts = min_ts; /* * cleanup stat-cache 清理状态缓存。每秒钟清理一次。 */ stat_cache_trigger_cleanup(srv); /** * check all connections for timeouts 检查所有的连接是否超时。 */ for (ndx = 0; ndx < conns->used; ndx++) { int changed = 0; connection *con; int t_diff; con = conns->ptr[ndx]; //连接的状态是在读 if (con->state == CON_STATE_READ || con->state == CON_STATE_READ_POST) { if (con->request_count == 1) //连接正在处理一个请求 { if (srv->cur_ts - con->read_idle_ts > con->conf.max_read_idle) { /* * time - out */ #if 0 log_error_write(srv, __FILE__, __LINE__, "sd", "connection closed - read-timeout:", con->fd); #endif connection_set_state(srv, con, CON_STATE_ERROR); changed = 1; } } //这个连接同时处理多个请求 else { if (srv->cur_ts - con->read_idle_ts > con->conf.max_keep_alive_idle) { /* * time - out */ #if 0 log_error_write(srv, __FILE__, __LINE__, "sd", "connection closed - read-timeout:", con->fd); #endif connection_set_state(srv, con, CON_STATE_ERROR); changed = 1; } } } //连接的状态是写 if ((con->state == CON_STATE_WRITE) && (con->write_request_ts != 0)) { #if 0 if (srv->cur_ts - con->write_request_ts > 60) { log_error_write(srv, __FILE__, __LINE__, "sdd", "connection closed - pre-write-request-timeout:", con->fd, srv->cur_ts - con->write_request_ts); } #endif if (srv->cur_ts - con->write_request_ts > con->conf.max_write_idle) { /* * time - out */ #if 1 log_error_write(srv, __FILE__, __LINE__, "sbsosds", "NOTE: a request for", con->request.uri, "timed out after writing", con->bytes_written, "bytes. We waited", (int) con->conf. max_write_idle, "seconds. If this a problem increase server.max-write-idle"); #endif connection_set_state(srv, con, CON_STATE_ERROR); changed = 1; } } /* * we don't like div by zero 防止除0。。。 */ if (0 == (t_diff = srv->cur_ts - con->connection_start)) t_diff = 1; /** * 下面的if语句不是用来判断连接是否超时。 * lighttpd对每个连接设置了一个kbytes_per_second,这个变量设定每个连接在一秒钟内多能传输的最大数据量。 * 如果传送的数据大于这个值,那么这个连接将停止传输数据,被追加到作业队列中等待下一次处理。 * 作者这样做估计是为了平衡各个连接之间的数据传输。 */ if (con->traffic_limit_reached && (con->conf.kbytes_per_second == 0 || ((con->bytes_written / t_diff) < con->conf.kbytes_per_second * 1024))) { /* * enable connection again */ con->traffic_limit_reached = 0; changed = 1; } if (changed) { connection_state_machine(srv, con); } con->bytes_written_cur_second = 0; *(con->conf.global_bytes_per_second_cnt_ptr) = 0; #if 0 if (cs == 0) { fprintf(stderr, "connection-state: "); cs = 1; } fprintf(stderr, "c[%d,%d]: %s ", con->fd, con->fcgi.fd, connection_get_state(con->state)); #endif }//end of for( ndx = 0; ... if (cs == 1) fprintf(stderr, "\n"); }//end of if (min_ts != srv->cur_ts)... }//end of if (handle_sig_alarm)... if (srv->sockets_disabled) { /* * our server sockets are disabled, why ? * 服务器socket连接失效。为什么捏???后面的服务器过载处理中。。。 * * 将所有连接重新加入的fdevent中。 */ if ((srv->cur_fds + srv->want_fds < srv->max_fds * 0.8) && /* we have enough unused fds */ (srv->conns->used < srv->max_conns * 0.9) && (0 == graceful_shutdown)) { for (i = 0; i < srv->srv_sockets.used; i++) { server_socket *srv_socket = srv->srv_sockets.ptr[i]; fdevent_event_add(srv->ev, &(srv_socket->fde_ndx), srv_socket->fd, FDEVENT_IN); } log_error_write(srv, __FILE__, __LINE__, "s", "[note] sockets enabled again"); srv->sockets_disabled = 0; } } else { /* * 下面处理服务器过载的情况。 */ if ((srv->cur_fds + srv->want_fds > srv->max_fds * 0.9) || /* out of fds */ (srv->conns->used > srv->max_conns) || /* out of connections */ (graceful_shutdown)) /* graceful_shutdown */ { /* * disable server-fds 关闭所有的服务socket */ for (i = 0; i < srv->srv_sockets.used; i++) { server_socket *srv_socket = srv->srv_sockets.ptr[i]; fdevent_event_del(srv->ev, &(srv_socket->fde_ndx), srv_socket->fd); if (graceful_shutdown) { /* * we don't want this socket anymore, closing it right * away will make it possible for the next lighttpd to * take over (graceful restart) */ fdevent_unregister(srv->ev, srv_socket->fd); close(srv_socket->fd); srv_socket->fd = -1; /* * network_close() will cleanup after us */ if (srv->srvconf.pid_file->used && srv->srvconf.changeroot->used == 0) { if (0 != unlink(srv->srvconf.pid_file->ptr)) { if (errno != EACCES && errno != EPERM) { log_error_write(srv, __FILE__, __LINE__, "sbds", "unlink failed for:", srv -> srvconf.pid_file, errno, strerror(errno)); } } } } }//end of for(i = 0; ... if (graceful_shutdown) { log_error_write(srv, __FILE__, __LINE__, "s", "[note] graceful shutdown started"); } else if (srv->conns->used > srv->max_conns) { log_error_write(srv, __FILE__, __LINE__, "s","[note] sockets disabled, connection limit reached"); } else { log_error_write(srv, __FILE__, __LINE__, "s", "[note] sockets disabled, out-of-fds"); } srv->sockets_disabled = 1; //服务器过载了,socket失效。 } } if (graceful_shutdown && srv->conns->used == 0) { /* * we are in graceful shutdown phase and all connections are closed * we are ready to terminate without harming anyone */ srv_shutdown = 1; } /* * we still have some fds to share */ if (srv->want_fds) { /* * check the fdwaitqueue for waiting fds */ int free_fds = srv->max_fds - srv->cur_fds - 16; connection *con; for (; free_fds > 0 && NULL != (con = fdwaitqueue_unshift(srv, srv->fdwaitqueue)); free_fds--) { connection_state_machine(srv, con); srv->want_fds--; } } /** ********************************************************** * 至此,上面那些杂七杂八的事全部处理结束。下面,干正事!! * 也就是处理服务请求。 ********************************************************** */ //启动事件轮询。底层使用的是IO多路转接。 if ((n = fdevent_poll(srv->ev, 1000)) > 0) { /* * n is the number of events n是事件的数量(服务请求啦,文件读写啦什么的。。。) */ int revents; int fd_ndx; #if 0 if (n > 0) { log_error_write(srv, __FILE__, __LINE__, "sd", "polls:", n); } #endif fd_ndx = -1; /** * 这个循环中逐个的处理已经准备好的请求,知道所有的请求处理结束。 */ do { fdevent_handler handler; void *context; handler_t r; fd_ndx = fdevent_event_next_fdndx(srv->ev, fd_ndx); revents = fdevent_event_get_revent(srv->ev, fd_ndx); fd = fdevent_event_get_fd(srv->ev, fd_ndx); handler = fdevent_get_handler(srv->ev, fd); context = fdevent_get_context(srv->ev, fd); /* * connection_handle_fdevent needs a joblist_append */ #if 0 log_error_write(srv, __FILE__, __LINE__, "sdd", "event for", fd, revents); #endif /** * 这里,调用请求的处理函数handler处理请求! * 这才是重点中的重点!! */ switch (r = (*handler) (srv, context, revents)) { case HANDLER_FINISHED: case HANDLER_GO_ON: case HANDLER_WAIT_FOR_EVENT: case HANDLER_WAIT_FOR_FD: break; case HANDLER_ERROR: /* * should never happen */ SEGFAULT(); break; default: log_error_write(srv, __FILE__, __LINE__, "d", r); break; } }while (--n > 0); //到这里,本次的请求都处理结束了。。。累啊! } else if (n < 0 && errno != EINTR) { log_error_write(srv, __FILE__, __LINE__, "ss", "fdevent_poll failed:", strerror(errno)); } //由于上面处理的都是发生了IO事件的描述符,这些描述符的状态都被正确的设置了。 //对于没有发生IO事件的描述符,其状态机的状态也需要设置, //下面的循环就是对剩下的描述符进行处理。 for (ndx = 0; ndx < srv->joblist->used; ndx++) { connection *con = srv->joblist->ptr[ndx]; handler_t r; connection_state_machine(srv, con); switch (r = plugins_call_handle_joblist(srv, con)) { case HANDLER_FINISHED: case HANDLER_GO_ON: break; default: log_error_write(srv, __FILE__, __LINE__, "d", r); break; } con->in_joblist = 0; } srv->joblist->used = 0; } /* end of main loop */ /* * 主循环的结束 */ if (srv->srvconf.pid_file->used && srv->srvconf.changeroot->used == 0 && 0 == graceful_shutdown) { if (0 != unlink(srv->srvconf.pid_file->ptr)) { if (errno != EACCES && errno != EPERM) { log_error_write(srv, __FILE__, __LINE__, "sbds", "unlink failed for:", srv->srvconf.pid_file, errno, strerror(errno)); } } } #ifdef HAVE_SIGACTION log_error_write(srv, __FILE__, __LINE__, "sdsd", "server stopped by UID =", last_sigterm_info.si_uid,"PID =", last_sigterm_info.si_pid); #else log_error_write(srv, __FILE__, __LINE__, "s", "server stopped"); #endif /* * clean-up */ log_error_close(srv); network_close(srv); connections_free(srv); plugins_free(srv); server_free(srv); return 0; }
int main(int argc, char **argv) { char **client_env=NULL; char **client_argv=NULL; int rc; struct stat stat_buf; struct timeval tv; double test_start; test_params params; INIT_TEST_PARAMS(params); int test_fail = 0; char *tmp; int ns_nprocs; gettimeofday(&tv, NULL); test_start = tv.tv_sec + 1E-6*tv.tv_usec; /* smoke test */ if (PMIX_SUCCESS != 0) { TEST_ERROR(("ERROR IN COMPUTING CONSTANTS: PMIX_SUCCESS = %d", PMIX_SUCCESS)); exit(1); } TEST_VERBOSE(("Testing version %s", PMIx_Get_version())); parse_cmd(argc, argv, ¶ms); TEST_VERBOSE(("Start PMIx_lite smoke test (timeout is %d)", params.timeout)); /* set common argv and env */ client_env = pmix_argv_copy(environ); set_client_argv(¶ms, &client_argv); tmp = pmix_argv_join(client_argv, ' '); TEST_VERBOSE(("Executing test: %s", tmp)); free(tmp); /* verify executable */ if( 0 > ( rc = stat(params.binary, &stat_buf) ) ){ TEST_ERROR(("Cannot stat() executable \"%s\": %d: %s", params.binary, errno, strerror(errno))); FREE_TEST_PARAMS(params); return 0; } else if( !S_ISREG(stat_buf.st_mode) ){ TEST_ERROR(("Client executable \"%s\": is not a regular file", params.binary)); FREE_TEST_PARAMS(params); return 0; }else if( !(stat_buf.st_mode & S_IXUSR) ){ TEST_ERROR(("Client executable \"%s\": has no executable flag", params.binary)); FREE_TEST_PARAMS(params); return 0; } if (PMIX_SUCCESS != (rc = server_init(¶ms))) { FREE_TEST_PARAMS(params); return rc; } cli_init(params.lsize); int launched = 0; /* set namespaces and fork clients */ if (NULL == params.ns_dist) { uint32_t i; int base_rank = 0; /* compute my start counter */ for(i = 0; i < (uint32_t)my_server_id; i++) { base_rank += (params.nprocs % params.nservers) > (uint32_t)i ? params.nprocs / params.nservers + 1 : params.nprocs / params.nservers; } /* we have a single namespace for all clients */ ns_nprocs = params.nprocs; launched += server_launch_clients(params.lsize, params.nprocs, base_rank, ¶ms, &client_env, &client_argv); } else { char *pch; pch = strtok(params.ns_dist, ":"); while (NULL != pch) { ns_nprocs = (int)strtol(pch, NULL, 10); if (params.nprocs < (uint32_t)(launched+ns_nprocs)) { TEST_ERROR(("Total number of processes doesn't correspond number specified by ns_dist parameter.")); FREE_TEST_PARAMS(params); return PMIX_ERROR; } if (0 < ns_nprocs) { launched += server_launch_clients(ns_nprocs, ns_nprocs, 0, ¶ms, &client_env, &client_argv); } pch = strtok (NULL, ":"); } } if (params.lsize != (uint32_t)launched) { TEST_ERROR(("Total number of processes doesn't correspond number specified by ns_dist parameter.")); cli_kill_all(); test_fail = 1; } /* hang around until the client(s) finalize */ while (!test_terminated()) { // To avoid test hang we want to interrupt the loop each 0.1s double test_current; // check if we exceed the max time gettimeofday(&tv, NULL); test_current = tv.tv_sec + 1E-6*tv.tv_usec; if( (test_current - test_start) > params.timeout ){ break; } cli_wait_all(0); } if( !test_terminated() ){ TEST_ERROR(("Test exited by a timeout!")); cli_kill_all(); test_fail = 1; } if( test_abort ){ TEST_ERROR(("Test was aborted!")); /* do not simply kill the clients as that generates * event notifications which these tests then print * out, flooding the log */ // cli_kill_all(); test_fail = 1; } if (0 != params.test_spawn) { PMIX_WAIT_FOR_COMPLETION(spawn_wait); } /* deregister the errhandler */ PMIx_Deregister_event_handler(0, op_callbk, NULL); cli_wait_all(1.0); test_fail += server_finalize(¶ms); FREE_TEST_PARAMS(params); pmix_argv_free(client_argv); pmix_argv_free(client_env); return test_fail; }
int main(int argc, char *argv[]) { int opt, sortarcs = 1; char *infilename; struct fsm *net; setvbuf(stdout, buffer, _IOFBF, sizeof(buffer)); while ((opt = getopt(argc, argv, "abhHiI:qs:SA:P:w:vx")) != -1) { switch(opt) { case 'a': apply_alternates = 1; break; case 'b': buffered_output = 0; break; case 'h': printf("%s%s\n", usagestring,helpstring); exit(0); case 'i': direction = DIR_DOWN; applyer = &apply_down; break; case 'q': sortarcs = 0; break; case 'I': if (strcmp(optarg, "f") == 0) { index_flag_states = 1; index_arcs = 1; } else if (strcasestr(optarg, "k") != NULL) { /* k limit */ index_mem_limit = 1024*atoi(optarg); index_arcs = 1; } else if (strcasestr(optarg, "m") != NULL) { /* m limit */ index_mem_limit = 1024*1024*atoi(optarg); index_arcs = 1; } else if (isdigit(*optarg)) { index_arcs = 1; index_cutoff = atoi(optarg); } break; case 's': separator = strdup(optarg); break; case 'S': mode_server = 1; break; case 'A': server_address = strdup(optarg); break; case 'P': port_number = atoi(optarg); break; case 'w': wordseparator = strdup(optarg); break; case 'v': printf("flookup 1.02 (foma library version %s)\n", fsm_get_library_version_string()); exit(0); case 'x': echo = 0; break; default: fprintf(stderr, "%s", usagestring); exit(EXIT_FAILURE); } } if (optind == argc) { fprintf(stderr, "%s", usagestring); exit(EXIT_FAILURE); } infilename = argv[optind]; if ((fsrh = fsm_read_binary_file_multiple_init(infilename)) == NULL) { perror("File error"); exit(EXIT_FAILURE); } chain_head = chain_tail = NULL; while ((net = fsm_read_binary_file_multiple(fsrh)) != NULL) { numnets++; chain_new = xxmalloc(sizeof(struct lookup_chain)); if (direction == DIR_DOWN && net->arcs_sorted_in != 1 && sortarcs) { fsm_sort_arcs(net, 1); } if (direction == DIR_UP && net->arcs_sorted_out != 1 && sortarcs) { fsm_sort_arcs(net, 2); } chain_new->net = net; chain_new->ah = apply_init(net); if (direction == DIR_DOWN && index_arcs) { apply_index(chain_new->ah, APPLY_INDEX_INPUT, index_cutoff, index_mem_limit, index_flag_states); } if (direction == DIR_UP && index_arcs) { apply_index(chain_new->ah, APPLY_INDEX_OUTPUT, index_cutoff, index_mem_limit, index_flag_states); } chain_new->next = NULL; chain_new->prev = NULL; if (chain_tail == NULL) { chain_tail = chain_head = chain_new; } else if (direction == DIR_DOWN || apply_alternates == 1) { chain_tail->next = chain_new; chain_new->prev = chain_tail; chain_tail = chain_new; } else { chain_new->next = chain_head; chain_head->prev = chain_new; chain_head = chain_new; } } if (numnets < 1) { fprintf(stderr, "%s: %s\n", "File error", infilename); exit(EXIT_FAILURE); } if (mode_server) { server_init(); serverstring = xxcalloc(UDP_MAX+1, sizeof(char)); line = xxcalloc(UDP_MAX+1, sizeof(char)); addrlen = sizeof(clientaddr); for (;;) { numbytes = recvfrom(listen_sd, line, UDP_MAX, 0,(struct sockaddr *)&clientaddr, &addrlen); if (numbytes == -1) { perror("recvfrom() failed, aborting"); break; } line[numbytes] = '\0'; line[strcspn(line, "\n\r")] = '\0'; fflush(stdout); results = 0; udpsize = 0; serverstring[0] = '\0'; handle_line(line); if (results == 0) { app_print(NULL); } if (serverstring[0] != '\0') { numbytes = sendto(listen_sd, serverstring, strlen(serverstring), 0, (struct sockaddr *)&clientaddr, addrlen); if (numbytes < 0) { perror("sendto() failed"); fflush(stdout); } } } } else { /* Standard read from stdin */ line = xxcalloc(LINE_LIMIT, sizeof(char)); INFILE = stdin; while (get_next_line() != NULL) { results = 0; handle_line(line); if (results == 0) { app_print(NULL); } fprintf(stdout, "%s", wordseparator); if (!buffered_output) { fflush(stdout); } } } /* Cleanup */ for (chain_pos = chain_head; chain_pos != NULL; chain_pos = chain_head) { chain_head = chain_pos->next; if (chain_pos->ah != NULL) { apply_clear(chain_pos->ah); } if (chain_pos->net != NULL) { fsm_destroy(chain_pos->net); } xxfree(chain_pos); } if (serverstring != NULL) xxfree(serverstring); if (line != NULL) xxfree(line); exit(0); }
main (int argc, char **argv) { int sock; int i; spy_t spy; int repetition = 100; int resp_size = 4971; int ch; int become_server = 0; while ((ch = getopt(argc, argv, "sn:b:")) != EOF) { switch (ch) { case 's': become_server = 1; break; case 'b': resp_size = atoi(optarg); break; case 'n': repetition = atoi(optarg); break; default: usage(); } } if (become_server) { int sockbufsize = 4096; struct sockaddr_in sin_client; char buf[1024]; char *send_buf = malloc(resp_size); int main_sock, sock; int n; main_sock = server_init(); for (;;) { int sinlen = sizeof(sin_client); sock = accept(main_sock, (struct sockaddr *)&sin_client, &sinlen); if (sock < 0) { perror("accept"); exit(1); } if (setsockopt(sock, SOL_SOCKET, SO_SNDBUF, (void *) &sockbufsize, sizeof(sockbufsize)) < 0) { perror("setsockopt"); } if (fcntl(sock, F_SETFL, O_NDELAY) < 0) { perror("fcntl"); } n = read(sock, buf, sizeof buf); if (n > 0) { if (write(sock, send_buf, 4096) < 4096) { perror("write"); exit(1); } if (write(sock, send_buf, 4971-4096) < 4971-4096) { perror("write2"); exit(1); } } close(sock); } } else { char x = ' '; char *host = argv[optind]; char *port = argv[optind+1]; if (host == 0 || port == 0) usage(); client_init(host, port); printf("connected to %s:%s\n", host, port); spy = spy_create("client", repetition); for (i = 0; i < repetition; i++) { int j, n; char send_msg[80]; char *recv_msg = malloc(resp_size); for (j = 0; j < 78; j++) { send_msg[j] = x++; if (x >= 0x7f) x = ' '; } send_msg[j++] = '\n'; send_msg[j++] = '\0'; spy_start(spy); sock = client_connect(); n = write(sock, send_msg, j); if (n < j) { perror("write"); exit(1); } { int k = resp_size; while (k > 0) { n = read(sock, recv_msg + resp_size-k, k); if (n == 0) break; if (n < 0) { perror("read"); exit(1); } k -= n; } } close(sock); spy_stop(spy); /* if (strcmp(send_msg, recv_msg)) { printf("msg mismatch : \n%s\n%s\n", send_msg, recv_msg); exit(1); }*/ } } spy_set_display_mode(SPY_MICROSEC_ONLY); spy_dump_all(); }
int main(int argc,char **argv) { server *srv=NULL; //step 1 : initialize server if( (srv= server_init()) ==NULL){ fprintf(stderr,"failed to initialize server in [%s|%d|%s]\n",__FILE__,__LINE__,__FUNCTION__); return -1; } //step 2 : parameter parse char opt_chr; while( (opt_chr=getopt(argc,argv,"f:hvD"))!=-1 ){ switch(opt_chr){ /*configuration file path */ case 'f':{ buffer_copy_string(srv->config->minihttpd_global_config_filepath,optarg); break; } /* show help */ case 'h':{ print_help(); server_free(srv); return 0; } case 'v':{ fprintf(stdout,"%s-%s",srv->config->service_name->ptr,srv->config->version_info->ptr); server_free(srv); return 0; } case 'D':{ srv->dont_daemonize=1; break; } default:{ print_help(); server_free(srv); return -1; } } } //step 3 :check if all configuraiton is legal if(buffer_is_empty(srv->config->service_root_dir)){ fprintf(stderr,"[%s|%d|%s]:please specify minihttp root dir in configuration file\n", __FILE__,__LINE__,__FUNCTION__); server_free(srv); return -1; } /*parse the mime configuration file */ if(buffer_is_empty(srv->config->mimetype_filepath) || (srv->config->table= mime_table_initialize( (const char*)srv->config->mimetype_filepath->ptr) )==NULL){ fprintf(stderr,"invalid mime configuration file is specified,pls check it..\n"); server_free(srv); return -1; } //step4 :server started srv->uid=getuid(); srv->gid=getgid(); if(srv->uid==0) { //we are root struct rlimit res_limit; if(getrlimit(RLIMIT_NOFILE,&res_limit)!=0){ fprintf(stderr,"[%s|%d|%s]: failed to get file descriptor max number for current process!\n", __FILE__,__LINE__,__FUNCTION__); server_free(srv); return -1; } res_limit.rlim_cur=srv->config->max_fd; res_limit.rlim_max=srv->config->max_fd; if(setrlimit(RLIMIT_NOFILE,&res_limit)!=0){ fprintf(stderr,"[%s|%d|%s]: failed call setrlimit(RLIMIT_NOFILE,) for current process!\n", __FILE__,__LINE__,__FUNCTION__); server_free(srv); return -1; } }else{ struct rlimit res_limit; if(getrlimit(RLIMIT_NOFILE,&res_limit)!=0){ fprintf(stderr,"[%s|%d|%s]: failed to get file descriptor max number for current process!\n", __FILE__,__LINE__,__FUNCTION__); server_free(srv); return -1; } if(srv->config->max_fd< res_limit.rlim_cur) res_limit.rlim_cur=srv->config->max_fd; else if(srv->config->max_fd<=res_limit.rlim_max) res_limit.rlim_cur=srv->config->max_fd; if(setrlimit(RLIMIT_NOFILE,&res_limit)!=0){ fprintf(stderr,"[%s|%d|%s]: failed call setrlimit(RLIMIT_NOFILE,) for current process!\n", __FILE__,__LINE__,__FUNCTION__); server_free(srv); return -1; } } //step 5: become a daemon process if dont_daemonize=0; if(!srv->dont_daemonize){ daemonize((const char*)srv->config->service_name->ptr); } //step 6: open log file for error log, by default we use syslog. // if the minihttpd log filepath is specified manually or server dont_daemonize=1, // we set mode = LOG_MODE_FILE; if(!buffer_is_empty(srv->config->log_filename) || srv->dont_daemonize ){ if(buffer_is_empty(srv->config->log_filename)) buffer_copy_string(srv->config->log_filename,MINIHTTPD_DEFAULT_LOG_FILEPATH); srv->log_fd= open((const char*)srv->config->log_filename->ptr,O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH); if(srv->log_fd<0){ server_free(srv); return -1; } fd_close_on_exec(srv->log_fd); srv->mode=server::LOG_MODE_FILE; } log_to_backend(srv,MINIHTTPD_LOG_LEVEL_INFO,"%s is start now...",(const char*)srv->config->service_name->ptr); //step 7 : create listening tcp socket(we only support ipv4 now) struct sockaddr_in * addr= (struct sockaddr_in*)&srv->server_addr; memset(addr,0,sizeof(*addr)); addr->sin_family=AF_INET; addr->sin_addr.s_addr=htonl(INADDR_ANY); addr->sin_port=htons(srv->config->listenint_port); srv->listening_socket_fd= create_tcp_socket((struct sockaddr*)addr,srv->config->max_listening_number); if(srv->listening_socket_fd<0){ log_to_backend(srv, MINIHTTPD_LOG_LEVEL_ERROR,"failed to create listening tcp socket on port:%d", srv->config->listenint_port); server_free(srv); return -1; } /* step 8: setup signal handler signo: SIGCHLD signo: SIGPIPE: unix domain socket pipe is broken signo: SIGINT: user intend to shutdown the minihttpd server if SIGINT is kill to the server proces for twice, the minihtpd server is going to shutdown signo: SIGTERM: exit minihttpd service now */ struct sigaction act; sigemptyset(&act.sa_mask); act.sa_flags=0; act.sa_handler=signal_handler; sigaction(SIGPIPE,&act,NULL); sigaction(SIGCHLD,&act,NULL); sigaction(SIGINT,&act,NULL); sigaction(SIGTERM,&act,NULL); /* step 9: fork worker child process and transfter accept socket file descriptor to worker process the only tasks for main processis : 1) to call accept to wait for connection and pick one worker process to handle the connection 2) wait all worker process to finish before exit. */ for(uint32_t worker_process_id=0;worker_process_id< srv->worker_number ;worker_process_id++) { server_child * child= &srv->child[worker_process_id]; //create unix domain socket if(socketpair(AF_UNIX,SOCK_STREAM,0,child->unix_domain_socket_fd)<0){ log_to_backend(srv,MINIHTTPD_LOG_LEVEL_ERROR,"failed to create unix domain socket for worker%d", worker_process_id); close(srv->listening_socket_fd); server_free(srv); return -1; } child->sent_connection_number=0; int unix_domain_socket_child_fd=child->unix_domain_socket_fd[1]; fd_set_nonblocking(unix_domain_socket_child_fd); child->pid=fork(); if(child->pid <0){ //we can not fork worker process, this should not be happened close(srv->listening_socket_fd); server_free(srv) ; return -1; } else if(child->pid ==0) { /* worker process */ /*we should use p_worker only in the child worker process */ #if 0 minihttpd_running_log(srv->log_fd,MINIHTTPD_LOG_LEVEL_INFO,__FILE__,__LINE__,__FUNCTION__, "worker(pid=%d) is starting.....",getpid()); #endif worker * server_worker = (worker*)malloc(sizeof(worker)); memset(server_worker,0,sizeof(worker)); server_worker->worker_id= worker_process_id; server_worker->unix_domain_socekt_fd=unix_domain_socket_child_fd; server_worker->log_filepath=buffer_init(); server_worker->global_config= srv->config; /*step1 : get current file descriptor max number (it should be same as parent process which we have set the resouces)*/ struct rlimit limit; if(getrlimit(RLIMIT_NOFILE,&limit)<0){ exit(-1); // terminated the worker } //close unnecessary file descriptor for(uint32_t file_descriptor_index=0;file_descriptor_index< limit.rlim_cur;file_descriptor_index++){ if(file_descriptor_index> STDERR_FILENO && file_descriptor_index != unix_domain_socket_child_fd){ close(file_descriptor_index); } } //step 2: set event handler server_worker->ev= fdevent_initialize(limit.rlim_cur); /*support max connection number */ uint32_t worker_support_max_connections=limit.rlim_cur/2; worker_connection_initialize(server_worker, worker_support_max_connections); //step 3 : register unix domain socket event fdevents_register_fd(server_worker->ev,server_worker->unix_domain_socekt_fd, unix_domain_socket_handle,server_worker); //EPOLLHUP |EPOLLERR events is set by default fdevents_set_events(server_worker->ev,server_worker->unix_domain_socekt_fd,EPOLLIN); //step 4 : open log file for worker to log debug/info/warning/error if(buffer_is_empty(server_worker->log_filepath)){ char worker_log_filepath[255]; snprintf(worker_log_filepath,sizeof(worker_log_filepath), MINIHTTPD_WORKER_CONFIG_PATH"%u.log", server_worker->worker_id ); buffer_append_string(server_worker->log_filepath,worker_log_filepath); } server_worker->log_fd= open((const char*)server_worker->log_filepath->ptr, O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH); if(server_worker->log_fd<0){ exit(-2); } //step 5 : setup timer and expect timer will expire with internal 1 seconds time(&server_worker->cur_ts); int timer_fd=timerfd_create(CLOCK_REALTIME,TFD_NONBLOCK); struct itimerspec timer_spec; timer_spec.it_value.tv_sec=1; timer_spec.it_value.tv_nsec=0; timer_spec.it_interval.tv_sec=1; timer_spec.it_interval.tv_nsec=0; timerfd_settime(timer_fd,0,&timer_spec,NULL); // setup timer experation events handler fdevents_register_fd(server_worker->ev, timer_fd,worker_timer_expire_handler, server_worker); fdevents_set_events(server_worker->ev,timer_fd,EPOLLIN); /* main loop for worker: epoll event loop for unix domain socket and connections */ while(server_shutdown==0 || server_worker->cur_connection_number >0 ) { int n=epoll_wait(server_worker->ev->epoll_fd, server_worker->ev->epoll_events, server_worker->ev->max_epoll_events,-1); if(n<0 ){ if(errno!=EINTR){ minihttpd_running_log(server_worker->log_fd,MINIHTTPD_LOG_LEVEL_ERROR ,__FILE__,__LINE__,__FUNCTION__, "failed to call epoll with errno=%d",errno); } continue; } else if(n==0){ //we should not get to here continue; }else { for(uint32_t event_index=0;event_index<n;event_index++){ struct epoll_event * event= &server_worker->ev->epoll_events[event_index]; assert(event!=NULL); int connection_socket_fd= event->data.fd; event_handle handler=fdevents_get_handle(server_worker->ev,connection_socket_fd); void * event_ctx=fdevents_get_context(server_worker->ev, connection_socket_fd); assert(handler!=NULL); int handle_status= handler(connection_socket_fd,event_ctx,event->events); minihttpd_running_log(server_worker->log_fd,handle_status==0? MINIHTTPD_LOG_LEVEL_INFO:MINIHTTPD_LOG_LEVEL_ERROR, __FILE__,__LINE__,__FUNCTION__,"the epoll event is already handled!"); } } } minihttpd_running_log(server_worker->log_fd,MINIHTTPD_LOG_LEVEL_INFO, __FILE__,__LINE__,__FUNCTION__,"child worker process has finished all client requests!\n"); /*free all connections */ worker_free_connectons(server_worker); /* unregister timer file descriptor */ fdevents_unset_event(server_worker->ev,timer_fd); fdevents_unregister_fd(server_worker->ev,timer_fd); close(timer_fd); /* unregister unix domain socket hanlde events and handler context */ fdevents_unset_event(server_worker->ev,server_worker->unix_domain_socekt_fd); fdevents_unregister_fd(server_worker->ev,server_worker->unix_domain_socekt_fd); close(server_worker->unix_domain_socekt_fd); /* free fevents resources */ close(server_worker->ev->epoll_fd); fdevent_free(server_worker->ev); //close the log file close(server_worker->log_fd); buffer_free(server_worker->log_filepath); /* free worker */ free( (void*) server_worker); exit(0); //termianted the worker } //close the unix domain socket worker file descriptor; close(child->unix_domain_socket_fd[1]); // child worker is running child->worker_running=1; //parent process log_to_backend(srv,MINIHTTPD_LOG_LEVEL_INFO,"worker process %d is already created!",worker_process_id); } //main loop to accept client connection and re-transfter to worker process while(!server_shutdown) { /* log signal events after signal si handled by signal handler */ if(signal_pipe_handled){ /* if unix domain socket pipe is broken and we still write data to the pipe */ } if(signal_child_handled){ /*a child worker process has terminated */ int worker_exit_status; pid_t exit_worker_pid; while( (exit_worker_pid= waitpid(-1,&worker_exit_status,WNOHANG))>0){ if(WIFEXITED(worker_exit_status)){ log_to_backend(srv,MINIHTTPD_LOG_LEVEL_ERROR,"worker child process(pid=%d) has exited normally with exit" \ "status=%d",exit_worker_pid,WEXITSTATUS(worker_exit_status)); } else if(WIFSIGNALED(worker_exit_status)){ log_to_backend(srv,MINIHTTPD_LOG_LEVEL_ERROR,"worker child process(pid=%d) is killed by signal(%d)", exit_worker_pid,WTERMSIG(worker_exit_status)) } else{ log_to_backend(srv,MINIHTTPD_LOG_LEVEL_ERROR,"worker child process(pid=%d) has exited unexpected", exit_worker_pid); } //remove the worker from available worker list and do not send socket file descriptor to it for(uint32_t child_worker_id=0;child_worker_id< srv->worker_number;child_worker_id++){ if(srv->child[child_worker_id].pid==exit_worker_pid) srv->child[child_worker_id].worker_running=0; } } signal_child_handled=0; } //we block here to wait connection(only IPV4 is supported now ) struct sockaddr_in client_addr; socklen_t client_addr_length=sizeof(client_addr); int connection_fd =accept(srv->listening_socket_fd,(struct sockaddr*)&client_addr,(socklen_t*)& client_addr_length); if(connection_fd<0){ switch(errno){ case EINTR: // the connection is reset by client case ECONNABORTED: continue; case EMFILE: //file descriptor is all used now, need to send file descriptor to worker soon break; default: { log_to_backend(srv,MINIHTTPD_LOG_LEVEL_ERROR,"failed to call accept() with errno=%d\n",errno); break; } } } else{ /* pick up a worker process and send the @conneciton_fd to it the pick algorithm is round-robin,; but for the draft version, we just pick a worker that we has sent the min connections */ log_to_backend(srv,MINIHTTPD_LOG_LEVEL_INFO,"client connection is accepted,pick a worker to handle it."); uint32_t pick_worker_index= srv->worker_number; uint32_t min_sent_connections=0xFFFFFFFF; for(uint32_t worker_process_id=0; worker_process_id<srv->worker_number;worker_process_id++){ if(srv->child[worker_process_id].sent_connection_number < min_sent_connections && srv->child[worker_process_id].worker_running) { min_sent_connections= srv->child[worker_process_id].sent_connection_number; pick_worker_index= worker_process_id; } } if(pick_worker_index>= srv->worker_number){ /* we can not handle it as all child worker has exited...*/ close(connection_fd); continue; } /*set file descriptor to nonblocking and set close_on_exec flag*/ fd_set_nonblocking(connection_fd); fd_close_on_exec(connection_fd); if(unix_domain_socket_sendfd(srv->child[pick_worker_index].unix_domain_socket_fd[0], connection_fd)<0){ log_to_backend(srv,MINIHTTPD_LOG_LEVEL_ERROR,"failed to send the connection file descriptor to worker!"); close(connection_fd); //just close it to tell the client,we can not handle it now. continue; } srv->child[pick_worker_index].sent_connection_number++; //close the file descriptor as it is already marked in flight close(connection_fd); } }
void user_init(void) { uart_set_baud(0, 921600); printf("\n\nESP8266 UMAC\n\n"); bridge_init(); umac_cfg um_cfg = { .timer_fn = umac_impl_request_future_tick, .cancel_timer_fn = umac_impl_cancel_future_tick, .now_fn = umac_impl_now_tick, .tx_byte_fn = umac_impl_tx_byte, .tx_buf_fn = umac_impl_tx_buf, .rx_pkt_fn = umac_impl_rx_pkt, .rx_pkt_ack_fn = bridge_pkt_acked, .timeout_fn = bridge_timeout, .nonprotocol_data_fn = NULL }; umac_init(&um, &um_cfg, rx_buf); um_tim_hdl = xTimerCreate( (signed char *)"umac_tim", 10, false, (void *)um_tim_id, um_tim_cb); char ap_cred[128]; struct sdk_station_config config; bool setup_ap = true; systask_init(); device_id = 0; fs_init(); if (fs_mount() >= 0) { #if 0 spiffs_DIR d; struct spiffs_dirent e; struct spiffs_dirent *pe = &e; fs_opendir("/", &d); while ((pe = fs_readdir(&d, pe))) { printf("%s [%04x] size:%i\n", pe->name, pe->obj_id, pe->size); } fs_closedir(&d); #endif // read preferred ssid spiffs_file fd_ssid = fs_open(".ssid", SPIFFS_RDONLY, 0); if (fd_ssid > 0) { if (fs_read(fd_ssid, (uint8_t *)ap_cred, sizeof(ap_cred)) > 0) { fs_close(fd_ssid); char *nl_ix = strchr(ap_cred, '\n'); if (nl_ix > 0) { memset(&config, 0, sizeof(struct sdk_station_config)); strncpy((char *)&config.ssid, ap_cred, nl_ix - ap_cred); char *nl_ix2 = strchr(nl_ix + 1, '\n'); if (nl_ix2 > 0) { strncpy((char *)&config.password, nl_ix + 1, nl_ix2 - (nl_ix + 1)); setup_ap = false; } } printf("ssid:%s\n", config.ssid); } // if read else { printf("could not read .ssid\n"); } } // if fs_ssid else { printf("no .ssid found, running softAP\n"); } // find device id or create one spiffs_file fd_devid = fs_open(".devid", SPIFFS_RDONLY, 0); if (fd_devid < 0) { device_id = hwrand(); fd_devid = fs_open(".devid", SPIFFS_O_CREAT | SPIFFS_O_TRUNC | SPIFFS_O_WRONLY | SPIFFS_O_APPEND, 0); fs_write(fd_devid, &device_id, 4); printf("create devid\n"); } else { fs_read(fd_devid, &device_id, 4); } fs_close(fd_devid); printf("devid %08x\n", device_id); // remove previous scan results fs_remove(SYSTASK_AP_SCAN_FILENAME); } // if mount if (setup_ap) { sdk_wifi_set_opmode(SOFTAP_MODE); struct ip_info ap_ip; IP4_ADDR(&ap_ip.ip, 192, 169, 1, 1); IP4_ADDR(&ap_ip.gw, 0, 0, 0, 0); IP4_ADDR(&ap_ip.netmask, 255, 255, 255, 0); sdk_wifi_set_ip_info(1, &ap_ip); struct sdk_softap_config ap_cfg = { .ssid = "WISLEEP", .password = "", .ssid_len = 7, .channel = 1, .authmode = AUTH_OPEN, .ssid_hidden = false, .max_connection = 255, .beacon_interval = 100 }; sdk_wifi_softap_set_config(&ap_cfg); ip_addr_t first_client_ip; IP4_ADDR(&first_client_ip, 192, 169, 1, 100); dhcpserver_start(&first_client_ip, 4); } else { // required to call wifi_set_opmode before station_set_config sdk_wifi_set_opmode(STATION_MODE); sdk_wifi_station_set_config(&config); } server_init(server_actions); um_mutex = xSemaphoreCreateMutex(); xTaskCreate(uart_task, (signed char * )"uart_task", 512, NULL, 2, NULL); xTaskCreate(server_task, (signed char *)"server_task", 1024, NULL, 2, NULL); }
/* run server */ void run_server (struct state *st, int cl_num_need, char *s_server_port) { int sfd; /* file descriptor of the socket */ struct sockaddr_storage peer_addr; /* address you receive a message from */ socklen_t peer_addr_len = sizeof(struct sockaddr_storage); ssize_t nread; uint8_t buf[MSG_BUF_SIZE]; /* message buffer */ int ret_code; /* code returned by a function */ if ((ret_code = server_init (&sfd, s_server_port)) != 0) { perror("Failed to initialize networking"); return; } /* non-blocking mode */ fcntl(sfd, F_SETFL, O_NONBLOCK); int cl_num = 0; struct client_record cl[MAX_CLIENT]; enum server_mode mode = server_mode_lobby; int finished = 0; int k=0; while( !finished ) { if (time_to_redraw) { switch(mode){ case server_mode_lobby: /* Lobby */ nread = recvfrom(sfd, buf, MSG_BUF_SIZE-1, 0, (struct sockaddr *) &peer_addr, &peer_addr_len); /* try to add a new client */ if ( server_get_msg(buf, nread) > 0 ) { int i; int found = 0; for(i=0; i<cl_num; ++i) { found = found || sa_match(&peer_addr, &cl[i].sa); } if (!found && cl_num < cl_num_need) { /* add the new client */ cl[cl_num].name = "Jim"; cl[cl_num].id = cl_num; cl[cl_num].pl = cl_num + 1; /* must be non-zero */ cl[cl_num].sa = peer_addr; addstr("!"); refresh(); cl_num++; } if (cl_num >= cl_num_need) { mode = server_mode_play; cl_num = cl_num_need; } } break; case server_mode_play: /* Game */ k++; if (k>=1600) k=0; int slowdown = game_slowdown(st->speed); if (k % slowdown == 0 && st->speed != sp_pause) { kings_move(st); simulate(st); server_send_msg_s_state(sfd, cl, cl_num, st); } nread = recvfrom(sfd, buf, MSG_BUF_SIZE-1, 0, (struct sockaddr *) &peer_addr, &peer_addr_len); if (nread != -1) { int found_i = -1; int i; for(i=0; i<cl_num; ++i) { if (sa_match(&peer_addr, &cl[i].sa)) found_i = i; } if (found_i>-1) { int msg = server_process_msg_c(buf, nread, st, cl[found_i].pl); if (msg == MSG_C_IS_ALIVE) addstr("."); else addstr("+"); refresh(); } } break; } time_to_redraw = 0; } finished = update_from_input_server(st); pause(); } close(sfd); }
int main(int argc, char **argv) { const char *ptr; int server_mode = -1; int i; int rc = 0; FILE *xmlf; #if !defined(HPUX) setlinebuf(stdout); #endif ptr = strrchr(argv[0], '/'); if (ptr == NULL) { strncpy(prog_name, argv[0], PROG_NAME_LEN); } else { strncpy(prog_name, ptr + 1, PROG_NAME_LEN); } pagesize = getpagesize(); printf("pagesize = %d\n", pagesize); cache_line_size = OPT_CACHE_LINE_EST; #ifdef TBB_KINFO int kinfo_fd = 0; #endif /* TBB_KINFO */ #ifdef TBB_KINFO if (options.kinfo) { kinfo_fd = pre_kinfo_init(); } #endif /* TBB_KINFO */ init_print_time(&tnow, &tprev); /* must happen before processing arguments */ options_set(); /* Process command line arguments */ process_args(argc, argv); /* Check for conflicts in the specified cmd line options */ check_options(); printf("INIT START\n"); num_idle = maxconns; printf("main: num_idle = %d\n", num_idle); printf("main: maxconns = %d\n", maxconns); printf("main: max_fds = %d\n", max_fds); #ifdef DEBUG_ON printf("Debugging is on debugging messages mask = 0x%x\n", MSG_MASK); #else printf("Compiled without debugging\n"); #endif /* DEBUG_ON */ if (options.use_socket_aio) { // for now leave some room for a few open files and // a few listening sockets (unfortunately we need to call this before // we know how many listening sockets there will be // max_sock_sd = maxconns + 20; // For now we just pick a value that _SHOULD_ avoid // collisions with future tests. // Note that if there were sd/fd collisions things // _should_ likely work just fine but this may // make finding problems easier - since there is // potential to control which range of values the // underlying aio layer is returning. #ifdef HAVE_AIO_LAYER /* These are just estimates !!! */ int aio_lowest_sock_sd = OPT_AIO_LOWEST_SD; int aio_highest_sock_sd = (maxconns + aio_lowest_sock_sd - 1) + OPT_AIO_MAX_LISTENERS; max_sock_sd = aio_highest_sock_sd; if (max_sock_sd > max_fds) { printf("main: max_sock_sd = %d > max_fds = %d\n", max_sock_sd, max_fds); exit(1); } printf("main: aio_lowest_sock_sd = %d\n", aio_lowest_sock_sd); printf("main: aio_highest_sock_sd = %d\n", aio_highest_sock_sd); PRINT_TIME(NOFD, &tnow, &tprev, "main: calling aio_sock_init with " "max_sock_sd = %d", max_sock_sd); rc = aio_sock_init(aio_lowest_sock_sd, aio_highest_sock_sd); if (rc < 0) { printf("main: aio_sock_init failed rc = %d\n", rc); exit(1); } #endif /* HAVE_AIO_LAYER */ } else { max_sock_sd = max_fds; } printf("main: max_sock_sd = %d\n", max_sock_sd); printf("main: FD_SETSIZE = %d\n", FD_SETSIZE); printf("main: sizeof(fd_set) = %d\n", (int) sizeof(fd_set)); #ifdef TBB_KINFO if (options.kinfo) { kinfo_fd = pre_kinfo_init(); } #endif /* TBB_KINFO */ rc = info_init(); info_listener_init(); /* must happen after processing arguments */ init_app_queues(); create_pidfile(); options_valid(); options_print(); xmlf = fopen("options.xml", "w"); if (!xmlf) { printf("main: failed to create options.xml\n"); exit(1); } options_print_xml(xmlf); fclose(xmlf); #ifndef AIO_WORKAROUND_BUGS print_extra_info(); #endif /* AIO_WORKAROUND_BUGS */ #ifdef HAVE_NETSTAT netstat_init(); #endif /* HAVE_NETSTAT */ sock_special_init(); /* initialize the event dispatch mechanism */ if (options.use_poll) { PRINT_TIME(NOFD, &tnow, &tprev, "userver: calling poll_loop_init"); poll_loop_init(); #ifdef HAVE_EPOLL } else if (options.use_epoll || options.use_epoll2) { PRINT_TIME(NOFD, &tnow, &tprev, "userver: calling epoll_loop_init"); epoll_loop_init(); #endif /* HAVE_EPOLL */ #ifdef HAVE_AIO_LAYER } else if (options.use_socket_aio) { PRINT_TIME(NOFD, &tnow, &tprev, "userver: calling aio_loop_init"); aio_loop_init(); #endif /* HAVE_AIO_LAYER */ } else if (!options.send_loop) { assert(options.send_loop == 0); PRINT_TIME(NOFD, &tnow, &tprev, "userver: calling select_loop_init"); select_loop_init(); } else { #ifdef SEND assert(options.send_loop == 1); PRINT_TIME(NOFD, &tnow, &tprev, "userver: calling send_loop_init"); send_loop_init(); #endif } switch (options.get_connections) { case OPT_CONN_WITH_SELECT_POLL_EPOLL: server_mode = LISTENER_NOT_ASYNC_INIT; break; #ifdef SEND case OPT_CONN_WITH_SEND_SELECT: server_mode = LISTENER_NOT_ASYNC_INIT | LISTENER_SEND_INIT; break; #endif /* SEND */ case OPT_CONN_WITH_SIGIO: server_mode = LISTENER_DO_ASYNC_INIT; break; case OPT_CONN_WITH_SEND_EVTS: server_mode = LISTENER_SEND_INIT; break; case OPT_CONN_WITH_AIO_ACCEPT: server_mode = LISTENER_AIO_INIT; break; default: printf("%s: options.get_connections = %d not handled\n", argv[0], options.get_connections); exit(1); break; } /* switch */ printf("Calling server_init with mode = 0x%x = %d\n", server_mode, server_mode); server_init(server_mode); for (i = sock_listener_min; i <= sock_listener_max; i++) { if (sock_is_listener(i)) { printf("listen_sd = %d\n", i); if (i > max_sd) { max_sd = i; } } } switch (options.process_sds_order) { case OPT_PROCESS_SDS_LRU: lru_copy_init(); break; case OPT_PROCESS_SDS_LIFO: q_init(max_fds + 1); if (options.get_connections == OPT_CONN_WITH_SELECT_POLL_EPOLL) { for (i = sock_listener_min; i <= sock_listener_max; i++) { if (sock_is_listener(i)) { q_add_to_front(i); } } } break; case OPT_PROCESS_SDS_FIFO: q_init(max_fds + 1); if (options.get_connections == OPT_CONN_WITH_SELECT_POLL_EPOLL) { for (i = sock_listener_min; i <= sock_listener_max; i++) { if (sock_is_listener(i)) { q_add_to_rear(i); } } } break; default: /* do nothing */ break; } if (options.caching_on) { initCache(options.cache_table_size, options.cache_max_bytes, options.cache_max_file_size, options.cache_max_load_factor, options.cache_lock_pages); #ifdef CACHE_MAPPED_NEW if (options.cache_warm) { cache_warm(options.cache_warm_file, (options.doc_root[0] != '\0') ? options.doc_root : NULL, options.cache_table_print); } #endif } rusage_init(); fork_servers(numprocs); return 0; }
int main(int argc, char *argv[]) { /* Scratch variables... */ int c; pid_t oldpid; size_t i; struct sigaction action; #ifdef HAVE_GETPWNAM struct passwd *pwd = NULL; #endif /* HAVE_GETPWNAM */ /* For initialising the address info structures */ /* static so it can get very big without overflowing the stack */ static struct addrinfo hints[MAX_INTERFACES]; static const char *nodes[MAX_INTERFACES]; const char *udp_port = 0; const char *tcp_port = 0; const char *configfile = CONFIGFILE; char* argv0 = (argv0 = strrchr(argv[0], '/')) ? argv0 + 1 : argv[0]; log_init(argv0); /* Initialize the server handler... */ memset(&nsd, 0, sizeof(struct nsd)); nsd.region = region_create(xalloc, free); nsd.dbfile = 0; nsd.pidfile = 0; nsd.server_kind = NSD_SERVER_MAIN; for (i = 0; i < MAX_INTERFACES; i++) { memset(&hints[i], 0, sizeof(hints[i])); hints[i].ai_family = DEFAULT_AI_FAMILY; hints[i].ai_flags = AI_PASSIVE; nodes[i] = NULL; } nsd.identity = 0; nsd.version = VERSION; nsd.username = 0; nsd.chrootdir = 0; nsd.nsid = NULL; nsd.nsid_len = 0; nsd.child_count = 0; nsd.maximum_tcp_count = 0; nsd.current_tcp_count = 0; nsd.grab_ip6_optional = 0; nsd.file_rotation_ok = 0; /* Set up our default identity to gethostname(2) */ if (gethostname(hostname, MAXHOSTNAMELEN) == 0) { nsd.identity = hostname; } else { log_msg(LOG_ERR, "failed to get the host name: %s - using default identity", strerror(errno)); nsd.identity = IDENTITY; } /* Parse the command line... */ while ((c = getopt(argc, argv, "46a:c:df:hi:I:l:N:n:P:p:s:u:t:X:V:v" #ifndef NDEBUG /* <mattthijs> only when configured with --enable-checking */ "F:L:" #endif /* NDEBUG */ )) != -1) { switch (c) { case '4': for (i = 0; i < MAX_INTERFACES; ++i) { hints[i].ai_family = AF_INET; } break; case '6': #ifdef INET6 for (i = 0; i < MAX_INTERFACES; ++i) { hints[i].ai_family = AF_INET6; } #else /* !INET6 */ error("IPv6 support not enabled."); #endif /* INET6 */ break; case 'a': if (nsd.ifs < MAX_INTERFACES) { nodes[nsd.ifs] = optarg; ++nsd.ifs; } else { error("too many interfaces ('-a') specified."); } break; case 'c': configfile = optarg; break; case 'd': nsd.debug = 1; break; case 'f': nsd.dbfile = optarg; break; case 'h': usage(); exit(0); case 'i': nsd.identity = optarg; break; case 'I': if (nsd.nsid_len != 0) { /* can only be given once */ break; } if (strncasecmp(optarg, "ascii_", 6) == 0) { nsd.nsid = xalloc(strlen(optarg+6)); nsd.nsid_len = strlen(optarg+6); memmove(nsd.nsid, optarg+6, nsd.nsid_len); } else { if (strlen(optarg) % 2 != 0) { error("the NSID must be a hex string of an even length."); } nsd.nsid = xalloc(strlen(optarg) / 2); nsd.nsid_len = strlen(optarg) / 2; if (hex_pton(optarg, nsd.nsid, nsd.nsid_len) == -1) { error("hex string cannot be parsed '%s' in NSID.", optarg); } } break; case 'l': nsd.log_filename = optarg; break; case 'N': i = atoi(optarg); if (i <= 0) { error("number of child servers must be greater than zero."); } else { nsd.child_count = i; } break; case 'n': i = atoi(optarg); if (i <= 0) { error("number of concurrent TCP connections must greater than zero."); } else { nsd.maximum_tcp_count = i; } break; case 'P': nsd.pidfile = optarg; break; case 'p': if (atoi(optarg) == 0) { error("port argument must be numeric."); } tcp_port = optarg; udp_port = optarg; break; case 's': #ifdef BIND8_STATS nsd.st.period = atoi(optarg); #else /* !BIND8_STATS */ error("BIND 8 statistics not enabled."); #endif /* BIND8_STATS */ break; case 't': #ifdef HAVE_CHROOT nsd.chrootdir = optarg; #else /* !HAVE_CHROOT */ error("chroot not supported on this platform."); #endif /* HAVE_CHROOT */ break; case 'u': nsd.username = optarg; break; case 'V': verbosity = atoi(optarg); break; case 'v': version(); /* version exits */ #ifndef NDEBUG case 'F': sscanf(optarg, "%x", &nsd_debug_facilities); break; case 'L': sscanf(optarg, "%d", &nsd_debug_level); break; #endif /* NDEBUG */ case '?': default: usage(); exit(1); } } argc -= optind; argv += optind; /* Commandline parse error */ if (argc != 0) { usage(); exit(1); } if (strlen(nsd.identity) > UCHAR_MAX) { error("server identity too long (%u characters)", (unsigned) strlen(nsd.identity)); } if(!tsig_init(nsd.region)) error("init tsig failed"); /* Read options */ nsd.options = nsd_options_create(region_create_custom(xalloc, free, DEFAULT_CHUNK_SIZE, DEFAULT_LARGE_OBJECT_SIZE, DEFAULT_INITIAL_CLEANUP_SIZE, 1)); if(!parse_options_file(nsd.options, configfile, NULL, NULL)) { error("could not read config: %s\n", configfile); } if(!parse_zone_list_file(nsd.options)) { error("could not read zonelist file %s\n", nsd.options->zonelistfile); } if(nsd.options->do_ip4 && !nsd.options->do_ip6) { for (i = 0; i < MAX_INTERFACES; ++i) { hints[i].ai_family = AF_INET; } } #ifdef INET6 if(nsd.options->do_ip6 && !nsd.options->do_ip4) { for (i = 0; i < MAX_INTERFACES; ++i) { hints[i].ai_family = AF_INET6; } } #endif /* INET6 */ if(nsd.options->ip_addresses) { ip_address_option_t* ip = nsd.options->ip_addresses; while(ip) { if (nsd.ifs < MAX_INTERFACES) { nodes[nsd.ifs] = ip->address; ++nsd.ifs; } else { error("too many interfaces ('-a' + " "'ip-address:') specified."); break; } ip = ip->next; } } if (verbosity == 0) verbosity = nsd.options->verbosity; #ifndef NDEBUG if (nsd_debug_level > 0 && verbosity == 0) verbosity = nsd_debug_level; #endif /* NDEBUG */ if(nsd.options->debug_mode) nsd.debug=1; if(!nsd.dbfile) { if(nsd.options->database) nsd.dbfile = nsd.options->database; else nsd.dbfile = DBFILE; } if(!nsd.pidfile) { if(nsd.options->pidfile) nsd.pidfile = nsd.options->pidfile; else nsd.pidfile = PIDFILE; } if(strcmp(nsd.identity, hostname)==0 || strcmp(nsd.identity,IDENTITY)==0) { if(nsd.options->identity) nsd.identity = nsd.options->identity; } if (nsd.options->logfile && !nsd.log_filename) { nsd.log_filename = nsd.options->logfile; } if(nsd.child_count == 0) { nsd.child_count = nsd.options->server_count; } if(nsd.maximum_tcp_count == 0) { nsd.maximum_tcp_count = nsd.options->tcp_count; } nsd.tcp_timeout = nsd.options->tcp_timeout; nsd.tcp_query_count = nsd.options->tcp_query_count; nsd.ipv4_edns_size = nsd.options->ipv4_edns_size; nsd.ipv6_edns_size = nsd.options->ipv6_edns_size; if(udp_port == 0) { if(nsd.options->port != 0) { udp_port = nsd.options->port; tcp_port = nsd.options->port; } else { udp_port = UDP_PORT; tcp_port = TCP_PORT; } } #ifdef BIND8_STATS if(nsd.st.period == 0) { nsd.st.period = nsd.options->statistics; } #endif /* BIND8_STATS */ #ifdef HAVE_CHROOT if(nsd.chrootdir == 0) nsd.chrootdir = nsd.options->chroot; #ifdef CHROOTDIR /* if still no chrootdir, fallback to default */ if(nsd.chrootdir == 0) nsd.chrootdir = CHROOTDIR; #endif /* CHROOTDIR */ #endif /* HAVE_CHROOT */ if(nsd.username == 0) { if(nsd.options->username) nsd.username = nsd.options->username; else nsd.username = USER; } if(nsd.options->zonesdir && nsd.options->zonesdir[0]) { if(chdir(nsd.options->zonesdir)) { error("cannot chdir to '%s': %s", nsd.options->zonesdir, strerror(errno)); } DEBUG(DEBUG_IPC,1, (LOG_INFO, "changed directory to %s", nsd.options->zonesdir)); } /* EDNS0 */ edns_init_data(&nsd.edns_ipv4, nsd.options->ipv4_edns_size); #if defined(INET6) #if defined(IPV6_USE_MIN_MTU) || defined(IPV6_MTU) edns_init_data(&nsd.edns_ipv6, nsd.options->ipv6_edns_size); #else /* no way to set IPV6 MTU, send no bigger than that. */ if (nsd.options->ipv6_edns_size < IPV6_MIN_MTU) edns_init_data(&nsd.edns_ipv6, nsd.options->ipv6_edns_size); else edns_init_data(&nsd.edns_ipv6, IPV6_MIN_MTU); #endif /* IPV6 MTU) */ #endif /* defined(INET6) */ if (nsd.nsid_len == 0 && nsd.options->nsid) { if (strlen(nsd.options->nsid) % 2 != 0) { error("the NSID must be a hex string of an even length."); } nsd.nsid = xalloc(strlen(nsd.options->nsid) / 2); nsd.nsid_len = strlen(nsd.options->nsid) / 2; if (hex_pton(nsd.options->nsid, nsd.nsid, nsd.nsid_len) == -1) { error("hex string cannot be parsed '%s' in NSID.", nsd.options->nsid); } } edns_init_nsid(&nsd.edns_ipv4, nsd.nsid_len); #if defined(INET6) edns_init_nsid(&nsd.edns_ipv6, nsd.nsid_len); #endif /* defined(INET6) */ /* Number of child servers to fork. */ nsd.children = (struct nsd_child *) region_alloc_array( nsd.region, nsd.child_count, sizeof(struct nsd_child)); for (i = 0; i < nsd.child_count; ++i) { nsd.children[i].kind = NSD_SERVER_BOTH; nsd.children[i].pid = -1; nsd.children[i].child_fd = -1; nsd.children[i].parent_fd = -1; nsd.children[i].handler = NULL; nsd.children[i].need_to_send_STATS = 0; nsd.children[i].need_to_send_QUIT = 0; nsd.children[i].need_to_exit = 0; nsd.children[i].has_exited = 0; } nsd.this_child = NULL; /* We need at least one active interface */ if (nsd.ifs == 0) { nsd.ifs = 1; /* * With IPv6 we'd like to open two separate sockets, * one for IPv4 and one for IPv6, both listening to * the wildcard address (unless the -4 or -6 flags are * specified). * * However, this is only supported on platforms where * we can turn the socket option IPV6_V6ONLY _on_. * Otherwise we just listen to a single IPv6 socket * and any incoming IPv4 connections will be * automatically mapped to our IPv6 socket. */ #ifdef INET6 if (hints[0].ai_family == AF_UNSPEC) { #ifdef IPV6_V6ONLY hints[0].ai_family = AF_INET6; hints[1].ai_family = AF_INET; nsd.ifs = 2; nsd.grab_ip6_optional = 1; #else /* !IPV6_V6ONLY */ hints[0].ai_family = AF_INET6; #endif /* IPV6_V6ONLY */ } #endif /* INET6 */ } /* Set up the address info structures with real interface/port data */ for (i = 0; i < nsd.ifs; ++i) { int r; const char* node = NULL; const char* service = NULL; /* We don't perform name-lookups */ if (nodes[i] != NULL) hints[i].ai_flags |= AI_NUMERICHOST; get_ip_port_frm_str(nodes[i], &node, &service); hints[i].ai_socktype = SOCK_DGRAM; if ((r=getaddrinfo(node, (service?service:udp_port), &hints[i], &nsd.udp[i].addr)) != 0) { #ifdef INET6 if(nsd.grab_ip6_optional && hints[0].ai_family == AF_INET6) { log_msg(LOG_WARNING, "No IPv6, fallback to IPv4. getaddrinfo: %s", r==EAI_SYSTEM?strerror(errno):gai_strerror(r)); continue; } #endif error("cannot parse address '%s': getaddrinfo: %s %s", nodes[i]?nodes[i]:"(null)", gai_strerror(r), r==EAI_SYSTEM?strerror(errno):""); } hints[i].ai_socktype = SOCK_STREAM; if ((r=getaddrinfo(node, (service?service:tcp_port), &hints[i], &nsd.tcp[i].addr)) != 0) { error("cannot parse address '%s': getaddrinfo: %s %s", nodes[i]?nodes[i]:"(null)", gai_strerror(r), r==EAI_SYSTEM?strerror(errno):""); } } /* Parse the username into uid and gid */ nsd.gid = getgid(); nsd.uid = getuid(); #ifdef HAVE_GETPWNAM /* Parse the username into uid and gid */ if (*nsd.username) { if (isdigit((unsigned char)*nsd.username)) { char *t; nsd.uid = strtol(nsd.username, &t, 10); if (*t != 0) { if (*t != '.' || !isdigit((unsigned char)*++t)) { error("-u user or -u uid or -u uid.gid"); } nsd.gid = strtol(t, &t, 10); } else { /* Lookup the group id in /etc/passwd */ if ((pwd = getpwuid(nsd.uid)) == NULL) { error("user id %u does not exist.", (unsigned) nsd.uid); } else { nsd.gid = pwd->pw_gid; } } } else { /* Lookup the user id in /etc/passwd */ if ((pwd = getpwnam(nsd.username)) == NULL) { error("user '%s' does not exist.", nsd.username); } else { nsd.uid = pwd->pw_uid; nsd.gid = pwd->pw_gid; } } } /* endpwent(); */ #endif /* HAVE_GETPWNAM */ #if defined(HAVE_SSL) key_options_tsig_add(nsd.options); #endif append_trailing_slash(&nsd.options->xfrdir, nsd.options->region); /* Check relativity of pathnames to chroot */ if (nsd.chrootdir && nsd.chrootdir[0]) { /* existing chrootdir: append trailing slash for strncmp checking */ append_trailing_slash(&nsd.chrootdir, nsd.region); append_trailing_slash(&nsd.options->zonesdir, nsd.options->region); /* zonesdir must be absolute and within chroot, * all other pathnames may be relative to zonesdir */ if (strncmp(nsd.options->zonesdir, nsd.chrootdir, strlen(nsd.chrootdir)) != 0) { error("zonesdir %s has to be an absolute path that starts with the chroot path %s", nsd.options->zonesdir, nsd.chrootdir); } else if (!file_inside_chroot(nsd.pidfile, nsd.chrootdir)) { error("pidfile %s is not relative to %s: chroot not possible", nsd.pidfile, nsd.chrootdir); } else if (!file_inside_chroot(nsd.dbfile, nsd.chrootdir)) { error("database %s is not relative to %s: chroot not possible", nsd.dbfile, nsd.chrootdir); } else if (!file_inside_chroot(nsd.options->xfrdfile, nsd.chrootdir)) { error("xfrdfile %s is not relative to %s: chroot not possible", nsd.options->xfrdfile, nsd.chrootdir); } else if (!file_inside_chroot(nsd.options->zonelistfile, nsd.chrootdir)) { error("zonelistfile %s is not relative to %s: chroot not possible", nsd.options->zonelistfile, nsd.chrootdir); } else if (!file_inside_chroot(nsd.options->xfrdir, nsd.chrootdir)) { error("xfrdir %s is not relative to %s: chroot not possible", nsd.options->xfrdir, nsd.chrootdir); } } /* Set up the logging */ log_open(LOG_PID, FACILITY, nsd.log_filename); if (!nsd.log_filename) log_set_log_function(log_syslog); else if (nsd.uid && nsd.gid) { if(chown(nsd.log_filename, nsd.uid, nsd.gid) != 0) VERBOSITY(2, (LOG_WARNING, "chown %s failed: %s", nsd.log_filename, strerror(errno))); } /* Do we have a running nsd? */ if ((oldpid = readpid(nsd.pidfile)) == -1) { if (errno != ENOENT) { log_msg(LOG_ERR, "can't read pidfile %s: %s", nsd.pidfile, strerror(errno)); } } else { if (kill(oldpid, 0) == 0 || errno == EPERM) { log_msg(LOG_WARNING, "%s is already running as %u, continuing", argv0, (unsigned) oldpid); } else { log_msg(LOG_ERR, "...stale pid file from process %u", (unsigned) oldpid); } } /* Setup the signal handling... */ action.sa_handler = sig_handler; sigfillset(&action.sa_mask); action.sa_flags = 0; sigaction(SIGTERM, &action, NULL); sigaction(SIGHUP, &action, NULL); sigaction(SIGINT, &action, NULL); sigaction(SIGILL, &action, NULL); sigaction(SIGUSR1, &action, NULL); sigaction(SIGALRM, &action, NULL); sigaction(SIGCHLD, &action, NULL); action.sa_handler = SIG_IGN; sigaction(SIGPIPE, &action, NULL); /* Initialize... */ nsd.mode = NSD_RUN; nsd.signal_hint_child = 0; nsd.signal_hint_reload = 0; nsd.signal_hint_reload_hup = 0; nsd.signal_hint_quit = 0; nsd.signal_hint_shutdown = 0; nsd.signal_hint_stats = 0; nsd.signal_hint_statsusr = 0; nsd.quit_sync_done = 0; /* Initialize the server... */ if (server_init(&nsd) != 0) { error("server initialization failed, %s could " "not be started", argv0); } #if defined(HAVE_SSL) if(nsd.options->control_enable) { /* read ssl keys while superuser and outside chroot */ if(!(nsd.rc = daemon_remote_create(nsd.options))) error("could not perform remote control setup"); } #endif /* HAVE_SSL */ /* Unless we're debugging, fork... */ if (!nsd.debug) { int fd; /* Take off... */ switch ((nsd.pid = fork())) { case 0: /* Child */ break; case -1: error("fork() failed: %s", strerror(errno)); default: /* Parent is done */ server_close_all_sockets(nsd.udp, nsd.ifs); server_close_all_sockets(nsd.tcp, nsd.ifs); exit(0); } /* Detach ourselves... */ if (setsid() == -1) { error("setsid() failed: %s", strerror(errno)); } if ((fd = open("/dev/null", O_RDWR, 0)) != -1) { (void)dup2(fd, STDIN_FILENO); (void)dup2(fd, STDOUT_FILENO); (void)dup2(fd, STDERR_FILENO); if (fd > 2) (void)close(fd); } } /* Get our process id */ nsd.pid = getpid(); /* Set user context */ #ifdef HAVE_GETPWNAM if (*nsd.username) { #ifdef HAVE_SETUSERCONTEXT /* setusercontext does initgroups, setuid, setgid, and * also resource limits from login config, but we * still call setresuid, setresgid to be sure to set all uid */ if (setusercontext(NULL, pwd, nsd.uid, LOGIN_SETALL & ~LOGIN_SETUSER & ~LOGIN_SETGROUP) != 0) log_msg(LOG_WARNING, "unable to setusercontext %s: %s", nsd.username, strerror(errno)); #endif /* HAVE_SETUSERCONTEXT */ } #endif /* HAVE_GETPWNAM */ /* Chroot */ #ifdef HAVE_CHROOT if (nsd.chrootdir && nsd.chrootdir[0]) { int l = strlen(nsd.chrootdir)-1; /* ends in trailing slash */ if (file_inside_chroot(nsd.log_filename, nsd.chrootdir)) nsd.file_rotation_ok = 1; /* strip chroot from pathnames if they're absolute */ nsd.options->zonesdir += l; if (nsd.log_filename){ if (nsd.log_filename[0] == '/') nsd.log_filename += l; } if (nsd.pidfile[0] == '/') nsd.pidfile += l; if (nsd.dbfile[0] == '/') nsd.dbfile += l; if (nsd.options->xfrdfile[0] == '/') nsd.options->xfrdfile += l; if (nsd.options->zonelistfile[0] == '/') nsd.options->zonelistfile += l; if (nsd.options->xfrdir[0] == '/') nsd.options->xfrdir += l; /* strip chroot from pathnames of "include:" statements * on subsequent repattern commands */ cfg_parser->chroot = nsd.chrootdir; #ifdef HAVE_TZSET /* set timezone whilst not yet in chroot */ tzset(); #endif if (chroot(nsd.chrootdir)) { error("unable to chroot: %s", strerror(errno)); } if (chdir("/")) { error("unable to chdir to chroot: %s", strerror(errno)); } DEBUG(DEBUG_IPC,1, (LOG_INFO, "changed root directory to %s", nsd.chrootdir)); /* chdir to zonesdir again after chroot */ if(nsd.options->zonesdir && nsd.options->zonesdir[0]) { if(chdir(nsd.options->zonesdir)) { error("unable to chdir to '%s': %s", nsd.options->zonesdir, strerror(errno)); } DEBUG(DEBUG_IPC,1, (LOG_INFO, "changed directory to %s", nsd.options->zonesdir)); } } else #endif /* HAVE_CHROOT */ nsd.file_rotation_ok = 1; DEBUG(DEBUG_IPC,1, (LOG_INFO, "file rotation on %s %sabled", nsd.log_filename, nsd.file_rotation_ok?"en":"dis")); /* Write pidfile */ if (writepid(&nsd) == -1) { log_msg(LOG_ERR, "cannot overwrite the pidfile %s: %s", nsd.pidfile, strerror(errno)); } /* Drop the permissions */ #ifdef HAVE_GETPWNAM if (*nsd.username) { #ifdef HAVE_INITGROUPS if(initgroups(nsd.username, nsd.gid) != 0) log_msg(LOG_WARNING, "unable to initgroups %s: %s", nsd.username, strerror(errno)); #endif /* HAVE_INITGROUPS */ endpwent(); #ifdef HAVE_SETRESGID if(setresgid(nsd.gid,nsd.gid,nsd.gid) != 0) #elif defined(HAVE_SETREGID) && !defined(DARWIN_BROKEN_SETREUID) if(setregid(nsd.gid,nsd.gid) != 0) #else /* use setgid */ if(setgid(nsd.gid) != 0) #endif /* HAVE_SETRESGID */ error("unable to set group id of %s: %s", nsd.username, strerror(errno)); #ifdef HAVE_SETRESUID if(setresuid(nsd.uid,nsd.uid,nsd.uid) != 0) #elif defined(HAVE_SETREUID) && !defined(DARWIN_BROKEN_SETREUID) if(setreuid(nsd.uid,nsd.uid) != 0) #else /* use setuid */ if(setuid(nsd.uid) != 0) #endif /* HAVE_SETRESUID */ error("unable to set user id of %s: %s", nsd.username, strerror(errno)); DEBUG(DEBUG_IPC,1, (LOG_INFO, "dropped user privileges, run as %s", nsd.username)); } #endif /* HAVE_GETPWNAM */ xfrd_make_tempdir(&nsd); #ifdef USE_ZONE_STATS options_zonestatnames_create(nsd.options); server_zonestat_alloc(&nsd); #endif /* USE_ZONE_STATS */ if(nsd.server_kind == NSD_SERVER_MAIN) { server_prepare_xfrd(&nsd); /* xfrd forks this before reading database, so it does not get * the memory size of the database */ server_start_xfrd(&nsd, 0, 0); } if (server_prepare(&nsd) != 0) { unlinkpid(nsd.pidfile); error("server preparation failed, %s could " "not be started", argv0); } if(nsd.server_kind == NSD_SERVER_MAIN) { server_send_soa_xfrd(&nsd, 0); } /* Really take off */ log_msg(LOG_NOTICE, "%s started (%s), pid %d", argv0, PACKAGE_STRING, (int) nsd.pid); if (nsd.server_kind == NSD_SERVER_MAIN) { server_main(&nsd); } else { server_child(&nsd); } /* NOTREACH */ exit(0); }
int main(int argc, char *argv[]) { cal_path(); setlocale(LC_MESSAGES, ""); bindtextdomain("opvdm", get_lang_path()); textdomain("opvdm"); timer_init(0); timer_init(1); dbus_init(); set_ewe_lock_file("", ""); cell.onlypos = FALSE; char pwd[1000]; if (getcwd(pwd, 1000) == NULL) { ewe("IO error\n"); } dump_init(&cell); dump_load_config(&cell); remove("snapshots.zip"); remove("light_dump.zip"); hard_limit_init(); //char path[PATH_MAX]; //char dest[PATH_MAX]; //pid_t pid = getpid(); //sprintf(path, "/proc/%d/exe", pid); //if (readlink(path, dest, PATH_MAX) == -1) //{ // printf("error\n"); // exit(1); //} // char *base = strrchr(dest, '/'); //*base='/'; //*(base+1)=0; set_plot_script_dir(pwd); //set_plot_script_dir(char * in) if (scanarg(argv, argc, "--help") == TRUE) { printf("opvdm_core - Organic Photovoltaic Device Model\n"); printf(copyright); printf("\n"); printf("Usage: opvdm_core [options]\n"); printf("\n"); printf("Options:\n"); printf("\n"); printf("\t--outputpath\toutput data path"); printf("\t--inputpath\t sets the input path\n"); printf("\t--version\tdisplays the current version\n"); printf("\t--zip_results\t zip the results\n"); printf("\t--optics\t runs only optical simulation\n"); printf("\t--cpus\t sets the number of CPUs\n"); printf("\n"); printf ("Additional information about opvdm is available at www.opvdm.com.\n"); printf("\n"); printf ("Report bugs to: [email protected]\n\n"); exit(0); } if (scanarg(argv, argc, "--version") == TRUE) { printf("opvdm_core, Version %s\n", opvdm_ver); printf(copyright); printf(this_is_free_software); printf ("There is ABSOLUTELY NO WARRANTY; not even for MERCHANTABILITY or\n"); printf("FITNESS FOR A PARTICULAR PURPOSE.\n"); printf("\n"); exit(0); } if (geteuid() == 0) { ewe("Don't run me as root!\n"); } set_dump_status(dump_stop_plot, FALSE); set_dump_status(dump_print_text, TRUE); set_io_dump(FALSE); srand(time(0)); textcolor(fg_green); randomprint(_("Organic Photovoltaic Device Model (www.opvdm.com)\n")); randomprint(_ ("You should have received a copy of the GNU General Public License\n")); randomprint(_ ("along with this software. If not, see www.gnu.org/licenses/.\n")); randomprint("\n"); randomprint(_ ("If you wish to collaborate in anyway please get in touch:\n")); randomprint(_("[email protected]\n")); randomprint(_("www.roderickmackenzie.eu/contact.html\n")); randomprint("\n"); textcolor(fg_reset); globalserver.on = FALSE; globalserver.cpus = 1; globalserver.readconfig = TRUE; if (scanarg(argv, argc, "--outputpath") == TRUE) { strcpy(sim_output_path(), get_arg_plusone(argv, argc, "--outputpath")); } else { strcpy(sim_output_path(), pwd); } if (scanarg(argv, argc, "--inputpath") == TRUE) { strcpy(sim_input_path(), get_arg_plusone(argv, argc, "--inputpath")); } else { strcpy(sim_input_path(), sim_output_path()); } dump_load_config(&cell); if (scanarg(argv, argc, "--onlypos") == TRUE) { cell.onlypos = TRUE; } char name[200]; struct inp_file inp; inp_init(&inp); inp_load_from_path(&inp, sim_input_path(), "ver.inp"); inp_check(&inp, 1.0); inp_search_string(&inp, name, "#core"); inp_free(&inp); if (strcmp(name, opvdm_ver) != 0) { printf ("Software is version %s and the input files are version %s\n", opvdm_ver, name); exit(0); } gui_start(); if (scanarg(argv, argc, "--optics") == FALSE) server_init(&globalserver); if (scanarg(argv, argc, "--lock") == TRUE) { server_set_dbus_finish_signal(&globalserver, get_arg_plusone(argv, argc, "--lock")); } int ret = 0; int do_fit = FALSE; if (scanarg(argv, argc, "--fit") == TRUE) do_fit = TRUE; FILE *f = fopen("fit.inp", "r"); if (f != NULL) { fclose(f); inp_init(&inp); inp_load_from_path(&inp, pwd, "fit.inp"); int fit_temp; inp_search_int(&inp, &fit_temp, "#do_fit"); if (fit_temp == 1) { do_fit = TRUE; } inp_free(&inp); } if (do_fit == TRUE) { set_dump_status(dump_lock, FALSE); set_dump_status(dump_print_text, FALSE); set_dump_status(dump_iodump, FALSE); set_dump_status(dump_optics, FALSE); set_dump_status(dump_newton, FALSE); set_dump_status(dump_plot, FALSE); set_dump_status(dump_stop_plot, FALSE); set_dump_status(dump_opt_for_fit, FALSE); set_dump_status(dump_print_newtonerror, FALSE); set_dump_status(dump_print_converge, FALSE); set_dump_status(dump_print_pos_error, FALSE); set_dump_status(dump_lock, TRUE); } #include "main_args.c" if (scanarg(argv, argc, "--optics") == TRUE) { gui_start(); struct light two; light_init(&two, &cell, pwd); //light_set_dx(&cell.mylight,cell.ymesh[1]-cell.ymesh[0]); light_load_config(&two); two.disable_transfer_to_electrical_mesh = TRUE; set_dump_status(dump_lock, FALSE); set_dump_status(dump_optics, TRUE); set_dump_status(dump_optics_verbose, TRUE); double Psun; inp_init(&inp); inp_load_from_path(&inp, pwd, "light.inp"); inp_search_double(&inp, &(Psun), "#Psun"); Psun = 1.0; //fabs(Psun); inp_free(&inp); light_solve_and_update(&cell, &two, Psun, 0.0); light_dump(&two); light_free(&two); complex_solver_free(); } else { gen_dos_fd_gaus_fd(); server_add_job(&globalserver, cell.outputpath, cell.inputpath); print_jobs(&globalserver); ret = server_run_jobs(&globalserver); } server_shut_down(&globalserver); if (scanarg(argv, argc, "--zip_results") == TRUE) { printf("zipping results\n"); int ret; char temp[200]; DIR *dir = opendir("snapshots"); if (dir) { closedir(dir); ret = system("zip -r -j -q snapshots.zip ./snapshots/*"); if (ret == -1) { printf("tar returned error\n"); } join_path(2, temp, cell.outputpath, "snapshots"); remove_dir(temp); } dir = opendir("light_dump"); if (dir) { closedir(dir); ret = system ("zip -r -j -q light_dump.zip ./light_dump/*"); if (ret == -1) { printf("tar returned error\n"); } join_path(2, temp, cell.outputpath, "light_dump"); remove_dir(temp); } } hard_limit_free(); if (ret != 0) { return 1; } return 0; }
rstatus_t conf_pool_each_transform(void *elem, void *data) { rstatus_t status; struct conf_pool *cp = elem; struct array *server_pool = data; struct server_pool *sp; ASSERT(cp->valid); sp = array_push(server_pool); ASSERT(sp != NULL); sp->idx = array_idx(server_pool, sp); sp->ctx = NULL; sp->p_conn = NULL; sp->nc_conn_q = 0; TAILQ_INIT(&sp->c_conn_q); sp->state = STATE_UNINITLIAZED; array_null(&sp->groups); array_null(&sp->sentinels); sp->sentinel = NULL; sp->sentinel_heartbeat = (uint32_t)cp->sentinel_heartbeat; array_null(&sp->server); sp->ncontinuum = 0; sp->nserver_continuum = 0; sp->continuum = NULL; sp->nlive_server = 0; sp->name = cp->name; sp->addrstr = cp->listen.pname; sp->port = (uint16_t)cp->listen.port; nc_memcpy(&sp->info, &cp->listen.info, sizeof(cp->listen.info)); sp->perm = cp->listen.perm; sp->dist_type = cp->distribution; sp->key_hash_type = cp->hash; sp->key_hash = hash_algos[cp->hash]; sp->hash_tag = cp->hash_tag; sp->timeout = cp->timeout; sp->backlog = cp->backlog; sp->redis_db = cp->redis_db; sp->client_connections = (uint32_t)cp->client_connections; sp->server_connections = (uint32_t)cp->server_connections; sp->redis_auth = cp->redis_auth; sp->require_auth = cp->redis_auth.len > 0 ? 1 : 0; sp->tcpkeepalive = cp->tcpkeepalive ? 1 : 0; sp->groups = cp->groups; status = server_init(&sp->server, &sp->groups, sp); if (status != NC_OK) { return status; } status = sentinel_init(&sp->sentinels, &cp->sentinels, sp); if (status != NC_OK) { return status; } log_debug(LOG_VERB, "transform to pool %"PRIu32" '%.*s'", sp->idx, sp->name.len, sp->name.data); return NC_OK; }
/* Run client and the server if needed. */ static void start_moc (const struct parameters *params, lists_t_strs *args) { int list_sock; int server_sock = -1; if (!params->foreground && (server_sock = server_connect()) == -1) { int notify_pipe[2]; int i = 0; ssize_t rc; printf ("Running the server...\n"); /* To notify the client that the server socket is ready */ if (pipe(notify_pipe)) fatal ("pipe() failed: %s", strerror(errno)); switch (fork()) { case 0: /* child - start server */ set_me_server (); list_sock = server_init (params->debug, params->foreground); rc = write (notify_pipe[1], &i, sizeof(i)); if (rc < 0) fatal ("write() to notify pipe failed: %s", strerror(errno)); close (notify_pipe[0]); close (notify_pipe[1]); signal (SIGCHLD, sig_chld); server_loop (list_sock); options_free (); decoder_cleanup (); io_cleanup (); files_cleanup (); rcc_cleanup (); compat_cleanup (); exit (EXIT_SUCCESS); case -1: fatal ("fork() failed: %s", strerror(errno)); default: close (notify_pipe[1]); if (read(notify_pipe[0], &i, sizeof(i)) != sizeof(i)) fatal ("Server exited!"); close (notify_pipe[0]); if ((server_sock = server_connect()) == -1) { perror ("server_connect()"); fatal ("Can't connect to the server!"); } } } else if (!params->foreground && params->only_server) fatal ("Server is already running!"); else if (params->foreground && params->only_server) { set_me_server (); list_sock = server_init (params->debug, params->foreground); server_loop (list_sock); } if (!params->only_server) { signal (SIGPIPE, SIG_IGN); if (ping_server(server_sock)) { if (!params->dont_run_iface) { init_interface (server_sock, params->debug, args); interface_loop (); interface_end (); } } else fatal ("Can't connect to the server!"); } if (!params->foreground && params->only_server) send_int (server_sock, CMD_DISCONNECT); close (server_sock); }
int32_t main(int32_t argc, char *argv[]) { struct bthid_server srv; struct sigaction sa; char const *pid_file = BTHIDD_PIDFILE; char *ep; int32_t opt, detach, tval; memset(&srv, 0, sizeof(srv)); memset(&srv.bdaddr, 0, sizeof(srv.bdaddr)); detach = 1; tval = 10; /* sec */ while ((opt = getopt(argc, argv, "a:c:dH:hp:t:")) != -1) { switch (opt) { case 'a': /* BDADDR */ if (!bt_aton(optarg, &srv.bdaddr)) { struct hostent *he; if ((he = bt_gethostbyname(optarg)) == NULL) errx(1, "%s: %s", optarg, hstrerror(h_errno)); memcpy(&srv.bdaddr, he->h_addr, sizeof(srv.bdaddr)); } break; case 'c': /* config file */ config_file = optarg; break; case 'd': /* do not detach */ detach = 0; break; case 'H': /* hids file */ hids_file = optarg; break; case 'p': /* pid file */ pid_file = optarg; break; case 't': /* rescan interval */ tval = strtol(optarg, (char **) &ep, 10); if (*ep != '\0' || tval <= 0) usage(); break; case 'h': default: usage(); /* NOT REACHED */ } } openlog(BTHIDD_IDENT, LOG_PID|LOG_PERROR|LOG_NDELAY, LOG_USER); /* Become daemon if required */ if (detach && daemon(0, 0) < 0) { syslog(LOG_CRIT, "Could not become daemon. %s (%d)", strerror(errno), errno); exit(1); } /* Install signal handler */ memset(&sa, 0, sizeof(sa)); sa.sa_handler = sighandler; if (sigaction(SIGTERM, &sa, NULL) < 0 || sigaction(SIGHUP, &sa, NULL) < 0 || sigaction(SIGINT, &sa, NULL) < 0) { syslog(LOG_CRIT, "Could not install signal handlers. %s (%d)", strerror(errno), errno); exit(1); } sa.sa_handler = SIG_IGN; if (sigaction(SIGPIPE, &sa, NULL) < 0) { syslog(LOG_CRIT, "Could not install signal handlers. %s (%d)", strerror(errno), errno); exit(1); } sa.sa_handler = SIG_IGN; sa.sa_flags = SA_NOCLDSTOP|SA_NOCLDWAIT; if (sigaction(SIGCHLD, &sa, NULL) < 0) { syslog(LOG_CRIT, "Could not install signal handlers. %s (%d)", strerror(errno), errno); exit(1); } if (read_config_file() < 0 || read_hids_file() < 0 || server_init(&srv) < 0 || write_pid_file(pid_file) < 0) exit(1); for (done = 0; !done; ) { if (elapsed(tval)) client_rescan(&srv); if (server_do(&srv) < 0) break; } server_shutdown(&srv); remove_pid_file(pid_file); clean_config(); closelog(); return (0); }
int main(int argc, char **argv) { /* Parse command line arguments. */ int c = 0, li = 0; int daemonize = 0; const char *config_fn = CONF_DEFAULT_FILE; const char *config_db = NULL; const char *daemon_root = "/"; /* Long options. */ struct option opts[] = { {"config", required_argument, 0, 'c' }, {"confdb", required_argument, 0, 'C' }, {"daemonize", optional_argument, 0, 'd'}, {"version", no_argument, 0, 'V'}, {"help", no_argument, 0, 'h'}, {0, 0, 0, 0} }; while ((c = getopt_long(argc, argv, "c:C:dVh", opts, &li)) != -1) { switch (c) { case 'c': config_fn = optarg; break; case 'C': config_db = optarg; break; case 'd': daemonize = 1; if (optarg) { daemon_root = optarg; } break; case 'V': printf("%s, version %s\n", "Knot DNS", PACKAGE_VERSION); return EXIT_SUCCESS; case 'h': case '?': help(); return EXIT_SUCCESS; default: help(); return EXIT_FAILURE; } } /* Check for non-option parameters. */ if (argc - optind > 0) { help(); return EXIT_FAILURE; } /* Now check if we want to daemonize. */ if (daemonize) { if (make_daemon(1, 0) != 0) { fprintf(stderr, "Daemonization failed, shutting down...\n"); return EXIT_FAILURE; } } /* Clear file creation mask. */ umask(0); /* Setup base signal handling. */ setup_signals(); /* Initialize cryptographic backend. */ dnssec_crypto_init(); atexit(dnssec_crypto_cleanup); /* Initialize pseudorandom number generator. */ srand(time(NULL)); /* POSIX 1003.1e capabilities. */ setup_capabilities(); /* Default logging to std out/err. */ log_init(); /* Open configuration. */ conf_t *new_conf = NULL; if (config_db == NULL) { int ret = conf_new(&new_conf, conf_scheme, NULL); if (ret != KNOT_EOK) { log_fatal("failed to initialize configuration database " "(%s)", knot_strerror(ret)); log_close(); return EXIT_FAILURE; } /* Import the configuration file. */ ret = conf_import(new_conf, config_fn, true); if (ret != KNOT_EOK) { log_fatal("failed to load configuration file (%s)", knot_strerror(ret)); conf_free(new_conf, false); log_close(); return EXIT_FAILURE; } new_conf->filename = strdup(config_fn); } else { /* Open configuration database. */ int ret = conf_new(&new_conf, conf_scheme, config_db); if (ret != KNOT_EOK) { log_fatal("failed to open configuration database '%s' " "(%s)", config_db, knot_strerror(ret)); log_close(); return EXIT_FAILURE; } } /* Run post-open config operations. */ int res = conf_post_open(new_conf); if (res != KNOT_EOK) { log_fatal("failed to use configuration (%s)", knot_strerror(res)); conf_free(new_conf, false); log_close(); return EXIT_FAILURE; } conf_update(new_conf); /* Initialize logging subsystem. */ log_reconfigure(conf(), NULL); /* Initialize server. */ server_t server; res = server_init(&server, conf_bg_threads(conf())); if (res != KNOT_EOK) { log_fatal("failed to initialize server (%s)", knot_strerror(res)); conf_free(conf(), false); log_close(); return EXIT_FAILURE; } /* Reconfigure server interfaces. * @note This MUST be done before we drop privileges. */ server_reconfigure(conf(), &server); log_info("configured %zu zones", conf_id_count(conf(), C_ZONE)); /* Alter privileges. */ int uid, gid; if (conf_user(conf(), &uid, &gid) != KNOT_EOK || log_update_privileges(uid, gid) != KNOT_EOK || proc_update_privileges(uid, gid) != KNOT_EOK) { log_fatal("failed to drop privileges"); server_deinit(&server); conf_free(conf(), false); log_close(); return EXIT_FAILURE; } /* Check and create PID file. */ long pid = (long)getpid(); char *pidfile = NULL; if (daemonize) { pidfile = pid_check_and_create(); if (pidfile == NULL) { server_deinit(&server); conf_free(conf(), false); log_close(); return EXIT_FAILURE; } log_info("PID stored in '%s'", pidfile); if (chdir(daemon_root) != 0) { log_warning("failed to change working directory to %s", daemon_root); } else { log_info("changed directory to %s", daemon_root); } } /* Now we're going multithreaded. */ rcu_register_thread(); /* Populate zone database. */ log_info("loading zones"); server_update_zones(conf(), &server); /* Check number of loaded zones. */ if (knot_zonedb_size(server.zone_db) == 0) { log_warning("no zones loaded"); } /* Start it up. */ log_info("starting server"); conf_val_t async_val = conf_get(conf(), C_SRV, C_ASYNC_START); res = server_start(&server, conf_bool(&async_val)); if (res != KNOT_EOK) { log_fatal("failed to start server (%s)", knot_strerror(res)); server_deinit(&server); rcu_unregister_thread(); pid_cleanup(pidfile); log_close(); conf_free(conf(), false); return EXIT_FAILURE; } if (daemonize) { log_info("server started as a daemon, PID %ld", pid); } else { log_info("server started in the foreground, PID %ld", pid); init_signal_started(); } /* Start the event loop. */ event_loop(&server); /* Teardown server and configuration. */ server_deinit(&server); /* Free configuration. */ conf_free(conf(), false); /* Unhook from RCU. */ rcu_unregister_thread(); /* Cleanup PID file. */ pid_cleanup(pidfile); log_info("shutting down"); log_close(); return EXIT_SUCCESS; }
int main(void) { unsigned int i; // Just a counter. Never mind it. puts("-------------------------------------------------------------------"); puts("This is an example of usage of the libbsmp. This output makes "); puts("more sense if you open the source code '"__FILE__"' and read along."); puts("-------------------------------------------------------------------"); puts(""); /* * We need to initialize our toy server. This wouldn't be needed in a real * client, because the server would reside elsewhere (in another thread, or * in another computer). */ server_init(); /* * Okay, let's begin our journey of creating and using a client of the BSMP. * * Firstly you shall create an instance for the client. */ bsmp_client_t client; /* * Initialize our client. Initialization does a lot of communications with * the server, so bear in mind that your communications should be ready to * be used before the call to this function. */ TRY("init", bsmp_client_init(&client, client_send, client_recv)); /* * If we got past the last line, we now have a new shiny client, waiting to * be used! */ /* * We can, for starters, get a list of all the Variables in the server: */ struct bsmp_var_info_list *vars; TRY("vars_list", bsmp_get_vars_list(&client, &vars)); printf(C"Server has %d Variable(s):\n", vars->count); for(i = 0; i < vars->count; ++i) printf(C" ID[%d] SIZE[%2d] %s\n", vars->list[i].id, vars->list[i].size, vars->list[i].writable ? "WRITABLE " : "READ-ONLY"); /* * How about a list of groups? */ struct bsmp_group_list *groups; TRY("groups_list", bsmp_get_groups_list(&client, &groups)); printf("\n"C"Server has %d Group(s):\n", groups->count); for(i = 0; i < groups->count; ++i) { printf(C" ID[%d] SIZE[%2d] %s VARS[", groups->list[i].id, groups->list[i].size, groups->list[i].writable ? "WRITABLE " : "READ-ONLY"); unsigned int j; for(j = 0; j < groups->list[i].vars.count; ++j) printf("%2d ", groups->list[i].vars.list[j]->id); printf("]\n"); } /* * Hmm cool! Easy! Now, Curves! */ struct bsmp_curve_info_list *curves; TRY("curves_list", bsmp_get_curves_list(&client, &curves)); printf("\n"C"Server has %d Curve(s):\n", curves->count); for(i = 0; i < curves->count; ++i) printf(C" ID[%d] BLOCKS[%3d (%5d bytes each)] %s\n", curves->list[i].id, curves->list[i].nblocks, curves->list[i].block_size, curves->list[i].writable ? "WRITABLE" : "READ-ONLY"); /* * Alright alright, last but no least, let's ask the server what are his * Functions. */ struct bsmp_func_info_list *funcs; TRY("funcs_list", bsmp_get_funcs_list(&client, &funcs)); printf("\n"C"Server has %d Functions(s):\n", funcs->count); for(i = 0; i < funcs->count; ++i) printf(C" ID[%d] INPUT[%2d bytes] OUTPUT[%2d bytes]\n", funcs->list[i].id, funcs->list[i].input_size, funcs->list[i].output_size); /* * At this point we know all the Entities in the server. We can start * manipulating them! */ /* * First, let's read some Variables. According to the "documentation" of our * toy server, the first Variable contains the name of the server. Let's see * what is his name. */ printf("\n"); struct bsmp_var_info *var_name = &vars->list[0]; uint8_t server_name[var_name->size]; TRY("read_server_name", bsmp_read_var(&client, var_name, server_name)); printf(C"Server said his name was %s. Hello %s!\n", (char*) server_name, (char*) server_name); /* * This Variable is read-only. What if we try to change the name of the * server? */ uint8_t new_server_name[var_name->size]; strcpy((char*)new_server_name, "Tiny little server"); printf(C"Let's try to change the server name to '%s'...\n", (char*)new_server_name); if(!bsmp_write_var(&client, var_name, new_server_name)) printf(C" Yes! We changed the server name! This library is lame.\n\n"); else printf(C" Crap. The server refuses to change his name... If it " "wasn't for this meddling library!\n\n"); /* * As you could see, it was impossible to change the server name. If you pay * more attention, you will notice that the message "SERVER: Request to * WRITE to the Variables..." wasn't printed. That's because the server * never knew we tried to write on a read-only Variable. The attempt was * blocked by the client library. Even if you managed to send a message like * this to the server, the server side library would return an error as * well, not writing anything to the Variable. */ /* * Let's test a Variable that CAN be written to: the digital output * Variable. Now, this variable accept values in the range ]1,255[ and this * range is enforced by the server. We first try to write an unacceptable * value to this variable. The digital output variable is, according to the * server documentation, the fourth Variable. */ printf(C"Okay okay, I'll try then to write to a WRITABLE variable (the\n"); printf(C"digital output). Will I be able to? I will write a value that\n"); printf(C"outside the acceptable range. I doubt the library will catch\n"); printf(C"*that*!\n"); struct bsmp_var_info *var_dig_output = &vars->list[3]; uint8_t dig_val[1] = {1}; TRY("invalid var value", !bsmp_write_var(&client, var_dig_output, dig_val)); printf(C"Oh noes! It DID!\n"); /* * If we are past the last sentence, then bsmp_write_var returned an error, * as expected (CMD_ERR_INVALID_VALUE) */ /* * Moving on, we will read the first A/D converter. According to our well- * written server manual, this is the second Variable. */ printf("\n"); struct bsmp_var_info *var_1st_ad = &vars->list[1]; uint8_t ad_value[var_1st_ad->size]; TRY("read 1st ad", bsmp_read_var(&client, var_1st_ad, ad_value)); /* * It's, of course, a bipolar A/D converter, from -10V to +10V. We need to * convert the bytes that we've got. */ printf(C"The 1st A/D converter is 'reading' %.3f V. Weird...\n", convert_ad(ad_value)); /* * The A/D is showing -10.0V! Oh, of course! We didn't "start" the * "conversion"! What a silly fake A/D. Let's do that. We shall call a * function. Our server manual (which is the source code server.c) says that * the function to start the A/D conversions is the first one. */ struct bsmp_func_info *func_convert_ads = &funcs->list[0]; printf(C"Server, start the conversions of the A/D converters. NOW!!!\n"); uint8_t convert_ads_error; TRY("convert ads", bsmp_func_execute(&client, func_convert_ads, &convert_ads_error, NULL, NULL)); TRY("reread 1st ad", bsmp_read_var(&client, var_1st_ad, ad_value)); printf(C"The 1st A/D converter is now 'reading' %.3f V! Nice!\n", convert_ad(ad_value)); /* * Remember that the server has 2 A/D's? What if we wanted to read both of * them with just one command? Is that possible? Yes we can! I mean, yes it * is. We just create a new Group first. We have to pass a NULL-terminated * list of Variables. The A/D's are the second and the third variables. */ printf("\n"C"Creating a group with both A/D converters in it\n"); struct bsmp_var_info *all_ads[3] = {&vars->list[1], &vars->list[2], NULL}; TRY("create group", bsmp_create_group(&client, all_ads)); /* The group created is the last one */ struct bsmp_group *ads_group = &groups->list[groups->count-1]; uint8_t ads_values[ads_group->size]; printf(C"Now the server has %d groups. The last group contains %d " "Variables.\n", groups->count, ads_group->vars.count); printf(C"Let's read this group. It contains our A/D's.\n"); TRY("read group", bsmp_read_group(&client, ads_group, ads_values)); printf(C" 1st A/D = %.3f V 2nd A/D = %.3f V\n", convert_ad(&ads_values[0]), convert_ad(&ads_values[1])); /* * Great! We read from two Variables with only one command! What a powerful * library! Now, we don't want those A/D's in a group anymore. In fact, we * don't want any groups anymore! What? You do? Well, I don't. I'll get rid * of all of them! MUAHAHAHAHA! */ printf("\n"C"Ok, enough of groups. I'll remove them all!\n"); TRY("remove groups", bsmp_remove_all_groups(&client)); printf(C"Done. Now the sever has... What? %d groups??\n", groups->count); printf(C"Oh yeah, of course, there are 3 irremovable standard groups...\n"); /* * It's not possible to remove the first three groups... Bummer! Well, at * least you have some of your *precious* groups. */ /* * We covered a lot of commands so far. Let's check these nifty binary * operations. Suppose our server has a missile launcher AND an atomic bomb. * Now suppose you are an evil warlord. You want to shoot that missile, but * you must not detonate the bomb, otherwise you'll die. * * The missile launches when the most significant bit of the server's * digital output toggles. Likewise, the bomb explodes when the least * significant bit of the digital toggles. You have to do that in only one * command. Why? Because I make the rules! * * The library comes to the rescue! You can toggle any bit of any Variable * without knowing its previous value. * * BIG FAT NOTE: a binary operation do NOT trigger a value check. */ uint8_t toggle_mask[var_dig_output->size]; toggle_mask[0] = 0x80; // Most significant bit printf("\n"C"Let's try to toggle the most significant bit of the digital " "output\n"); TRY("toggle bit", bsmp_bin_op_var(&client, BIN_OP_TOGGLE, var_dig_output, toggle_mask)); /* * Missile launched!! */ /* * Manipulating Curves. The server documentation states that there are 2 * curves, a small one and a big one. The small one is writable. So, to * exemplify the staggering simplicity of writing to a curve, we will put a * very complex pattern of numbers in the blocks of the little curve. */ printf("\n"C"Okay, enough with Variables and Groups. Those Curves should be " "read from/written to!\n"); /* * The pattern is simply 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 .... */ printf(C"I will make the little curve contain the pattern 0 1 2 3 4 5 6 " "7 8 9 in its data\n"); struct bsmp_curve_info *little_curve = &curves->list[0]; uint8_t pattern_block[little_curve->block_size]; /* * Fill the pattern */ for(i = 0; i < little_curve->block_size; ++i) pattern_block[i] = i % 10; /* * Send the pattern to all blocks, one at a time! */ for(i = 0; i < little_curve->nblocks; ++i) TRY("send curve block", bsmp_send_curve_block(&client, little_curve, i, pattern_block, little_curve->block_size)); /* * Was the pattern written? I'm sure it was, but to be on the safe side, we * should check. */ printf(C"Done! I've written that pattern! Now let's read back what I " "wrote\n"); uint8_t pattern_read_back[little_curve->block_size]; uint16_t pattern_read_bytes; TRY("request curve block", bsmp_request_curve_block(&client, little_curve, 0, pattern_read_back, &pattern_read_bytes)); printf(C"Got %d bytes for 1st block. The 15 first bytes are:\n"C" ", pattern_read_bytes); for(i = 0; i < 15; ++i) printf("%d ", pattern_read_back[i]); printf("\n\n"); /* * That was nice. But there is an even nicer feature of the library: * reading/writing whole curves! You just specify a big buffer and the * library takes care of the rest. */ printf(C"The big curve will be read now. But instead of reading block by " "block, let's use a neat function that reads the whole curve.\n"); struct bsmp_curve_info *big_curve = &curves->list[1]; uint8_t *big_curve_data = malloc(big_curve->block_size*big_curve->nblocks); uint32_t big_curve_data_len; TRY("malloc big curve", !big_curve_data); printf(C" Data malloc'ed at %p\n", big_curve_data); TRY("read curve", bsmp_read_curve (&client, big_curve, big_curve_data, &big_curve_data_len)); printf(C" Curve read!!\n"); printf("\n"C"Done!\n"); return 0; }
int main( int argc, char *argv[] ) { if( argc < 15 ) pexit1( "Usage: %s N_THREADS N_CLIENTS N_CYCLES N_QUESTS QSpread QuestsFile MapSizeX MapSizeY " "TreeDepth SpeedMax AppleRatio WallRatio BalanceType ActionsFile [print] [timeout]\n" "For more help check readme.txt .\n", argv[0] ); sv.num_threads = atoi( argv[1] ); sv.wl_client_count = atoi( argv[2] ); sv.wl_cycles = atoi( argv[3] ); sv.wl_quest_count = atoi( argv[4] ); sv.wl_quest_spread = atoi( argv[5] ); sv.wl_quest_file = argv[6]; assert( !sv.wl_quest_count || sv.wl_quest_spread ); int mapx = atoi( argv[7] ); int mapy = atoi( argv[8] ); int depth = atoi( argv[9] ); int speed_max = atoi( argv[10] ); int apple_map_ratio = atoi( argv[11] ); int wall_map_ratio = atoi( argv[12] ); char* balance = argv[13]; sv.m_actions_file = argv[14]; sv.wl_proportional_quests = 0; if( sv.wl_quest_count < 0 ) { sv.wl_quest_count = -sv.wl_quest_count; sv.wl_proportional_quests = 1; } int apple_pl_ratio; int wall_pl_ratio; // mike: ignore warning, apple_pl_ratio assigned in the function decode_entity_ratio( apple_map_ratio, apple_pl_ratio, &apple_map_ratio, &apple_pl_ratio, mapx, mapy, depth ); // mike: ignore warning, wall_pl_ratio assigned in the function decode_entity_ratio( wall_map_ratio, wall_pl_ratio, &wall_map_ratio, &wall_pl_ratio, mapx, mapy, depth ); if( argc >= 16 ) { int print_v = atoi( argv[15] ); if( print_v < 0 ) sv.print_pls = 1; print_v = abs( print_v ); assert( print_v >= 0 && print_v <= 100 ); sv.print_grid = (sv.wl_cycles * print_v ) / 100; if( print_v && sv.print_grid == 0 ) sv.print_grid = 1; if( sv.print_grid == 0 || sv.print_grid == sv.wl_cycles ) sv.print_progress = ( sv.wl_cycles < 10 ) ? 1 : (sv.wl_cycles/10); } if( argc >= 17 ) sv.wl_timeout = t_to_c( atoi( argv[16] ) ); else sv.wl_timeout = t_to_c( 3600 ); server_init( (char*)"./config/default.cfg", mapx, mapy, depth, speed_max/4, speed_max, apple_map_ratio, apple_pl_ratio, wall_map_ratio, wall_pl_ratio, balance ); sv.wl_stop = get_c() + sv.wl_timeout; int i; for( i = 1; i < sv.num_threads; ++i ) { svts[i].thread = thread_create( server_thread_run, (void*)&svts[i] ); assert( svts[i].thread ); } server_thread_run( &svts[0] ); server_deinit(); return 0; }
int main(int argc, char *argv[]) { struct timeval tp; int move[MAX_MOVE+1]={0}; int port=31415; int num_games=1; int i=1; while( i < argc ) { if( strcmp( argv[i], "-p" ) == 0 ) { if( i+1 >= argc ) { usage( argv[0] ); } port = atoi(argv[i+1]); i += 2; } else if( strcmp( argv[i], "-x" ) == 0 ) { is_human[0] = TRUE; i++; } else if( strcmp( argv[i], "-o" ) == 0 ) { is_human[1] = TRUE; i++; } else if( strcmp( argv[i], "-m" ) == 0 ) { if( i+2 >= argc ) { usage( argv[0] ); } move[0] = atoi(argv[i+1]); move[1] = atoi(argv[i+2]); if( move[0] < 1 || move[0] > 9 || move[1] < 1 || move[1] > 9 ) { usage( argv[0] ); } i += 3; } else if( strcmp( argv[i], "-t" ) == 0 ) { if( i+2 >= argc ) { usage( argv[0] ); } seconds_initially = atoi(argv[i+1]); seconds_per_move = atoi(argv[i+2]); if( seconds_initially <= 0 || seconds_per_move < 0 ) { usage( argv[0] ); } i += 3; } else if( strcmp( argv[i], "-n" ) == 0 ) { if( i+1 >= argc ) { usage( argv[0] ); } num_games = atoi(argv[i+1]); i += 2; } else { usage( argv[0] ); } } // generate a new random seed each time gettimeofday( &tp, NULL ); srandom(( unsigned int )( tp.tv_usec )); if( !is_human[0] || !is_human[1] ) { server_init( port ); } play_games( num_games,move ); cleanup(); return 0; }
/** * @brief LCD & LEDs periodic handling * @param localtime: the current LocalTime value * @retval None */ void Display_Periodic_Handle(__IO uint32_t localtime) { /* 250 ms */ if (localtime - DisplayTimer >= LCD_TIMER_MSECS) { DisplayTimer = localtime; /* We have got a new IP address so update the display */ if (IPaddress != netif.ip_addr.addr) { __IO uint8_t iptab[4]; uint8_t iptxt[20]; /* Read the new IP address */ IPaddress = netif.ip_addr.addr; iptab[0] = (uint8_t)(IPaddress >> 24); iptab[1] = (uint8_t)(IPaddress >> 16); iptab[2] = (uint8_t)(IPaddress >> 8); iptab[3] = (uint8_t)(IPaddress); sprintf((char*)iptxt, " %d.%d.%d.%d ", iptab[3], iptab[2], iptab[1], iptab[0]); /* Display the new IP address */ #if LWIP_DHCP if (netif.flags & NETIF_FLAG_DHCP) { /* Display the IP address */ LCD_DisplayStringLine(Line7, "IP address assigned "); LCD_DisplayStringLine(Line8, " by a DHCP server "); LCD_DisplayStringLine(Line9, iptxt); Delay(LCD_DELAY); /** Start the client/server application: only when a dynamic IP address has been obtained **/ /* Clear the LCD */ LCD_Clear(Black); LCD_SetBackColor(Black); LCD_SetTextColor(White); iptab[0] = (uint8_t)(IPaddress >> 24); iptab[1] = (uint8_t)(IPaddress >> 16); iptab[2] = (uint8_t)(IPaddress >> 8); iptab[3] = (uint8_t)(IPaddress); sprintf((char*)iptxt, "is: %d.%d.%d.%d ", iptab[3], iptab[2], iptab[1], iptab[0]); LCD_DisplayStringLine(Line0, " You are configured "); LCD_DisplayStringLine(Line2, iptxt); if(Server) { LCD_DisplayStringLine(Line1, "as a server, your IP"); /* Initialize the server application */ server_init(); } else { LCD_DisplayStringLine(Line1, "as a client, your IP"); /* Configure the IO Expander */ IOE_Config(); /* Enable the Touch Screen and Joystick interrupts */ IOE_ITConfig(IOE_ITSRC_TSC); /* Initialize the client application */ client_init(); } }
// Receives from another IP server and sends reply back void* IPTask(void* _IP_data_task) { struct IP_data* IP_data_task = (struct IP_data*) _IP_data_task; struct Context* context = (struct Context*) IP_data_task->ptr_context; unsigned char VPS = IP_data_task->VPS, *dataPtr, msgFlag; char printbuffer[DATASIZE]; /////////////////////////////////////// // task_id needs to be made generic! // //name_id[SENDERNAMESIZE] = {IPTask1_id,UNUSED,UNUSED}; /////////////////////////////////////// unsigned char name_id[SENDERNAMESIZE] = { context->task_id, UNUSED,UNUSED }; int server_port = IP_data_task->port; printf("IPTask%i: Started\n", VPS); // Initialize socket and port int s, client; unsigned int tmp; fd_set fdset; struct timeval timer; struct sockaddr_in c_addr; //unsigned char *pointer; if ((s = server_init(server_port)) < 0) //return(s); FD_ZERO(&fdset); FD_SET(s, &fdset); timer.tv_sec = 30; timer.tv_usec = 0; pthread_mutex_lock(context->mutex); while (communication_needed) { //Wait for IP packet if (select(s + 1, &fdset, NULL, NULL, NULL)> 0 ) { //#ifdef _DEBUG_VERBOSE printf("IPTask%i: SELECT has continued\n",VPS); //#endif tmp = sizeof(c_addr); client = accept(s, (struct sockaddr *)&c_addr, &tmp); if (client < 0) { printf("FAIL1: %s\n", strerror(errno)); } if (PRINT_STATUS) { printf("IPTask%i: client connect from %s\n",VPS, inet_ntoa(c_addr.sin_addr)); } usleep(10000); if ( (dataPtr = receive_cmd(client, VPS)) != NULL ) { //#ifdef _DEBUG_VERBOSE printf("IPTask%i: Got [%s] from receive_cmd (ASCII)\n", VPS,binary_to_hexbinaryString(dataPtr,dataPtr[1]+2,printbuffer)); //#endif dataPtr[1] = strlen((char*)dataPtr+2); // TODO remove warning // Convert hexbinary to binary if first char is a hexbin char else skip conv if( ((0x30 <= dataPtr[2]) && (dataPtr[2] <= 0x39)) || (('a' <= dataPtr[2] ) && (dataPtr[2] <= 'f')) || (('A' <= dataPtr[2]) && (dataPtr[2] <= 'F'))) { dataPtr[1] = hexbinary_to_binary( &dataPtr[2], &dataPtr[2]);} printf("IPTask%i: Receiving from port %i: [",VPS, server_port); printf("%s]\n", binary_to_hexbinaryString(dataPtr,dataPtr[1]+2,printbuffer)); //printf("IPTask%i: Has data after strcat: [%s]\n",VPS,binary_to_hexbinaryString(dataPtr,dataPtr[1]+2,printbuffer)); // Pass message on //#ifdef _DEBUG_VERBOSE printf("broadcast: IPTask%i\n",VPS); //#endif broadcast_msg(name_id, Out1, dataPtr); // DEBUG: Must wait for receiver to pass data on //sleep(1.5); // Begin listening on Condition for reply //#ifdef _DEBUG_VERBOSE printf("IPTask%i: calling receive()\n",VPS); //#endif //msgFlag = receive(IPTask1_id, context->condition, context->mutex); msgFlag = receive(VPS, context->condition, context->mutex); dataPtr = context->holder; printf(" *** IPTask%i: Sending on port %i: [%s] ***\n", VPS, server_port, binary_to_hexbinaryString(dataPtr,dataPtr[1]+2,printbuffer)); //#ifdef _DEBUG_VERBOSE printf("IPTask%i: received from sender: [%s]\n", VPS, binary_to_hexbinaryString(context->sender,SENDERNAMESIZE,printbuffer)); //#endif // Send reply back thru open connection // dataPtr+2 to avoid sending the VPS and length //if(server_port==MANAGEMENTPORT) IP_send_server_String(client, dataPtr+2, dataPtr[1]); //else IP_send_server_hexbinaryString(client, dataPtr+2, dataPtr[1]); IP_send_server_hexbinaryString(client, dataPtr+2, dataPtr[1]); printf("IPTask%i: ip send server func: \n", VPS); } else printf("IPTask%i: no data in client \n", VPS); // Shutdown connection if ((shutdown(client, 0) < 0) || (close(client) < 0)) { printf("FAIL2: %s\n", strerror(errno)); } } // end select } // while-end // Shutdown listening server if (s> 0) server_end(s); printf("IPTask%i: unlocking mutex and stopping\n",VPS); pthread_mutex_unlock(context->mutex); return NULL; }
/* OpenOCD can't really handle failure of this command. Patches welcome! :-) */ int handle_init_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) { if (argc!=0) return ERROR_COMMAND_SYNTAX_ERROR; int retval; static int initialized=0; if (initialized) return ERROR_OK; initialized=1; atexit(exit_handler); if (target_init(cmd_ctx) != ERROR_OK) return ERROR_FAIL; LOG_DEBUG("target init complete"); if ((retval=jtag_interface_init(cmd_ctx)) != ERROR_OK) { /* we must be able to set up the jtag interface */ return retval; } LOG_DEBUG("jtag interface init complete"); /* Try to initialize & examine the JTAG chain at this point, but * continue startup regardless */ if (jtag_init(cmd_ctx) == ERROR_OK) { LOG_DEBUG("jtag init complete"); if (target_examine() == ERROR_OK) { LOG_DEBUG("jtag examine complete"); } } if (flash_init_drivers(cmd_ctx) != ERROR_OK) return ERROR_FAIL; LOG_DEBUG("flash init complete"); if (mflash_init_drivers(cmd_ctx) != ERROR_OK) return ERROR_FAIL; LOG_DEBUG("mflash init complete"); if (nand_init(cmd_ctx) != ERROR_OK) return ERROR_FAIL; LOG_DEBUG("NAND init complete"); if (pld_init(cmd_ctx) != ERROR_OK) return ERROR_FAIL; LOG_DEBUG("pld init complete"); /* initialize tcp server */ server_init(); /* initialize telnet subsystem */ telnet_init("Open On-Chip Debugger"); gdb_init(); tcl_init(); /* allows tcl to just connect without going thru telnet */ target_register_event_callback(log_target_callback_event_handler, cmd_ctx); return ERROR_OK; }
rstatus_t conf_pool_each_transform(void *elem, void *data) { rstatus_t status; struct conf_pool *cp = elem; struct array *server_pool = data; struct server_pool *sp; ASSERT(cp->valid); sp = array_push(server_pool); ASSERT(sp != NULL); sp->idx = array_idx(server_pool, sp); sp->ctx = NULL; sp->p_conn = NULL; sp->nc_conn_q = 0; TAILQ_INIT(&sp->c_conn_q); array_null(&sp->server); sp->ncontinuum = 0; sp->nserver_continuum = 0; sp->continuum = NULL; sp->nlive_server = 0; sp->next_rebuild = 0LL; sp->name = cp->name; sp->addrstr = cp->listen.pname; sp->port = (uint16_t)cp->listen.port; sp->family = cp->listen.info.family; sp->addrlen = cp->listen.info.addrlen; sp->addr = (struct sockaddr *)&cp->listen.info.addr; sp->key_hash_type = cp->hash; sp->key_hash = hash_algos[cp->hash]; sp->dist_type = cp->distribution; sp->hash_tag = cp->hash_tag; sp->redis = cp->redis ? 1 : 0; sp->timeout = cp->timeout; sp->backlog = cp->backlog; sp->client_connections = (uint32_t)cp->client_connections; sp->server_connections = (uint32_t)cp->server_connections; sp->server_retry_timeout = (int64_t)cp->server_retry_timeout * 1000LL; sp->server_failure_limit = (uint32_t)cp->server_failure_limit; sp->auto_eject_hosts = cp->auto_eject_hosts ? 1 : 0; sp->preconnect = cp->preconnect ? 1 : 0; status = server_init(&sp->server, &cp->server, sp); if (status != NC_OK) { return status; } log_debug(LOG_VERB, "transform to pool %"PRIu32" '%.*s'", sp->idx, sp->name.len, sp->name.data); return NC_OK; }
/** * @brief Main function of whole server. * * @return EXIT_SUCCESS - when forked properly * @return EXIT_FAILURE - on error during server initialization * @return 0 - on application exit */ int main(void) { pid_t pid, sid; int fd; int ret = 0; struct sigaction sa; char buff[16] = {0}; sa.sa_handler = server_sig_handler; sigemptyset(&sa.sa_mask); sigaction(SIGTERM, &sa, NULL); openlog("ScopeServer", LOG_PID | LOG_LOCAL0, LOG_LOCAL0); pid = fork(); if(pid < 0) { syslog(LOG_ERR, "Fork failed, daemon couldn't start! (errno = %d)\n", -errno); return EXIT_FAILURE; } else if(pid > 0){ return EXIT_SUCCESS; } openlog("ScopeServer", LOG_PID | LOG_LOCAL0, LOG_LOCAL0); umask(0); syslog(LOG_INFO, "[ScopeServer]: Daemon started!\n"); sid = setsid(); if(sid < 0) { syslog(LOG_ERR, "Setsid failed, couldn't create new sid! (errno = %d)\n", -errno); return EXIT_FAILURE; } sprintf(buff, "%ld", (long)getpid()); fd = open(SCOPE_FILE_PID, O_CREAT | O_WRONLY); if(fd <0) { syslog(LOG_ERR, "Couldn't create pid file! (errno = %d)\n", -errno); ret = EXIT_FAILURE; goto init_fail; } if(write(fd, buff, strlen(buff)+1) < 0) { syslog(LOG_ERR, "Couldn't save pid file for ScopeServer! (errno = %d)\n", -errno); close(fd); ret = EXIT_FAILURE; goto init_fail; } close(fd); if(mkfifo(SCOPE_FILE_FIFO, O_RDWR) < 0) { syslog(LOG_ERR, "Couldn't create fifo file: %s! (errno = %d)\n", SCOPE_FILE_FIFO, -errno); ret = EXIT_FAILURE; goto init_fail; } if(chdir("/") < 0) { syslog(LOG_ERR, "Chdir failed! (errno = %d)\n", -errno); ret = EXIT_FAILURE; goto init_fail; } close(STDIN_FILENO); close(STDOUT_FILENO); close(STDERR_FILENO); if(server_init() < 0) { syslog(LOG_ERR, "Unable to initizalize the server! (errno = %d)\n", -errno); ret = EXIT_FAILURE; goto init_fail; } server_start(); init_fail: unlink(SCOPE_FILE_FIFO); unlink(SCOPE_FILE_PID); closelog(); return ret; }
int main(int argc, char *argv[]) { server_t server; char const *control = SDP_LOCAL_PATH; char const *user = "******", *group = "nobody"; int32_t detach = 1, opt; struct sigaction sa; while ((opt = getopt(argc, argv, "c:dg:hu:")) != -1) { switch (opt) { case 'c': /* control */ control = optarg; break; case 'd': /* do not detach */ detach = 0; break; case 'g': /* group */ group = optarg; break; case 'u': /* user */ user = optarg; break; case 'h': default: usage(); /* NOT REACHED */ } } log_open(SDPD, !detach); /* Become daemon if required */ if (detach && daemon(0, 0) < 0) { log_crit("Could not become daemon. %s (%d)", strerror(errno), errno); exit(1); } /* Set signal handlers */ memset(&sa, 0, sizeof(sa)); sa.sa_handler = sighandler; if (sigaction(SIGTERM, &sa, NULL) < 0 || sigaction(SIGHUP, &sa, NULL) < 0 || sigaction(SIGINT, &sa, NULL) < 0) { log_crit("Could not install signal handlers. %s (%d)", strerror(errno), errno); exit(1); } sa.sa_handler = SIG_IGN; if (sigaction(SIGPIPE, &sa, NULL) < 0) { log_crit("Could not install signal handlers. %s (%d)", strerror(errno), errno); exit(1); } /* Initialize server */ if (server_init(&server, control) < 0) exit(1); if ((user != NULL || group != NULL) && drop_root(user, group) < 0) exit(1); for (done = 0; !done; ) { if (server_do(&server) != 0) done ++; } server_shutdown(&server); log_close(); return (0); }
int main(int argc, char **argv) { struct server *s = NULL; pthread_t pt, ctl; int c, is_forward = 0; const char *config = SR_CONFIG_FILE; int daemon = 0; while ((c = getopt(argc,argv,"c:vhfd")) != -1) { switch(c) { case 'c': config = optarg; break; case 'h': help(argv[0]); exit(0); break; case 'f': is_forward = 1; break; case 'd': daemon = 1; break; case '?': printf("Try -h please\n"); exit(0); break; case 'v': printf("dnspod-sr 0.01\n"); exit(0); break; default: exit(0); break; } } sanity_test(0); drop_privilege("./"); daemonrize(daemon); trig_signals(1); global_now = time(NULL); //for read root.z g_nameservers[0] = g_nameservers[1] = NULL; init_globe(); init_mempool(); s = server_init(); s->is_forward = is_forward; read_config(config, (char *)s->logpath, s->forward, g_nameservers); // add default dns server 8.8.8.8, 114.114.114.114 if (g_nameservers[0] == NULL) { assert(g_nameservers[1] == NULL); g_nameservers[0] = strdup("119.29.29.29"); g_nameservers[1] = strdup("8.8.4.4"); } if (g_nameservers[1] == NULL) { if (strcmp(g_nameservers[0], "119.29.29.29") == 0) { g_nameservers[1] = strdup("8.8.4.4"); } else { g_nameservers[1] = strdup("119.29.29.29"); } } // if (create_fetcher(s, s->nfetcher) < 0) dns_error(0, "create worker"); if (create_author(s, s->nquizzer) < 0) dns_error(0, "create author"); if (pthread_create(&pt, NULL, (void *) time_cron, s) != 0) dns_error(0, "time cron error"); if (pthread_create(&ctl, NULL, (void *)recv_update, s) != 0) { dns_error(0, "recv update thread error"); } read_root(s->datasets, s->ttlexp); print_basic_debug(); global_serv = s; run_sentinel(s); return 0; }