void run(int argc, char **argv){ ready_list_t ready_list; ready_list_t ready_list_2; ready_list_t::iterator it; const Fdevents::events_t *events; Server serv(ssdb); Fdevents select; select.set(serv_link->fd(), FDEVENT_IN, 0, serv_link); select.set(serv.reader->fd(), FDEVENT_IN, 0, serv.reader); select.set(serv.writer->fd(), FDEVENT_IN, 0, serv.writer); int link_count = 0; while(!quit){ bool write_pending = false; ready_list.clear(); ready_list_2.clear(); if(write_pending || !ready_list.empty()){ // give links that are not in ready_list a chance events = select.wait(0); }else{ events = select.wait(50); } if(events == NULL){ log_fatal("events.wait error: %s", strerror(errno)); break; } for(int i=0; i<(int)events->size(); i++){ const Fdevent *fde = events->at(i); if(fde->data.ptr == serv_link){ Link *link = serv_link->accept(); if(link == NULL){ log_error("accept fail!"); continue; } link_count ++; log_info("new link from %s:%d, fd: %d, link_count: %d", link->remote_ip, link->remote_port, link->fd(), link_count); link->nodelay(); link->noblock(); link->create_time = millitime(); link->active_time = link->create_time; select.set(link->fd(), FDEVENT_IN, 1, link); }else if(fde->data.ptr == serv.reader || fde->data.ptr == serv.writer){ WorkerPool<Server::ProcWorker, ProcJob> *worker = (WorkerPool<Server::ProcWorker, ProcJob> *)fde->data.ptr; ProcJob job; if(worker->pop(&job) == 0){ log_fatal("reading result from workers error!"); exit(0); } if(proc_result(job, select, ready_list_2) == PROC_ERROR){ link_count --; } }else{ Link *link = (Link *)fde->data.ptr; // 不能同时监听读和写事件, 只能监听其中一个 if(fde->events & FDEVENT_ERR){ log_info("fd: %d error, delete link", link->fd()); link_count --; select.del(link->fd()); delete link; }else if(fde->events & FDEVENT_IN){ int len = link->read(); //log_trace("fd: %d read: %d", link->fd(), len); if(len <= 0){ log_info("fd: %d, read: %d, delete link", link->fd(), len); link_count --; select.del(link->fd()); delete link; }else{ ready_list.push_back(link); } }else if(fde->events & FDEVENT_OUT){ int len = link->write(); //log_trace("fd: %d write: %d", link->fd(), len); if(len <= 0){ log_info("fd: %d, write: %d, delete link", link->fd(), len); link_count --; select.del(link->fd()); delete link; }else if(link->output->empty()){ //log_trace("delete %d from select.out", link->fd()); select.clr(link->fd(), FDEVENT_OUT); if(!link->input->empty()){ ready_list.push_back(link); }else{ //log_trace("add %d to select.in", link->fd()); select.set(link->fd(), FDEVENT_IN, 1, link); } }else{ write_pending = true; } } } } for(it = ready_list.begin(); it != ready_list.end(); it ++){ Link *link = *it; const Request *req = link->recv(); if(req == NULL){ log_warn("fd: %d, link parse error, delete link", link->fd()); link_count --; select.del(link->fd()); delete link; continue; } if(req->empty()){ if(!select.isset(link->fd(), FDEVENT_IN)){ //log_trace("add %d to select.in", link->fd()); select.set(link->fd(), FDEVENT_IN, 1, link); } continue; } link->active_time = millitime(); ProcJob job; job.link = link; serv.proc(&job); if(job.result == PROC_THREAD){ select.del(link->fd()); continue; } if(job.result == PROC_BACKEND){ select.del(link->fd()); link_count --; continue; } if(proc_result(job, select, ready_list_2) == PROC_ERROR){ link_count --; } } // end foreach ready link ready_list.swap(ready_list_2); } }
int TcpClient::ProcessHeader(bool eof) { // search for the length/body separator, ':' char* body = 0; char* header = buffer_; char* end = buffer_ + bufferLength_; for (char* current = buffer_; current < end; current++) { if (*current == ':') { body = current + 1; break; } } // If we haven't gotten the entire header yet, return (keep reading) if (body == 0) { // EOF in the middle of a request is an error, otherwise its ok if (eof) { log_warn("EOF while reading header"); return HEADER_FAULT; } return HEADER_INCOMPLETE; // Keep reading } // check for comma separator if (commaExpected_) { if (*header != ',') { log_warn("Expected comma to separate messages"); log_warn("bufferLength=" << bufferLength_ << ", buffer=" << buffer_); return HEADER_FAULT; } header++; } contentLength_ = atoi(header); if (contentLength_ <= 0) { log_warn("Invalid string length specified " << contentLength_); log_warn("bufferLength=" << bufferLength_ << ", buffer=" << buffer_); return HEADER_FAULT; } int bufferSpaceAvail = buffer_ + MaxBufferLength - body; contentAvail_ = end - body; if (contentLength_ > MaxContentLength) { log_warn("String length too large=" << contentLength_ << ", max allowed=" << MaxContentLength); return HEADER_FAULT; } if (contentLength_ > bufferSpaceAvail) { // try to malloc the buffer space needed response_ = static_cast<char*>(malloc(contentLength_+1)); if (response_ == 0) { log_warn("Could not allocate space=" << contentLength_); return HEADER_FAULT; } // copy the content that was already read to the new space memcpy(response_,body,contentAvail_); responseAllocated_ = true; } else { responseAllocated_ = false; response_ = body; } response_[contentAvail_] = 0; log_info("specified content length is " << contentLength_); // a comma is expected to separate the next message commaExpected_ = true; return HEADER_COMPLETE; }
/** Perform the final (client-side) step of a circuit-creation handshake of * type <b>type</b>, using our state in <b>handshake_state</b> and the * server's response in <b>reply</b>. On success, generate <b>keys_out_len</b> * bytes worth of key material in <b>keys_out_len</b>, set * <b>rend_authenticator_out</b> to the "KH" field that can be used to * establish introduction points at this hop, and return 0. On failure, * return -1, and set *msg_out to an error message if this is worth * complaining to the usre about. */ int onion_skin_client_handshake(int type, const onion_handshake_state_t *handshake_state, const uint8_t *reply, size_t reply_len, uint8_t *keys_out, size_t keys_out_len, uint8_t *rend_authenticator_out, const char **msg_out) { if (handshake_state->tag != type) return -1; switch (type) { case ONION_HANDSHAKE_TYPE_TAP: if (reply_len != TAP_ONIONSKIN_REPLY_LEN) { if (msg_out) *msg_out = "TAP reply was not of the correct length."; return -1; } if (onion_skin_TAP_client_handshake(handshake_state->u.tap, (const char*)reply, (char *)keys_out, keys_out_len, msg_out) < 0) return -1; memcpy(rend_authenticator_out, reply+DH_KEY_LEN, DIGEST_LEN); return 0; case ONION_HANDSHAKE_TYPE_FAST: if (reply_len != CREATED_FAST_LEN) { if (msg_out) *msg_out = "TAP reply was not of the correct length."; return -1; } if (fast_client_handshake(handshake_state->u.fast, reply, keys_out, keys_out_len, msg_out) < 0) return -1; memcpy(rend_authenticator_out, reply+DIGEST_LEN, DIGEST_LEN); return 0; case ONION_HANDSHAKE_TYPE_NTOR: if (reply_len < NTOR_REPLY_LEN) { if (msg_out) *msg_out = "ntor reply was not of the correct length."; return -1; } { size_t keys_tmp_len = keys_out_len + DIGEST_LEN; uint8_t *keys_tmp = tor_malloc(keys_tmp_len); if (onion_skin_ntor_client_handshake(handshake_state->u.ntor, reply, keys_tmp, keys_tmp_len, msg_out) < 0) { tor_free(keys_tmp); return -1; } memcpy(keys_out, keys_tmp, keys_out_len); memcpy(rend_authenticator_out, keys_tmp + keys_out_len, DIGEST_LEN); memwipe(keys_tmp, 0, keys_tmp_len); tor_free(keys_tmp); } return 0; default: log_warn(LD_BUG, "called with unknown handshake state type %d", type); tor_fragile_assert(); return -1; } }
void NetworkServer::serve(){ writer = new ProcWorkerPool("writer"); writer->start(WRITER_THREADS); reader = new ProcWorkerPool("reader"); reader->start(READER_THREADS); ready_list_t ready_list; ready_list_t ready_list_2; ready_list_t::iterator it; const Fdevents::events_t *events; fdes->set(serv_link->fd(), FDEVENT_IN, 0, serv_link); fdes->set(this->reader->fd(), FDEVENT_IN, 0, this->reader); fdes->set(this->writer->fd(), FDEVENT_IN, 0, this->writer); uint32_t last_ticks = g_ticks; while(!quit){ // status report if((uint32_t)(g_ticks - last_ticks) >= STATUS_REPORT_TICKS){ last_ticks = g_ticks; log_info("server running, links: %d", this->link_count); } ready_list.swap(ready_list_2); ready_list_2.clear(); if(!ready_list.empty()){ // ready_list not empty, so we should return immediately events = fdes->wait(0); }else{ events = fdes->wait(50); } if(events == NULL){ log_fatal("events.wait error: %s", strerror(errno)); break; } for(int i=0; i<(int)events->size(); i++){ const Fdevent *fde = events->at(i); if(fde->data.ptr == serv_link){ Link *link = accept_link(); if(link){ this->link_count ++; log_debug("new link from %s:%d, fd: %d, links: %d", link->remote_ip, link->remote_port, link->fd(), this->link_count); fdes->set(link->fd(), FDEVENT_IN, 1, link); } }else if(fde->data.ptr == this->reader || fde->data.ptr == this->writer){ ProcWorkerPool *worker = (ProcWorkerPool *)fde->data.ptr; ProcJob job; if(worker->pop(&job) == 0){ log_fatal("reading result from workers error!"); exit(0); } if(proc_result(&job, &ready_list) == PROC_ERROR){ // } }else{ proc_client_event(fde, &ready_list); } } for(it = ready_list.begin(); it != ready_list.end(); it ++){ Link *link = *it; if(link->error()){ destroy_link(link); continue; } const Request *req = link->recv(); if(req == NULL){ log_warn("fd: %d, link parse error, delete link", link->fd()); destroy_link(link); continue; } if(req->empty()){ link->unRef(); fdes->set(link->fd(), FDEVENT_IN, 1, link); log_debug("serve parse incomplete request, remote_ip: %s ref: %d", link->remote_ip, link->ref_count); continue; } link->active_time = millitime(); //FIXME char remote_ip_port[32]; snprintf(remote_ip_port, 32, "%s:%d", link->remote_ip, link->remote_port); this->active_links.add(remote_ip_port,(int64_t)link->active_time); ProcJob job; job.link = link; this->proc(&job); if(job.result == PROC_THREAD){ fdes->del(link->fd()); continue; } if(job.result == PROC_BACKEND){ fdes->del(link->fd()); this->link_count --; char remote_ip_port[32]; snprintf(remote_ip_port, 32, "%s:%d", link->remote_ip, link->remote_port); this->link_map.erase(remote_ip_port); this->active_links.del(remote_ip_port); // don't delete link continue; } if(proc_result(&job, &ready_list_2) == PROC_ERROR){ // } } // end foreach ready link //every event loop destroy_idle_link(); } }
/** daemonize, drop user priviliges and chroot if needed */ static void perform_setup(struct daemon* daemon, struct config_file* cfg, int debug_mode, const char** cfgfile) { #ifdef HAVE_GETPWNAM struct passwd *pwd = NULL; uid_t uid; gid_t gid; /* initialize, but not to 0 (root) */ memset(&uid, 112, sizeof(uid)); memset(&gid, 112, sizeof(gid)); log_assert(cfg); if(cfg->username && cfg->username[0]) { if((pwd = getpwnam(cfg->username)) == NULL) fatal_exit("user '%s' does not exist.", cfg->username); uid = pwd->pw_uid; gid = pwd->pw_gid; /* endpwent below, in case we need pwd for setusercontext */ } #endif /* init syslog (as root) if needed, before daemonize, otherwise * a fork error could not be printed since daemonize closed stderr.*/ if(cfg->use_syslog) { log_init(cfg->logfile, cfg->use_syslog, cfg->chrootdir); } /* if using a logfile, we cannot open it because the logfile would * be created with the wrong permissions, we cannot chown it because * we cannot chown system logfiles, so we do not open at all. * So, using a logfile, the user does not see errors unless -d is * given to unbound on the commandline. */ /* read ssl keys while superuser and outside chroot */ #ifdef HAVE_SSL if(!(daemon->rc = daemon_remote_create(cfg))) fatal_exit("could not set up remote-control"); if(cfg->ssl_service_key && cfg->ssl_service_key[0]) { if(!(daemon->listen_sslctx = listen_sslctx_create( cfg->ssl_service_key, cfg->ssl_service_pem, NULL))) fatal_exit("could not set up listen SSL_CTX"); } if(!(daemon->connect_sslctx = connect_sslctx_create(NULL, NULL, NULL))) fatal_exit("could not set up connect SSL_CTX"); #endif #ifdef HAVE_KILL /* check old pid file before forking */ if(cfg->pidfile && cfg->pidfile[0]) { /* calculate position of pidfile */ if(cfg->pidfile[0] == '/') daemon->pidfile = strdup(cfg->pidfile); else daemon->pidfile = fname_after_chroot(cfg->pidfile, cfg, 1); if(!daemon->pidfile) fatal_exit("pidfile alloc: out of memory"); checkoldpid(daemon->pidfile, /* true if pidfile is inside chrootdir, or nochroot */ !(cfg->chrootdir && cfg->chrootdir[0]) || (cfg->chrootdir && cfg->chrootdir[0] && strncmp(daemon->pidfile, cfg->chrootdir, strlen(cfg->chrootdir))==0)); } #endif /* daemonize because pid is needed by the writepid func */ if(!debug_mode && cfg->do_daemonize) { detach(); } /* write new pidfile (while still root, so can be outside chroot) */ #ifdef HAVE_KILL if(cfg->pidfile && cfg->pidfile[0]) { writepid(daemon->pidfile, getpid()); if(!(cfg->chrootdir && cfg->chrootdir[0]) || (cfg->chrootdir && cfg->chrootdir[0] && strncmp(daemon->pidfile, cfg->chrootdir, strlen(cfg->chrootdir))==0)) { /* delete of pidfile could potentially work, * chown to get permissions */ if(cfg->username && cfg->username[0]) { if(chown(daemon->pidfile, uid, gid) == -1) { log_err("cannot chown %u.%u %s: %s", (unsigned)uid, (unsigned)gid, daemon->pidfile, strerror(errno)); } } } } #else (void)daemon; #endif /* Set user context */ #ifdef HAVE_GETPWNAM if(cfg->username && cfg->username[0]) { #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, uid, (unsigned) LOGIN_SETALL & ~LOGIN_SETUSER & ~LOGIN_SETGROUP) != 0) log_warn("unable to setusercontext %s: %s", cfg->username, strerror(errno)); #endif /* HAVE_SETUSERCONTEXT */ } #endif /* HAVE_GETPWNAM */ /* box into the chroot */ #ifdef HAVE_CHROOT if(cfg->chrootdir && cfg->chrootdir[0]) { if(chdir(cfg->chrootdir)) { fatal_exit("unable to chdir to chroot %s: %s", cfg->chrootdir, strerror(errno)); } verbose(VERB_QUERY, "chdir to %s", cfg->chrootdir); if(chroot(cfg->chrootdir)) fatal_exit("unable to chroot to %s: %s", cfg->chrootdir, strerror(errno)); if(chdir("/")) fatal_exit("unable to chdir to / in chroot %s: %s", cfg->chrootdir, strerror(errno)); verbose(VERB_QUERY, "chroot to %s", cfg->chrootdir); if(strncmp(*cfgfile, cfg->chrootdir, strlen(cfg->chrootdir)) == 0) (*cfgfile) += strlen(cfg->chrootdir); /* adjust stored pidfile for chroot */ if(daemon->pidfile && daemon->pidfile[0] && strncmp(daemon->pidfile, cfg->chrootdir, strlen(cfg->chrootdir))==0) { char* old = daemon->pidfile; daemon->pidfile = strdup(old+strlen(cfg->chrootdir)); free(old); if(!daemon->pidfile) log_err("out of memory in pidfile adjust"); } daemon->chroot = strdup(cfg->chrootdir); if(!daemon->chroot) log_err("out of memory in daemon chroot dir storage"); } #else (void)cfgfile; #endif /* change to working directory inside chroot */ if(cfg->directory && cfg->directory[0]) { char* dir = cfg->directory; if(cfg->chrootdir && cfg->chrootdir[0] && strncmp(dir, cfg->chrootdir, strlen(cfg->chrootdir)) == 0) dir += strlen(cfg->chrootdir); if(dir[0]) { if(chdir(dir)) { fatal_exit("Could not chdir to %s: %s", dir, strerror(errno)); } verbose(VERB_QUERY, "chdir to %s", dir); } } /* drop permissions after chroot, getpwnam, pidfile, syslog done*/ #ifdef HAVE_GETPWNAM if(cfg->username && cfg->username[0]) { # ifdef HAVE_INITGROUPS if(initgroups(cfg->username, gid) != 0) log_warn("unable to initgroups %s: %s", cfg->username, strerror(errno)); # endif /* HAVE_INITGROUPS */ endpwent(); #ifdef HAVE_SETRESGID if(setresgid(gid,gid,gid) != 0) #elif defined(HAVE_SETREGID) && !defined(DARWIN_BROKEN_SETREUID) if(setregid(gid,gid) != 0) #else /* use setgid */ if(setgid(gid) != 0) #endif /* HAVE_SETRESGID */ fatal_exit("unable to set group id of %s: %s", cfg->username, strerror(errno)); #ifdef HAVE_SETRESUID if(setresuid(uid,uid,uid) != 0) #elif defined(HAVE_SETREUID) && !defined(DARWIN_BROKEN_SETREUID) if(setreuid(uid,uid) != 0) #else /* use setuid */ if(setuid(uid) != 0) #endif /* HAVE_SETRESUID */ fatal_exit("unable to set user id of %s: %s", cfg->username, strerror(errno)); verbose(VERB_QUERY, "drop user privileges, run as %s", cfg->username); } #endif /* HAVE_GETPWNAM */ /* file logging inited after chroot,chdir,setuid is done so that * it would succeed on SIGHUP as well */ if(!cfg->use_syslog) log_init(cfg->logfile, cfg->use_syslog, cfg->chrootdir); }
void tw_master_cycle(struct env_master* env) { int sigio; sigset_t set; struct itimerval itv; unsigned int live; // msec: 1/1000 sec unsigned int delay; int i, r; struct timeval tv; nc_process_role = NC_PROCESS_MASTER; nc_setproctitle("master"); sigemptyset(&set); sigaddset(&set, SIGCHLD); sigaddset(&set, SIGALRM); sigaddset(&set, SIGIO); sigaddset(&set, SIGINT); //reconfigure sigaddset(&set, SIGHUP); // noaccept sigaddset(&set, SIGWINCH); sigaddset(&set, SIGTERM); sigaddset(&set, SIGQUIT); //sigaddset(&set, ngx_signal_value(NGX_CHANGEBIN_SIGNAL)); //sigaddset(&set, ngx_signal_value(NGX_REOPEN_SIGNAL)); // block above singalling if (sigprocmask(SIG_BLOCK, &set, NULL) == -1) { log_error("sigprocmask() failed %s", strerror(errno)); } sigemptyset(&set); nc_start_worker_processes(env); // master //delay = 1000; delay = 1; // 1ms sigio = 0; live = 1; nc_reload_start = 0; for ( ;; ) { // no singal, alarm event if (nc_sigalarm) { sigio = 0; // like slow start // delay *= 2; nc_sigalarm= 0; rebuild_fdset(); tv.tv_sec = 0; tv.tv_usec = 0; //log_error("tyson, %d", fds_width); r = select(fds_width, &rdfs, NULL, NULL, &tv); if (r) { for (i = 0; i < fds_width; i++) { if (FD_ISSET(i, &rdfs)){ nc_read_channel(i, &env_global.ctrl_msg, sizeof(nc_channel_msg_t)); } } } /* for (i = 0; i < nc_last_process; i++) { if (nc_processes[i].pid == -1 || nc_processes[i].pid == 0){ continue; } //log_debug(LOG_ERR, "tyson here"); nc_read_channel(nc_processes[0].channel_back[0], &env_global.ctrl_msg, sizeof(nc_channel_msg_t)); //nc_read_channel(nc_processes[i].channel[1], &env_global.ctrl_msg, sizeof(nc_channel_msg_t)); }*/ if (nc_reload_start && !nc_cnt_reload) { nc_reload_start = 0; nc_cnt_reload = NC_CNT_RELOAD_MAGIC; } } log_debug("termination cycle: %d", delay); itv.it_interval.tv_sec = 0; itv.it_interval.tv_usec = 0; itv.it_value.tv_sec = delay / 1000; itv.it_value.tv_usec = (delay % 1000 ) * 1000; // produce SIGALARM if (setitimer(ITIMER_REAL, &itv, NULL) == -1) { log_debug("setitimer() failed %s", strerror(errno)); } //log_debug("sigsuspend"); sigsuspend(&set); // wake up this place log_debug("wake up, sigio %d", sigio); if (nc_reap) { nc_reap = 0; log_warn("reap children"); live = nc_reap_children(); } // best effort, send signal via channel before death // if (!live && (nc_terminate || nc_quit)) { if (nc_terminate) { nc_term_children(); sleep(1); nc_master_post_run(env); exit(1); } if (nc_terminate) { if (delay == 0) { delay = 50; } if (sigio) { sigio--; continue; } sigio = env->worker_processes; // kill -9 if (delay > 2000) { nc_signal_worker_processes(SIGKILL); } else { nc_signal_worker_processes(SIGTERM); } continue; } // graceful shutdown if (nc_quit) { nc_signal_worker_processes(SIGQUIT); /* ls = cycle->listening.elts; for (n = 0; n < cycle->listening.nelts; n++) { if (ngx_close_socket(ls[n].fd) == -1) { ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_socket_errno, ngx_close_socket_n " %V failed", &ls[n].addr_text); } } cycle->listening.nelts = 0; */ continue; } // todo /* if (nc_restart) { nc_restart = 0; nc_start_worker_processes(env); live = 1; } */ #ifdef GRACEFUL if (nc_reload && !nc_reload_start) { nc_reload = 0; nc_reload_start = 1; nc_cnt_reload = NC_CNT_RELOAD_MAGIC; //reset after all worker processes reload done nc_signal_worker_processes(SIGHUP); continue; } else if (nc_reload) { log_debug(LOG_ERR, "deny reload request due to reason: still in reconfiguation status %d", nc_reload_start); } #endif } }
int MRtmpHandshake::handshake_with_client(MTcpSocket & skt) { int ret = ERROR_SUCCESS; int c0c1Size = C0_SIZE + C1_SIZE; char* c0c1 = new char[c0c1Size]; mAutoFreeArray(char, c0c1); if ((ret = skt.readFully(c0c1, c0c1Size)) <= 0) { log_warn("read c0c1 failed. ret=%d", ret); return ret; } log_verbose("read c0c1 success."); bool encrypted = false; bool FP9HandShake = false; int type = c0c1[0]; if (type == 3) { encrypted = false; } else if (type == 6 || type == 8){ encrypted = true; FP9HandShake = true; /* use FP10 if client is capable */ if (c0c1[5] == 128) { type = 8; } } else { ret = ERROR_RTMP_PLAIN_REQUIRED; log_warn("only support rtmp plain text. ret=%d", ret); return ret; } //if c1[4] is not 0,use complex handshake if (!FP9HandShake && c0c1[5]) { FP9HandShake = true; } log_verbose("check c0 success, required plain text."); if (FP9HandShake) { // use complex handshake ret = use_complex_response(skt, c0c1 + 1, encrypted); if (ret == ERROR_SUCCESS) { log_trace("complex handshake success."); return ret; } log_trace("--------------> ret = %d", ret); if (ret != ERROR_RTMP_TRY_SIMPLE_HS) { log_error("complex handshake failed. ret=%d", ret); return ret; } } else { //use simple handshake if ((ret = use_simple_response(skt,c0c1)) != ERROR_SUCCESS) { log_warn("simple handshake read c2 failed. ret=%d", ret); return ret; } log_trace("simple handshake success."); } if (ret == ERROR_RTMP_TRY_SIMPLE_HS) ret = use_simple_response(skt,c0c1); return ret; }
// global sender initialize (not thread specific) iterator_t* send_init(void) { // compute number of targets uint64_t allowed = blacklist_count_allowed(); assert(allowed <= (1LL << 32)); if (allowed == (1LL << 32)) { zsend.targets = 0xFFFFFFFF; } else { zsend.targets = allowed; } if (zsend.targets > zconf.max_targets) { zsend.targets = zconf.max_targets; } // generate a new primitive root and starting position iterator_t *it; it = iterator_init(zconf.senders, zconf.shard_num, zconf.total_shards); // process the dotted-notation addresses passed to ZMAP and determine // the source addresses from which we'll send packets; srcip_first = inet_addr(zconf.source_ip_first); if (srcip_first == INADDR_NONE) { log_fatal("send", "invalid begin source ip address: `%s'", zconf.source_ip_first); } srcip_last = inet_addr(zconf.source_ip_last); if (srcip_last == INADDR_NONE) { log_fatal("send", "invalid end source ip address: `%s'", zconf.source_ip_last); } log_debug("send", "srcip_first: %u", srcip_first); log_debug("send", "srcip_last: %u", srcip_last); if (srcip_first == srcip_last) { srcip_offset = 0; num_src_addrs = 1; } else { uint32_t ip_first = ntohl(srcip_first); uint32_t ip_last = ntohl(srcip_last); assert(ip_first && ip_last); assert(ip_last > ip_first); uint32_t offset = (uint32_t) (aesrand_getword() & 0xFFFFFFFF); srcip_offset = offset % (srcip_last - srcip_first); num_src_addrs = ip_last - ip_first + 1; } // process the source port range that ZMap is allowed to use num_src_ports = zconf.source_port_last - zconf.source_port_first + 1; log_debug("send", "will send from %i address%s on %u source ports", num_src_addrs, ((num_src_addrs ==1 ) ? "":"es"), num_src_ports); // global initialization for send module assert(zconf.probe_module); if (zconf.probe_module->global_initialize) { zconf.probe_module->global_initialize(&zconf); } // concert specified bandwidth to packet rate if (zconf.bandwidth > 0) { int pkt_len = zconf.probe_module->packet_length; pkt_len *= 8; pkt_len += 8*24; // 7 byte MAC preamble, 1 byte Start frame, // 4 byte CRC, 12 byte inter-frame gap if (pkt_len < 84*8) { pkt_len = 84*8; } if (zconf.bandwidth / pkt_len > 0xFFFFFFFF) { zconf.rate = 0; } else { zconf.rate = zconf.bandwidth / pkt_len; if (zconf.rate == 0) { log_warn("send", "bandwidth %lu bit/s is slower than 1 pkt/s, " "setting rate to 1 pkt/s", zconf.bandwidth); zconf.rate = 1; } } log_debug("send", "using bandwidth %lu bits/s, rate set to %d pkt/s", zconf.bandwidth, zconf.rate); } // Get the source hardware address, and give it to the probe // module if (get_iface_hw_addr(zconf.iface, zconf.hw_mac)) { log_fatal("send", "could not retrieve hardware address for " "interface: %s", zconf.iface); return NULL; } if (zconf.dryrun) { log_info("send", "dryrun mode -- won't actually send packets"); } // initialize random validation key validate_init(); zsend.start = now(); return it; }
/** Given an encrypted DH public key as generated by onion_skin_create, * and the private key for this onion router, generate the reply (128-byte * DH plus the first 20 bytes of shared key material), and store the * next key_out_len bytes of key material in key_out. */ int onion_skin_server_handshake(const char *onion_skin, /*ONIONSKIN_CHALLENGE_LEN*/ crypto_pk_t *private_key, crypto_pk_t *prev_private_key, char *handshake_reply_out, /*ONIONSKIN_REPLY_LEN*/ char *key_out, size_t key_out_len) { char challenge[ONIONSKIN_CHALLENGE_LEN]; crypto_dh_t *dh = NULL; ssize_t len; char *key_material=NULL; size_t key_material_len=0; int i; crypto_pk_t *k; len = -1; for (i=0;i<2;++i) { k = i==0?private_key:prev_private_key; if (!k) break; note_crypto_pk_op(DEC_ONIONSKIN); len = crypto_pk_private_hybrid_decrypt(k, challenge, ONIONSKIN_CHALLENGE_LEN, onion_skin, ONIONSKIN_CHALLENGE_LEN, PK_PKCS1_OAEP_PADDING,0); if (len>0) break; } if (len<0) { log_info(LD_PROTOCOL, "Couldn't decrypt onionskin: client may be using old onion key"); goto err; } else if (len != DH_KEY_LEN) { log_warn(LD_PROTOCOL, "Unexpected onionskin length after decryption: %ld", (long)len); goto err; } dh = crypto_dh_new(DH_TYPE_CIRCUIT); if (!dh) { log_warn(LD_BUG, "Couldn't allocate DH key"); goto err; } if (crypto_dh_get_public(dh, handshake_reply_out, DH_KEY_LEN)) { log_info(LD_GENERAL, "crypto_dh_get_public failed."); goto err; } key_material_len = DIGEST_LEN+key_out_len; key_material = tor_malloc(key_material_len); len = crypto_dh_compute_secret(LOG_PROTOCOL_WARN, dh, challenge, DH_KEY_LEN, key_material, key_material_len); if (len < 0) { log_info(LD_GENERAL, "crypto_dh_compute_secret failed."); goto err; } /* send back H(K|0) as proof that we learned K. */ memcpy(handshake_reply_out+DH_KEY_LEN, key_material, DIGEST_LEN); /* use the rest of the key material for our shared keys, digests, etc */ memcpy(key_out, key_material+DIGEST_LEN, key_out_len); memset(challenge, 0, sizeof(challenge)); memset(key_material, 0, key_material_len); tor_free(key_material); crypto_dh_free(dh); return 0; err: memset(challenge, 0, sizeof(challenge)); if (key_material) { memset(key_material, 0, key_material_len); tor_free(key_material); } if (dh) crypto_dh_free(dh); return -1; }
static int udp_global_initialize(struct state_conf *conf) { char *args, *c; int i; unsigned int n; FILE *inp; num_ports = conf->source_port_last - conf->source_port_first + 1; udp_send_msg = strdup(udp_send_msg_default); udp_send_msg_len = strlen(udp_send_msg); if (!(conf->probe_args && strlen(conf->probe_args) > 0)) return(0); args = strdup(conf->probe_args); if (! args) exit(1); c = strchr(args, ':'); if (! c) { free(args); free(udp_send_msg); log_fatal("udp", udp_usage_error); exit(1); } *c++ = 0; if (strcmp(args, "text") == 0) { free(udp_send_msg); udp_send_msg = strdup(c); udp_send_msg_len = strlen(udp_send_msg); } else if (strcmp(args, "file") == 0 || strcmp(args, "template") == 0) { inp = fopen(c, "rb"); if (!inp) { free(args); free(udp_send_msg); log_fatal("udp", "could not open UDP data file '%s'\n", c); exit(1); } free(udp_send_msg); udp_send_msg = xmalloc(MAX_UDP_PAYLOAD_LEN); udp_send_msg_len = fread(udp_send_msg, 1, MAX_UDP_PAYLOAD_LEN, inp); fclose(inp); if (strcmp(args, "template") == 0) { udp_send_substitutions = 1; udp_template = udp_template_load(udp_send_msg, udp_send_msg_len); } } else if (strcmp(args, "hex") == 0) { udp_send_msg_len = strlen(c) / 2; free(udp_send_msg); udp_send_msg = xmalloc(udp_send_msg_len); for (i=0; i < udp_send_msg_len; i++) { if (sscanf(c + (i*2), "%2x", &n) != 1) { free(args); free(udp_send_msg); log_fatal("udp", "non-hex character: '%c'", c[i*2]); exit(1); } udp_send_msg[i] = (n & 0xff); } } else { log_fatal("udp", udp_usage_error); free(udp_send_msg); free(args); exit(1); } if (udp_send_msg_len > MAX_UDP_PAYLOAD_LEN) { log_warn("udp", "warning: reducing UDP payload to %d " "bytes (from %d) to fit on the wire\n", MAX_UDP_PAYLOAD_LEN, udp_send_msg_len); udp_send_msg_len = MAX_UDP_PAYLOAD_LEN; } free(args); return EXIT_SUCCESS; }
/** Executes the given process as a child process of Tor. This function is * responsible for setting up the child process and run it. This includes * setting up pipes for interprocess communication, initialize the waitpid * callbacks, and finally run fork() followed by execve(). Returns * <b>PROCESS_STATUS_RUNNING</b> upon success. */ process_status_t process_unix_exec(process_t *process) { static int max_fd = -1; process_unix_t *unix_process; pid_t pid; int stdin_pipe[2]; int stdout_pipe[2]; int stderr_pipe[2]; int retval, fd; unix_process = process_get_unix_process(process); /* Create standard in pipe. */ retval = pipe(stdin_pipe); if (-1 == retval) { log_warn(LD_PROCESS, "Unable to create pipe for stdin " "communication with process: %s", strerror(errno)); return PROCESS_STATUS_ERROR; } /* Create standard out pipe. */ retval = pipe(stdout_pipe); if (-1 == retval) { log_warn(LD_PROCESS, "Unable to create pipe for stdout " "communication with process: %s", strerror(errno)); /** Cleanup standard in pipe. */ close(stdin_pipe[0]); close(stdin_pipe[1]); return PROCESS_STATUS_ERROR; } /* Create standard error pipe. */ retval = pipe(stderr_pipe); if (-1 == retval) { log_warn(LD_PROCESS, "Unable to create pipe for stderr " "communication with process: %s", strerror(errno)); /** Cleanup standard in pipe. */ close(stdin_pipe[0]); close(stdin_pipe[1]); /** Cleanup standard out pipe. */ close(stdout_pipe[0]); close(stdout_pipe[1]); return PROCESS_STATUS_ERROR; } #ifdef _SC_OPEN_MAX if (-1 == max_fd) { max_fd = (int)sysconf(_SC_OPEN_MAX); if (max_fd == -1) { max_fd = DEFAULT_MAX_FD; log_warn(LD_PROCESS, "Cannot find maximum file descriptor, assuming: %d", max_fd); } } #else /* !(defined(_SC_OPEN_MAX)) */ max_fd = DEFAULT_MAX_FD; #endif /* defined(_SC_OPEN_MAX) */ pid = fork(); if (0 == pid) { /* This code is running in the child process context. */ #if defined(HAVE_SYS_PRCTL_H) && defined(__linux__) /* Attempt to have the kernel issue a SIGTERM if the parent * goes away. Certain attributes of the binary being execve()ed * will clear this during the execve() call, but it's better * than nothing. */ prctl(PR_SET_PDEATHSIG, SIGTERM); #endif /* defined(HAVE_SYS_PRCTL_H) && defined(__linux__) */ /* Link process stdout to the write end of the pipe. */ retval = dup2(stdout_pipe[1], STDOUT_FILENO); if (-1 == retval) goto error; /* Link process stderr to the write end of the pipe. */ retval = dup2(stderr_pipe[1], STDERR_FILENO); if (-1 == retval) goto error; /* Link process stdin to the read end of the pipe */ retval = dup2(stdin_pipe[0], STDIN_FILENO); if (-1 == retval) goto error; /* Close our pipes now after they have been dup2()'ed. */ close(stderr_pipe[0]); close(stderr_pipe[1]); close(stdout_pipe[0]); close(stdout_pipe[1]); close(stdin_pipe[0]); close(stdin_pipe[1]); /* Close all other fds, including the read end of the pipe. XXX: We should * now be doing enough FD_CLOEXEC setting to make this needless. */ for (fd = STDERR_FILENO + 1; fd < max_fd; fd++) close(fd); /* Create the argv value for our new process. */ char **argv = process_get_argv(process); /* Create the env value for our new process. */ process_environment_t *env = process_get_environment(process); /* Call the requested program. */ retval = execve(argv[0], argv, env->unixoid_environment_block); /* If we made it here it is because execve failed :-( */ if (-1 == retval) fprintf(stderr, "Call to execve() failed: %s", strerror(errno)); tor_free(argv); process_environment_free(env); tor_assert_unreached(); error: /* LCOV_EXCL_START */ fprintf(stderr, "Error from child process: %s", strerror(errno)); _exit(1); /* LCOV_EXCL_STOP */ } /* We are in the parent process. */ if (-1 == pid) { log_warn(LD_PROCESS, "Failed to create child process: %s", strerror(errno)); /** Cleanup standard in pipe. */ close(stdin_pipe[0]); close(stdin_pipe[1]); /** Cleanup standard out pipe. */ close(stdout_pipe[0]); close(stdout_pipe[1]); /** Cleanup standard error pipe. */ close(stderr_pipe[0]); close(stderr_pipe[1]); return PROCESS_STATUS_ERROR; } /* Register our PID. */ unix_process->pid = pid; /* Setup waitpid callbacks. */ unix_process->waitpid = set_waitpid_callback(pid, process_unix_waitpid_callback, process); /* Handle standard out. */ unix_process->stdout_handle.fd = stdout_pipe[0]; retval = close(stdout_pipe[1]); if (-1 == retval) { log_warn(LD_PROCESS, "Failed to close write end of standard out pipe: %s", strerror(errno)); } /* Handle standard error. */ unix_process->stderr_handle.fd = stderr_pipe[0]; retval = close(stderr_pipe[1]); if (-1 == retval) { log_warn(LD_PROCESS, "Failed to close write end of standard error pipe: %s", strerror(errno)); } /* Handle standard in. */ unix_process->stdin_handle.fd = stdin_pipe[1]; retval = close(stdin_pipe[0]); if (-1 == retval) { log_warn(LD_PROCESS, "Failed to close read end of standard in pipe: %s", strerror(errno)); } /* Setup our handles. */ process_unix_setup_handle(process, &unix_process->stdout_handle, EV_READ|EV_PERSIST, stdout_read_callback); process_unix_setup_handle(process, &unix_process->stderr_handle, EV_READ|EV_PERSIST, stderr_read_callback); process_unix_setup_handle(process, &unix_process->stdin_handle, EV_WRITE|EV_PERSIST, stdin_write_callback); /* Start reading from standard out and standard error. */ process_unix_start_reading(&unix_process->stdout_handle); process_unix_start_reading(&unix_process->stderr_handle); return PROCESS_STATUS_RUNNING; }
/** Given zero or more zlib-compressed or gzip-compressed strings of * total length * <b>in_len</b> bytes at <b>in</b>, uncompress them into a newly allocated * buffer, using the method described in <b>method</b>. Store the uncompressed * string in *<b>out</b>, and its length in *<b>out_len</b>. Return 0 on * success, -1 on failure. * * If <b>complete_only</b> is true, we consider a truncated input as a * failure; otherwise we decompress as much as we can. Warn about truncated * or corrupt inputs at <b>protocol_warn_level</b>. */ int tor_gzip_uncompress(char **out, size_t *out_len, const char *in, size_t in_len, compress_method_t method, int complete_only, int protocol_warn_level) { struct z_stream_s *stream = NULL; size_t out_size, old_size; off_t offset; int r; tor_assert(out); tor_assert(out_len); tor_assert(in); tor_assert(in_len < UINT_MAX); if (method == GZIP_METHOD && !is_gzip_supported()) { /* Old zlib version don't support gzip in inflateInit2 */ log_warn(LD_BUG, "Gzip not supported with zlib %s", ZLIB_VERSION); return -1; } *out = NULL; stream = tor_malloc_zero(sizeof(struct z_stream_s)); stream->zalloc = Z_NULL; stream->zfree = Z_NULL; stream->opaque = NULL; stream->next_in = (unsigned char*) in; stream->avail_in = (unsigned int)in_len; if (inflateInit2(stream, method_bits(method)) != Z_OK) { log_warn(LD_GENERAL, "Error from inflateInit2: %s", stream->msg?stream->msg:"<no message>"); goto err; } out_size = in_len * 2; /* guess 50% compression. */ if (out_size < 1024) out_size = 1024; if (out_size >= SIZE_T_CEILING || out_size > UINT_MAX) goto err; *out = tor_malloc(out_size); stream->next_out = (unsigned char*)*out; stream->avail_out = (unsigned int)out_size; while (1) { switch (inflate(stream, complete_only ? Z_FINISH : Z_SYNC_FLUSH)) { case Z_STREAM_END: if (stream->avail_in == 0) goto done; /* There may be more compressed data here. */ if ((r = inflateEnd(stream)) != Z_OK) { log_warn(LD_BUG, "Error freeing gzip structures"); goto err; } if (inflateInit2(stream, method_bits(method)) != Z_OK) { log_warn(LD_GENERAL, "Error from second inflateInit2: %s", stream->msg?stream->msg:"<no message>"); goto err; } break; case Z_OK: if (!complete_only && stream->avail_in == 0) goto done; /* In case zlib doesn't work as I think.... */ if (stream->avail_out >= stream->avail_in+16) break; case Z_BUF_ERROR: if (stream->avail_out > 0) { log_fn(protocol_warn_level, LD_PROTOCOL, "possible truncated or corrupt zlib data"); goto err; } offset = stream->next_out - (unsigned char*)*out; old_size = out_size; out_size *= 2; if (out_size < old_size) { log_warn(LD_GENERAL, "Size overflow in uncompression."); goto err; } if (is_compression_bomb(in_len, out_size)) { log_warn(LD_GENERAL, "Input looks like a possible zlib bomb; " "not proceeding."); goto err; } if (out_size >= SIZE_T_CEILING) { log_warn(LD_BUG, "Hit SIZE_T_CEILING limit while uncompressing."); goto err; } *out = tor_realloc(*out, out_size); stream->next_out = (unsigned char*)(*out + offset); if (out_size - offset > UINT_MAX) { log_warn(LD_BUG, "Ran over unsigned int limit of zlib while " "uncompressing."); goto err; } stream->avail_out = (unsigned int)(out_size - offset); break; default: log_warn(LD_GENERAL, "Gzip decompression returned an error: %s", stream->msg ? stream->msg : "<no message>"); goto err; } } done: *out_len = stream->next_out - (unsigned char*)*out; r = inflateEnd(stream); tor_free(stream); if (r != Z_OK) { log_warn(LD_BUG, "Error freeing gzip structures"); goto err; } /* NUL-terminate output. */ if (out_size == *out_len) *out = tor_realloc(*out, out_size + 1); (*out)[*out_len] = '\0'; return 0; err: if (stream) { inflateEnd(stream); tor_free(stream); } if (*out) { tor_free(*out); } return -1; }
/** Given <b>in_len</b> bytes at <b>in</b>, compress them into a newly * allocated buffer, using the method described in <b>method</b>. Store the * compressed string in *<b>out</b>, and its length in *<b>out_len</b>. * Return 0 on success, -1 on failure. */ int tor_gzip_compress(char **out, size_t *out_len, const char *in, size_t in_len, compress_method_t method) { struct z_stream_s *stream = NULL; size_t out_size, old_size; off_t offset; tor_assert(out); tor_assert(out_len); tor_assert(in); tor_assert(in_len < UINT_MAX); *out = NULL; if (method == GZIP_METHOD && !is_gzip_supported()) { /* Old zlib version don't support gzip in deflateInit2 */ log_warn(LD_BUG, "Gzip not supported with zlib %s", ZLIB_VERSION); goto err; } stream = tor_malloc_zero(sizeof(struct z_stream_s)); stream->zalloc = Z_NULL; stream->zfree = Z_NULL; stream->opaque = NULL; stream->next_in = (unsigned char*) in; stream->avail_in = (unsigned int)in_len; if (deflateInit2(stream, Z_BEST_COMPRESSION, Z_DEFLATED, method_bits(method), 8, Z_DEFAULT_STRATEGY) != Z_OK) { log_warn(LD_GENERAL, "Error from deflateInit2: %s", stream->msg?stream->msg:"<no message>"); goto err; } /* Guess 50% compression. */ out_size = in_len / 2; if (out_size < 1024) out_size = 1024; *out = tor_malloc(out_size); stream->next_out = (unsigned char*)*out; stream->avail_out = (unsigned int)out_size; while (1) { switch (deflate(stream, Z_FINISH)) { case Z_STREAM_END: goto done; case Z_OK: /* In case zlib doesn't work as I think .... */ if (stream->avail_out >= stream->avail_in+16) break; case Z_BUF_ERROR: offset = stream->next_out - ((unsigned char*)*out); old_size = out_size; out_size *= 2; if (out_size < old_size) { log_warn(LD_GENERAL, "Size overflow in compression."); goto err; } *out = tor_realloc(*out, out_size); stream->next_out = (unsigned char*)(*out + offset); if (out_size - offset > UINT_MAX) { log_warn(LD_BUG, "Ran over unsigned int limit of zlib while " "uncompressing."); goto err; } stream->avail_out = (unsigned int)(out_size - offset); break; default: log_warn(LD_GENERAL, "Gzip compression didn't finish: %s", stream->msg ? stream->msg : "<no message>"); goto err; } } done: *out_len = stream->total_out; #ifdef OPENBSD /* "Hey Rocky! Watch me change an unsigned field to a signed field in a * third-party API!" * "Oh, that trick will just make people do unsafe casts to the unsigned * type in their cross-platform code!" * "Don't be foolish. I'm _sure_ they'll have the good sense to make sure * the newly unsigned field isn't negative." */ tor_assert(stream->total_out >= 0); #endif if (((size_t)stream->total_out) > out_size + 4097) { /* If we're wasting more than 4k, don't. */ *out = tor_realloc(*out, stream->total_out + 1); } if (deflateEnd(stream)!=Z_OK) { log_warn(LD_BUG, "Error freeing gzip structures"); goto err; } tor_free(stream); if (is_compression_bomb(*out_len, in_len)) { log_warn(LD_BUG, "We compressed something and got an insanely high " "compression factor; other Tors would think this was a zlib bomb."); goto err; } return 0; err: if (stream) { deflateEnd(stream); tor_free(stream); } tor_free(*out); return -1; }
static void monitor_update(iterator_t *it, pthread_mutex_t *recv_ready_mutex) { uint32_t total_sent = iterator_get_sent(it); if (last_now > 0.0) { double age = now() - zsend.start; double delta = now() - last_now; double remaining_secs = compute_remaining_time(age, total_sent); double percent_complete = 100.*age/(age + remaining_secs); // ask pcap for fresh values pthread_mutex_lock(recv_ready_mutex); recv_update_pcap_stats(); pthread_mutex_unlock(recv_ready_mutex); // format times for display char time_left[20]; if (age < 5) { time_left[0] = '\0'; } else { char buf[20]; time_string((int)remaining_secs, 1, buf, sizeof(buf)); snprintf(time_left, sizeof(time_left), " (%s left)", buf); } char time_past[20]; time_string((int)age, 0, time_past, sizeof(time_past)); char send_rate[20], send_avg[20], recv_rate[20], recv_avg[20], pcap_drop[20], pcap_drop_avg[20]; // recv stats number_string((zrecv.success_unique - last_rcvd)/delta, recv_rate, sizeof(recv_rate)); number_string((zrecv.success_unique/age), recv_avg, sizeof(recv_avg)); // dropped stats number_string((zrecv.pcap_drop + zrecv.pcap_ifdrop - last_drop)/delta, pcap_drop, sizeof(pcap_drop)); number_string(((zrecv.pcap_drop + zrecv.pcap_ifdrop)/age), pcap_drop_avg, sizeof(pcap_drop_avg)); // Warn if we drop > 5% of our average receive rate uint32_t drop_rate = (uint32_t)((zrecv.pcap_drop + zrecv.pcap_ifdrop - last_drop) / delta); if (drop_rate > (uint32_t)((zrecv.success_unique - last_rcvd) / delta) / 20) { log_warn("monitor", "Dropped %d packets in the last second, (%d total dropped (pcap: %d + iface: %d))", drop_rate, zrecv.pcap_drop + zrecv.pcap_ifdrop, zrecv.pcap_drop, zrecv.pcap_ifdrop); } // Warn if we fail to send > 1% of our average send rate uint32_t fail_rate = (uint32_t)((zsend.sendto_failures - last_failures) / delta); // failures/sec if (fail_rate > ((total_sent / age) / 100)) { log_warn("monitor", "Failed to send %d packets/sec (%d total failures)", fail_rate, zsend.sendto_failures); } float hits; if (!total_sent) { hits = 0; } else { hits = zrecv.success_unique*100./total_sent; } if (!zsend.complete) { // main display (during sending) number_string((total_sent - last_sent)/delta, send_rate, sizeof(send_rate)); number_string((total_sent/age), send_avg, sizeof(send_avg)); fprintf(stderr, "%5s %0.0f%%%s; send: %u %sp/s (%sp/s avg); " "recv: %u %sp/s (%sp/s avg); " "drops: %sp/s (%sp/s avg); " "hits: %0.2f%%\n", time_past, percent_complete, time_left, total_sent, send_rate, send_avg, zrecv.success_unique, recv_rate, recv_avg, pcap_drop, pcap_drop_avg, hits); } else { // alternate display (during cooldown) number_string((total_sent/(zsend.finish - zsend.start)), send_avg, sizeof(send_avg)); fprintf(stderr, "%5s %0.0f%%%s; send: %u done (%sp/s avg); " "recv: %u %sp/s (%sp/s avg); " "drops: %sp/s (%sp/s avg); " "hits: %0.2f%%\n", time_past, percent_complete, time_left, total_sent, send_avg, zrecv.success_unique, recv_rate, recv_avg, pcap_drop, pcap_drop_avg, hits); } } last_now = now(); last_sent = total_sent; last_rcvd = zrecv.success_unique; last_drop = zrecv.pcap_drop + zrecv.pcap_ifdrop; last_failures = zsend.sendto_failures; }
/** Parse the content of a client_key file in <b>ckstr</b> and add * rend_authorized_client_t's for each parsed client to * <b>parsed_clients</b>. Return the number of parsed clients as result * or -1 for failure. */ int rend_parse_client_keys(strmap_t *parsed_clients, const char *ckstr) { int result = -1; smartlist_t *tokens; directory_token_t *tok; const char *current_entry = NULL; memarea_t *area = NULL; char *err_msg = NULL; if (!ckstr || strlen(ckstr) == 0) return -1; tokens = smartlist_new(); /* Begin parsing with first entry, skipping comments or whitespace at the * beginning. */ area = memarea_new(); current_entry = eat_whitespace(ckstr); while (!strcmpstart(current_entry, "client-name ")) { rend_authorized_client_t *parsed_entry; /* Determine end of string. */ const char *eos = strstr(current_entry, "\nclient-name "); if (!eos) eos = current_entry + strlen(current_entry); else eos = eos + 1; /* Free tokens and clear token list. */ SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t)); smartlist_clear(tokens); memarea_clear(area); /* Tokenize string. */ if (tokenize_string(area, current_entry, eos, tokens, client_keys_token_table, 0)) { log_warn(LD_REND, "Error tokenizing client keys file."); goto err; } /* Advance to next entry, if available. */ current_entry = eos; /* Check minimum allowed length of token list. */ if (smartlist_len(tokens) < 2) { log_warn(LD_REND, "Impossibly short client key entry."); goto err; } /* Parse client name. */ tok = find_by_keyword(tokens, C_CLIENT_NAME); tor_assert(tok == smartlist_get(tokens, 0)); tor_assert(tok->n_args == 1); if (!rend_valid_client_name(tok->args[0])) { log_warn(LD_CONFIG, "Illegal client name: %s. (Length must be " "between 1 and %d, and valid characters are " "[A-Za-z0-9+-_].)", tok->args[0], REND_CLIENTNAME_MAX_LEN); goto err; } /* Check if client name is duplicate. */ if (strmap_get(parsed_clients, tok->args[0])) { log_warn(LD_CONFIG, "HiddenServiceAuthorizeClient contains a " "duplicate client name: '%s'. Ignoring.", tok->args[0]); goto err; } parsed_entry = tor_malloc_zero(sizeof(rend_authorized_client_t)); parsed_entry->client_name = tor_strdup(tok->args[0]); strmap_set(parsed_clients, parsed_entry->client_name, parsed_entry); /* Parse client key. */ tok = find_opt_by_keyword(tokens, C_CLIENT_KEY); if (tok) { parsed_entry->client_key = tok->key; tok->key = NULL; /* Prevent free */ } /* Parse descriptor cookie. */ tok = find_by_keyword(tokens, C_DESCRIPTOR_COOKIE); tor_assert(tok->n_args == 1); if (rend_auth_decode_cookie(tok->args[0], parsed_entry->descriptor_cookie, NULL, &err_msg) < 0) { tor_assert(err_msg); log_warn(LD_REND, "%s", err_msg); tor_free(err_msg); goto err; } } result = strmap_size(parsed_clients); goto done; err: result = -1; done: /* Free tokens and clear token list. */ SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t)); smartlist_free(tokens); if (area) memarea_drop_all(area); return result; }
int request_dispatch(session_t *ses, struct evbuffer *in, struct evbuffer *out){ spie_header_t *pro; assert((ses != NULL) && (in != NULL) && (out != NULL)); while(header_unpack(in, &pro) == 0){ switch(pro->cmdcode){ case SPIE_CMD_TEMPLOGIN: svr_request_templogin(ses, in, out, pro); break; case SPIE_CMD_TEMPADD: svr_request_tempadd(ses, in, out, pro); break; case SPIE_CMD_LOGIN: svr_request_login(ses, in, out, pro); break; case SPIE_CMD_ADDUSER: svr_request_adduser(ses, in, out, pro); break; case SPIE_CMD_DELUSER: svr_request_deluser(ses, in, out, pro); break; case SPIE_CMD_LISTUSER: svr_request_listuser(ses, in, out, pro); break; case SPIE_CMD_UPDATEUSER: svr_request_updateuser(ses, in, out, pro); break; case SPIE_CMD_SYSINFO: svr_request_sysinfo(ses, in, out, pro); break; case SPIE_CMD_FOPEN: svr_request_fopen(ses, in, out, pro); break; case SPIE_CMD_FCLOSE: svr_request_fclose(ses, in, out, pro); break; case SPIE_CMD_FWRITE: svr_request_fwrite(ses, in, out, pro); break; case SPIE_CMD_FREAD: svr_request_fread(ses, in, out, pro); break; case SPIE_CMD_FSTAT: svr_request_fstat(ses, in, out, pro); break; case SPIE_CMD_FTRUNCATE: svr_request_ftruncate(ses, in, out, pro); break; case SPIE_CMD_FMOVETO: svr_request_fmoveto(ses, in, out, pro); break; case SPIE_CMD_FCREATE: svr_request_fcreate(ses, in, out, pro); break; case SPIE_CMD_FDELETE: svr_request_fdelete(ses, in, out, pro); break; case SPIE_CMD_FREADSNAP: svr_request_freadsnap(ses, in, out, pro); break; case SPIE_CMD_FWRITESNAP: svr_request_fwritesnap(ses, in, out, pro); break; case SPIE_CMD_LOOKUP_CREATE: svr_request_lookup_create(ses, in, out, pro); break; case SPIE_CMD_LOOKUP_DESTROY: svr_request_lookup_destroy(ses, in, out, pro); break; case SPIE_CMD_LOOKUP_NEXT: svr_request_lookup_next(ses, in, out, pro); break; default: log_warn("received command is unkown:%d\n", pro->cmdcode); trans_ack_fail(out, pro, SPIE_ECODE_INVAL); break; } pro = NULL; } return 0; }
/** Parse and validate the ASCII-encoded v2 descriptor in <b>desc</b>, * write the parsed descriptor to the newly allocated *<b>parsed_out</b>, the * binary descriptor ID of length DIGEST_LEN to <b>desc_id_out</b>, the * encrypted introduction points to the newly allocated * *<b>intro_points_encrypted_out</b>, their encrypted size to * *<b>intro_points_encrypted_size_out</b>, the size of the encoded descriptor * to *<b>encoded_size_out</b>, and a pointer to the possibly next * descriptor to *<b>next_out</b>; return 0 for success (including validation) * and -1 for failure. * * If <b>as_hsdir</b> is 1, we're parsing this as an HSDir, and we should * be strict about time formats. */ int rend_parse_v2_service_descriptor(rend_service_descriptor_t **parsed_out, char *desc_id_out, char **intro_points_encrypted_out, size_t *intro_points_encrypted_size_out, size_t *encoded_size_out, const char **next_out, const char *desc, int as_hsdir) { rend_service_descriptor_t *result = tor_malloc_zero(sizeof(rend_service_descriptor_t)); char desc_hash[DIGEST_LEN]; const char *eos; smartlist_t *tokens = smartlist_new(); directory_token_t *tok; char secret_id_part[DIGEST_LEN]; int i, version, num_ok=1; smartlist_t *versions; char public_key_hash[DIGEST_LEN]; char test_desc_id[DIGEST_LEN]; memarea_t *area = NULL; const int strict_time_fmt = as_hsdir; tor_assert(desc); /* Check if desc starts correctly. */ if (strcmpstart(desc, "rendezvous-service-descriptor ")) { log_info(LD_REND, "Descriptor does not start correctly."); goto err; } /* Compute descriptor hash for later validation. */ if (router_get_hash_impl(desc, strlen(desc), desc_hash, "rendezvous-service-descriptor ", "\nsignature", '\n', DIGEST_SHA1) < 0) { log_warn(LD_REND, "Couldn't compute descriptor hash."); goto err; } /* Determine end of string. */ eos = strstr(desc, "\nrendezvous-service-descriptor "); if (!eos) eos = desc + strlen(desc); else eos = eos + 1; /* Check length. */ if (eos-desc > REND_DESC_MAX_SIZE) { /* XXXX+ If we are parsing this descriptor as a server, this * should be a protocol warning. */ log_warn(LD_REND, "Descriptor length is %d which exceeds " "maximum rendezvous descriptor size of %d bytes.", (int)(eos-desc), REND_DESC_MAX_SIZE); goto err; } /* Tokenize descriptor. */ area = memarea_new(); if (tokenize_string(area, desc, eos, tokens, desc_token_table, 0)) { log_warn(LD_REND, "Error tokenizing descriptor."); goto err; } /* Set next to next descriptor, if available. */ *next_out = eos; /* Set length of encoded descriptor. */ *encoded_size_out = eos - desc; /* Check min allowed length of token list. */ if (smartlist_len(tokens) < 7) { log_warn(LD_REND, "Impossibly short descriptor."); goto err; } /* Parse base32-encoded descriptor ID. */ tok = find_by_keyword(tokens, R_RENDEZVOUS_SERVICE_DESCRIPTOR); tor_assert(tok == smartlist_get(tokens, 0)); tor_assert(tok->n_args == 1); if (!rend_valid_descriptor_id(tok->args[0])) { log_warn(LD_REND, "Invalid descriptor ID: '%s'", tok->args[0]); goto err; } if (base32_decode(desc_id_out, DIGEST_LEN, tok->args[0], REND_DESC_ID_V2_LEN_BASE32) < 0) { log_warn(LD_REND, "Descriptor ID contains illegal characters: %s", tok->args[0]); goto err; } /* Parse descriptor version. */ tok = find_by_keyword(tokens, R_VERSION); tor_assert(tok->n_args == 1); result->version = (int) tor_parse_long(tok->args[0], 10, 0, INT_MAX, &num_ok, NULL); if (result->version != 2 || !num_ok) { /* If it's <2, it shouldn't be under this format. If the number * is greater than 2, we bumped it because we broke backward * compatibility. See how version numbers in our other formats * work. */ log_warn(LD_REND, "Unrecognized descriptor version: %s", escaped(tok->args[0])); goto err; } /* Parse public key. */ tok = find_by_keyword(tokens, R_PERMANENT_KEY); result->pk = tok->key; tok->key = NULL; /* Prevent free */ /* Parse secret ID part. */ tok = find_by_keyword(tokens, R_SECRET_ID_PART); tor_assert(tok->n_args == 1); if (strlen(tok->args[0]) != REND_SECRET_ID_PART_LEN_BASE32 || strspn(tok->args[0], BASE32_CHARS) != REND_SECRET_ID_PART_LEN_BASE32) { log_warn(LD_REND, "Invalid secret ID part: '%s'", tok->args[0]); goto err; } if (base32_decode(secret_id_part, DIGEST_LEN, tok->args[0], 32) < 0) { log_warn(LD_REND, "Secret ID part contains illegal characters: %s", tok->args[0]); goto err; } /* Parse publication time -- up-to-date check is done when storing the * descriptor. */ tok = find_by_keyword(tokens, R_PUBLICATION_TIME); tor_assert(tok->n_args == 1); if (parse_iso_time_(tok->args[0], &result->timestamp, strict_time_fmt, 0) < 0) { log_warn(LD_REND, "Invalid publication time: '%s'", tok->args[0]); goto err; } /* Parse protocol versions. */ tok = find_by_keyword(tokens, R_PROTOCOL_VERSIONS); tor_assert(tok->n_args == 1); versions = smartlist_new(); smartlist_split_string(versions, tok->args[0], ",", SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); for (i = 0; i < smartlist_len(versions); i++) { version = (int) tor_parse_long(smartlist_get(versions, i), 10, 0, INT_MAX, &num_ok, NULL); if (!num_ok) /* It's a string; let's ignore it. */ continue; if (version >= REND_PROTOCOL_VERSION_BITMASK_WIDTH) /* Avoid undefined left-shift behaviour. */ continue; result->protocols |= 1 << version; } SMARTLIST_FOREACH(versions, char *, cp, tor_free(cp)); smartlist_free(versions); /* Parse encrypted introduction points. Don't verify. */ tok = find_opt_by_keyword(tokens, R_INTRODUCTION_POINTS); if (tok) { if (strcmp(tok->object_type, "MESSAGE")) { log_warn(LD_DIR, "Bad object type: introduction points should be of " "type MESSAGE"); goto err; } *intro_points_encrypted_out = tor_memdup(tok->object_body, tok->object_size); *intro_points_encrypted_size_out = tok->object_size; } else { *intro_points_encrypted_out = NULL; *intro_points_encrypted_size_out = 0; } /* Parse and verify signature. */ tok = find_by_keyword(tokens, R_SIGNATURE); if (check_signature_token(desc_hash, DIGEST_LEN, tok, result->pk, 0, "v2 rendezvous service descriptor") < 0) goto err; /* Verify that descriptor ID belongs to public key and secret ID part. */ if (crypto_pk_get_digest(result->pk, public_key_hash) < 0) { log_warn(LD_REND, "Unable to compute rend descriptor public key digest"); goto err; } rend_get_descriptor_id_bytes(test_desc_id, public_key_hash, secret_id_part); if (tor_memneq(desc_id_out, test_desc_id, DIGEST_LEN)) { log_warn(LD_REND, "Parsed descriptor ID does not match " "computed descriptor ID."); goto err; } goto done; err: rend_service_descriptor_free(result); result = NULL; done: if (tokens) { SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t)); smartlist_free(tokens); } if (area) memarea_drop_all(area); *parsed_out = result; if (result) return 0; return -1; }
int main(int argc, char* argv[]) { try { cxxtools::Arg<bool> fatal; fatal.set(argc, argv, 'f'); fatal.set(argc, argv, "--fatal"); cxxtools::Arg<bool> error; error.set(argc, argv, 'e'); error.set(argc, argv, "--error"); cxxtools::Arg<bool> warn; warn.set(argc, argv, 'w'); warn.set(argc, argv, "--warn"); cxxtools::Arg<bool> info; info.set(argc, argv, 'i'); info.set(argc, argv, "--info"); cxxtools::Arg<bool> debug; debug.set(argc, argv, 'd'); debug.set(argc, argv, "--debug"); cxxtools::Arg<std::string> properties("log4j.properties"); properties.set(argc, argv, 'p'); properties.set(argc, argv, "--properties"); if (argc <= 2) { std::cerr << "usage: " << argv[0] << " [options] category message\n" "\toptions: -f|--fatal\n" "\t -e|--error\n" "\t -w|--warn\n" "\t -i|--info\n" "\t -d|--debug\n" "\t -p|--properties filename" << std::endl; return -1; } log_init(properties.getValue()); category = argv[1]; for (int a = 2; a < argc; ++a) { if (fatal) log_fatal(argv[a]); else if (error) log_error(argv[a]); else if (warn) log_warn(argv[a]); else if (info) log_info(argv[a]); else if (debug) log_debug(argv[a]); } } catch (const std::exception& e) { std::cerr << e.what() << std::endl; return -1; } }
static int _pv_resize_single(struct cmd_context *cmd, struct volume_group *vg, struct physical_volume *pv, const uint64_t new_size) { struct pv_list *pvl; uint64_t size = 0; uint32_t new_pe_count = 0; int r = 0; struct dm_list mdas; const char *pv_name = pv_dev_name(pv); const char *vg_name = pv_vg_name(pv); struct lvmcache_info *info; int mda_count = 0; struct volume_group *old_vg = vg; dm_list_init(&mdas); if (is_orphan_vg(vg_name)) { if (!lock_vol(cmd, vg_name, LCK_VG_WRITE)) { log_error("Can't get lock for orphans"); return 0; } if (!(pv = pv_read(cmd, pv_name, &mdas, NULL, 1, 0))) { unlock_vg(cmd, vg_name); log_error("Unable to read PV \"%s\"", pv_name); return 0; } mda_count = dm_list_size(&mdas); } else { vg = vg_read_for_update(cmd, vg_name, NULL, 0); if (vg_read_error(vg)) { vg_release(vg); log_error("Unable to read volume group \"%s\".", vg_name); return 0; } if (!(pvl = find_pv_in_vg(vg, pv_name))) { log_error("Unable to find \"%s\" in volume group \"%s\"", pv_name, vg->name); goto out; } pv = pvl->pv; if (!(info = info_from_pvid(pv->dev->pvid, 0))) { log_error("Can't get info for PV %s in volume group %s", pv_name, vg->name); goto out; } mda_count = dm_list_size(&info->mdas); if (!archive(vg)) goto out; } /* FIXME Create function to test compatibility properly */ if (mda_count > 1) { log_error("%s: too many metadata areas for pvresize", pv_name); goto out; } if (!(pv->fmt->features & FMT_RESIZE_PV)) { log_error("Physical volume %s format does not support resizing.", pv_name); goto out; } /* Get new size */ if (!dev_get_size(pv_dev(pv), &size)) { log_error("%s: Couldn't get size.", pv_name); goto out; } if (new_size) { if (new_size > size) log_warn("WARNING: %s: Overriding real size. " "You could lose data.", pv_name); log_verbose("%s: Pretending size is %" PRIu64 " not %" PRIu64 " sectors.", pv_name, new_size, pv_size(pv)); size = new_size; } if (size < PV_MIN_SIZE) { log_error("%s: Size must exceed minimum of %ld sectors.", pv_name, PV_MIN_SIZE); goto out; } if (size < pv_pe_start(pv)) { log_error("%s: Size must exceed physical extent start of " "%" PRIu64 " sectors.", pv_name, pv_pe_start(pv)); goto out; } pv->size = size; if (vg) { pv->size -= pv_pe_start(pv); new_pe_count = pv_size(pv) / vg->extent_size; if (!new_pe_count) { log_error("%s: Size must leave space for at " "least one physical extent of " "%" PRIu32 " sectors.", pv_name, pv_pe_size(pv)); goto out; } if (!pv_resize(pv, vg, new_pe_count)) goto_out; } log_verbose("Resizing volume \"%s\" to %" PRIu64 " sectors.", pv_name, pv_size(pv)); log_verbose("Updating physical volume \"%s\"", pv_name); if (!is_orphan_vg(vg_name)) { if (!vg_write(vg) || !vg_commit(vg)) { log_error("Failed to store physical volume \"%s\" in " "volume group \"%s\"", pv_name, vg->name); goto out; } backup(vg); } else if (!(pv_write(cmd, pv, NULL, INT64_C(-1)))) { log_error("Failed to store physical volume \"%s\"", pv_name); goto out; } log_print("Physical volume \"%s\" changed", pv_name); r = 1; out: unlock_vg(cmd, vg_name); if (!old_vg) vg_release(vg); return r; }
int dup_sync_sender_manager::duplicate_batch_data(int bucket_number, const mput_record_vec* record_vec, const std::vector<uint64_t>& des_server_ids, base_packet *request, int version) { unsigned _copy_count=des_server_ids.size(); uint32_t max_packet_id = atomic_add_return(_copy_count,&packet_id_creater); if(0==max_packet_id) max_packet_id = atomic_add_return(_copy_count,&packet_id_creater); int ret=packets_mgr.addWaitNode(0,NULL,NULL,bucket_number,des_server_ids,request,max_packet_id,version); if(ret != TAIR_RETURN_SUCCESS) { return ret; } for(unsigned int i=0;i < _copy_count; i++) { request_mput* tmp_packet = new request_mput(); // just reuse original request's data, if necessray if (_copy_count < 2) { tmp_packet->swap(*(dynamic_cast<request_mput*>(request))); } else { tmp_packet->clone(*(dynamic_cast<request_mput*>(request)), true); } tmp_packet->server_flag = TAIR_SERVERFLAG_DUPLICATE; tmp_packet->packet_id = max_packet_id; // reset the compressed data as server_flag changed if (tmp_packet->compressed != 0) { tmp_packet->compressed = 0; if (tmp_packet->packet_data != NULL) { delete tmp_packet->packet_data; } tmp_packet->compress(); } //and send it to slave log_debug("duplicate packet %d sent: %s",tmp_packet->packet_id,tbsys::CNetUtil::addrToString(des_server_ids[i]).c_str()); if(conn_mgr->sendPacket(des_server_ids[i], tmp_packet, NULL, NULL, true) == false) { //duplicate sendpacket error. log_error("duplicate packet %d faile send: %s",tmp_packet->packet_id,tbsys::CNetUtil::addrToString(des_server_ids[i]).c_str()); delete tmp_packet; ret = TAIR_RETURN_DUPLICATE_BUSY; break; } } if (TAIR_RETURN_SUCCESS != ret) { //clear waitnode. packets_mgr.clear_waitnode(max_packet_id); //return failed,the caller will delete the packet. return ret; } //all data is send,wait response or timeout it. CPacket_Timeout_hint *phint=new CPacket_Timeout_hint(max_packet_id); if(!packets_mgr.put_timeout_hint(max_packet_id%MAX_DUP_COUNT,phint)) { //put to queue error,should remove the map node. delete phint; packets_mgr.clear_waitnode(max_packet_id); log_warn("timeout wait packet full ,ignore packet=%d",max_packet_id); return TAIR_RETURN_DUPLICATE_BUSY; } return TAIR_DUP_WAIT_RSP; }
int MRtmpHandshake::handshake_with_server_use_complex(MTcpSocket & skt,bool rtmpe,bool swf) { int ret = ERROR_SUCCESS; char* c0c1 = new char[1537]; bool FP9HandShake = false; mAutoFreeArray(char, c0c1); if (rtmpe) { c0c1[0] = 0x06; FP9HandShake = true; } else { c0c1[0] = 0x03; } //create c0c1 c1s1 c1; if ((ret = c1.c1_create(srs_schema1)) != ERROR_SUCCESS) { return ret; } c1.dump(&c0c1[1]); if ((ret = skt.write(c0c1, 1537)) < 0) { log_warn("complex handshake send c0c1 failed. ret=%d", ret); return ret; } //recv s0s1; char s0s1[1537]; if ((ret = skt.readFully(s0s1, 1537)) <= 0) { log_warn("complex handshake recv s0s1 failed. ret=%d", ret); return ret; } log_trace("version of rtmp is %d, version of flash player is %d.%d.%d.%d",s0s1[0],s0s1[5],s0s1[6],s0s1[7],s0s1[8]); c1s1 s1; // try schema0. if ((ret = s1.c1_parse(&s0s1[1], srs_schema0)) != ERROR_SUCCESS) { log_error("parse s1 schema%d error. ret=%d", srs_schema0, ret); return ret; } // try schema1 bool is_valid = false; if ((ret = s1.s1_validate_digest(is_valid)) != ERROR_SUCCESS || !is_valid) { if ((ret = s1.c1_parse(&s0s1[1], srs_schema1)) != ERROR_SUCCESS) { log_error("parse s1 schema%d error. ret=%d", srs_schema1, ret); return ret; } if ((ret = s1.s1_validate_digest(is_valid)) != ERROR_SUCCESS || !is_valid) { ret = ERROR_RTMP_TRY_SIMPLE_HS; log_info("all schema valid failed, try simple handshake. ret=%d", ret); return ret; } } log_verbose("decode s1 success."); c2s2 c2; if ((ret = c2.c2_create(&s1)) != ERROR_SUCCESS) { log_error("create s2 from c1 failed. ret=%d", ret); return ret; } log_verbose("create s2 from c1 success."); // sendout c2 char* c2_temp = new char[1536]; c2.dump(c2_temp); if ((ret = skt.write(c2_temp, 1536)) < 0) { log_warn("complex handshake send c2 failed. ret=%d", ret); return ret; } log_verbose("complex handshake send c2 success."); // recv s2 char* s2 = new char[1536]; mAutoFreeArray(char, s2); if ((ret = skt.readFully(s2, 1536)) <= 0) { log_warn("complex handshake read s2 failed. ret=%d", ret); return ret; } if (s2[4] == 0 && s2[5] == 0 && s2[6] == 0 && s2[7] == 0) { log_trace("sever refuse connenct"); return -1; } log_trace("complex handshake with server success"); return ret; }
tbnet::IPacketHandler::HPRetCode dup_sync_sender_manager::handlePacket(tbnet::Packet *packet, void *args) { int packet_id = reinterpret_cast<long>(args); if (!packet->isRegularPacket()) { tbnet::ControlPacket *cp = (tbnet::ControlPacket*)packet; log_error("cmd:%d,packetid:%d,timeout.", cp->getCommand(),packet_id); handleTimeOutPacket(packet_id); return tbnet::IPacketHandler::FREE_CHANNEL; } int pcode = packet->getPCode(); log_debug("================= get duplicate response, pcode: %d", pcode); if (TAIR_RESP_DUPLICATE_PACKET == pcode) { response_duplicate* resp = (response_duplicate*)packet; log_debug("response packet %d ,bucket =%d, server=%s",resp->packet_id,resp->bucket_id, \ tbsys::CNetUtil::addrToString(resp->server_id).c_str()); int ret = do_duplicate_response(resp->bucket_id, resp->server_id, resp->packet_id); if (0 != ret && TAIR_RETURN_DUPLICATE_ACK_WAIT != ret) { log_error("response packet %d failed,bucket =%d, server=%s, code=%d", resp->packet_id, resp->bucket_id, \ tbsys::CNetUtil::addrToString(resp->server_id).c_str(), ret); } resp->free(); } else if ( pcode == TAIR_RESP_MRETURN_DUP_PACKET) { response_mreturn_dup *resp_dup = dynamic_cast<response_mreturn_dup*>(packet); if (resp_dup == NULL) { log_error("bad packet %d", pcode); } else { log_debug("duplicate response packet %u, bucket = %d, server = %s", resp_dup->packet_id, resp_dup->bucket_id, tbsys::CNetUtil::addrToString(resp_dup->server_id).c_str()); CPacket_wait_Nodes *pnode = NULL; int ret = packets_mgr.doResponse(resp_dup->bucket_id, resp_dup->server_id, resp_dup->packet_id, &pnode); response_mreturn *resp = new response_mreturn(); resp->swap(*resp_dup); if (ret == TAIR_RETURN_SUCCESS && pnode != NULL) { resp->setChannelId(pnode->chid); resp->config_version = pnode->conf_version; if (pnode->conn->postPacket(resp) == false) { delete resp; ret = TAIR_RETURN_DUPLICATE_SEND_ERROR; } } else { delete resp; } } } else if (pcode == TAIR_RESP_PREFIX_INCDEC_PACKET) { response_prefix_incdec *resp = dynamic_cast<response_prefix_incdec*>(packet); if (resp == NULL) { log_error("bad packet %d", pcode); } else { log_debug("duplicate response packet %u, bucket = %d, server = %s", resp->packet_id, resp->bucket_id, tbsys::CNetUtil::addrToString(resp->server_id).c_str()); CPacket_wait_Nodes *pnode = NULL; int ret = packets_mgr.doResponse(resp->bucket_id, resp->server_id, resp->packet_id, &pnode); if (ret == TAIR_RETURN_SUCCESS && pnode != NULL) { resp->server_flag = TAIR_SERVERFLAG_CLIENT; resp->setChannelId(pnode->chid); resp->config_version = pnode->conf_version; if (!pnode->conn->postPacket(resp)) { delete resp; ret = TAIR_RETURN_DUPLICATE_SEND_ERROR; } } } } else { log_warn("unknow packet! pcode: %d", pcode); packet->free(); } return tbnet::IPacketHandler::KEEP_CHANNEL; }
/** check file descriptor count */ static void checkrlimits(struct config_file* cfg) { #ifndef S_SPLINT_S #ifdef HAVE_GETRLIMIT /* list has number of ports to listen to, ifs number addresses */ int list = ((cfg->do_udp?1:0) + (cfg->do_tcp?1 + (int)cfg->incoming_num_tcp:0)); size_t listen_ifs = (size_t)(cfg->num_ifs==0? ((cfg->do_ip4 && !cfg->if_automatic?1:0) + (cfg->do_ip6?1:0)):cfg->num_ifs); size_t listen_num = list*listen_ifs; size_t outudpnum = (size_t)cfg->outgoing_num_ports; size_t outtcpnum = cfg->outgoing_num_tcp; size_t misc = 4; /* logfile, pidfile, stdout... */ size_t perthread_noudp = listen_num + outtcpnum + 2/*cmdpipe*/ + 2/*libevent*/ + misc; size_t perthread = perthread_noudp + outudpnum; #if !defined(HAVE_PTHREAD) && !defined(HAVE_SOLARIS_THREADS) int numthread = 1; /* it forks */ #else int numthread = (cfg->num_threads?cfg->num_threads:1); #endif size_t total = numthread * perthread + misc; size_t avail; struct rlimit rlim; if(total > 1024 && strncmp(event_get_version(), "mini-event", 10) == 0) { log_warn("too many file descriptors requested. The builtin" "mini-event cannot handle more than 1024. Config " "for less fds or compile with libevent"); if(numthread*perthread_noudp+15 > 1024) fatal_exit("too much tcp. not enough fds."); cfg->outgoing_num_ports = (int)((1024 - numthread*perthread_noudp - 10 /* safety margin */) /numthread); log_warn("continuing with less udp ports: %u", cfg->outgoing_num_ports); total = 1024; } if(perthread > 64 && strncmp(event_get_version(), "winsock-event", 13) == 0) { log_err("too many file descriptors requested. The winsock" " event handler cannot handle more than 64 per " " thread. Config for less fds"); if(perthread_noudp+2 > 64) fatal_exit("too much tcp. not enough fds."); cfg->outgoing_num_ports = (int)((64 - perthread_noudp - 2/* safety margin */)); log_warn("continuing with less udp ports: %u", cfg->outgoing_num_ports); total = numthread*(perthread_noudp+ (size_t)cfg->outgoing_num_ports)+misc; } if(getrlimit(RLIMIT_NOFILE, &rlim) < 0) { log_warn("getrlimit: %s", strerror(errno)); return; } if(rlim.rlim_cur == (rlim_t)RLIM_INFINITY) return; if((size_t)rlim.rlim_cur < total) { avail = (size_t)rlim.rlim_cur; rlim.rlim_cur = (rlim_t)(total + 10); rlim.rlim_max = (rlim_t)(total + 10); #ifdef HAVE_SETRLIMIT if(setrlimit(RLIMIT_NOFILE, &rlim) < 0) { log_warn("setrlimit: %s", strerror(errno)); #else if(1) { #endif log_warn("cannot increase max open fds from %u to %u", (unsigned)avail, (unsigned)total+10); /* check that calculation below does not underflow, * with 15 as margin */ if(numthread*perthread_noudp+15 > avail) fatal_exit("too much tcp. not enough fds."); cfg->outgoing_num_ports = (int)((avail - numthread*perthread_noudp - 10 /* safety margin */) /numthread); log_warn("continuing with less udp ports: %u", cfg->outgoing_num_ports); log_warn("increase ulimit or decrease threads, " "ports in config to remove this warning"); return; } log_warn("increased limit(open files) from %u to %u", (unsigned)avail, (unsigned)total+10); } #else (void)cfg; #endif /* HAVE_GETRLIMIT */ #endif /* S_SPLINT_S */ } /** set verbosity, check rlimits, cache settings */ static void apply_settings(struct daemon* daemon, struct config_file* cfg, int cmdline_verbose) { /* apply if they have changed */ verbosity = cmdline_verbose + cfg->verbosity; daemon_apply_cfg(daemon, cfg); checkrlimits(cfg); }
void NetworkServer::serve(){ writer = new ProcWorkerPool("writer"); writer->start(num_writers); reader = new ProcWorkerPool("reader"); reader->start(num_readers); pthread_t tid; int err = pthread_create(&tid, NULL, &NetworkServer::_ops_timer_thread, this); if (err != 0) { log_error("can't start ops timer thread: %s", strerror(err)); exit(-1); } link_dict_t ready_dict; link_dict_t tmp_dict; link_dict_t blocked_dict; link_dict_t::iterator it; const Fdevents::events_t *events; fdes->set(serv_link->fd(), FDEVENT_IN, 0, serv_link); fdes->set(this->reader->fd(), FDEVENT_IN, 0, this->reader); fdes->set(this->writer->fd(), FDEVENT_IN, 0, this->writer); uint32_t last_ticks = g_ticks; while(!quit){ // status report if((uint32_t)(g_ticks - last_ticks) >= STATUS_REPORT_TICKS){ last_ticks = g_ticks; log_debug("server running, links: %d", this->link_count); } ready_dict.swap(tmp_dict); tmp_dict.clear(); if(!ready_dict.empty()){ /* ready_dict not empty, so we should return immediately */ events = fdes->wait(0); }else{ events = fdes->wait(50); } if(events == NULL){ log_fatal("events.wait error: %s", strerror(errno)); break; } for(int i=0; i<(int)events->size(); i++){ const Fdevent *fde = events->at(i); if(fde->data.ptr == serv_link){ Link *link = accept_link(); if(link){ this->link_count ++; log_debug("new link from %s:%d, fd: %d, links: %d", link->remote_ip, link->remote_port, link->fd(), this->link_count); fdes->set(link->fd(), FDEVENT_IN, 1, link); } }else if(fde->data.ptr == this->reader || fde->data.ptr == this->writer){ ProcWorkerPool *worker = (ProcWorkerPool *)fde->data.ptr; ProcJob job; if(worker->pop(&job) == 0){ log_fatal("reading result from workers error!"); exit(0); } if(proc_result(&job, &ready_dict) == PROC_ERROR){ // } }else{ proc_client_event(fde, &ready_dict); } } /* if clients paused, add specified link into blocked_list and disable parsing request */ if(NetworkServer::clients_paused) { if(NetworkServer::clients_pause_end_time < time_ms()) { NetworkServer::clients_paused = 0; NetworkServer::clients_pause_end_time = 0; ready_dict.insert(blocked_dict.begin(), blocked_dict.end()); blocked_dict.clear(); } else { blocked_dict.insert(ready_dict.begin(), ready_dict.end()); ready_dict.clear(); continue; } } for(it = ready_dict.begin(); it != ready_dict.end(); it ++){ Link *link = it->second; if(link->error()){ this->link_count --; fdes->del(link->fd()); delete link; continue; } const Request *req = link->recv(); if(req == NULL){ log_warn("fd: %d, link parse error, delete link", link->fd()); this->link_count --; fdes->del(link->fd()); delete link; continue; } if(req->empty()){ fdes->set(link->fd(), FDEVENT_IN, 1, link); continue; } link->active_time = millitime(); ProcJob job; job.link = link; this->proc(&job); if(job.result == PROC_THREAD){ fdes->del(link->fd()); continue; } if(job.result == PROC_BACKEND){ fdes->del(link->fd()); this->link_count --; continue; } if(proc_result(&job, &tmp_dict) == PROC_ERROR){ // } } // end foreach ready link } }
/** * @brief Interpreter * @param in Context structure * @return void * * An interpreter for configuration files. The context structure * contains the data to be passed to the interpreter. */ void Interpreter(const struct Interpreter_in *in) { #define interpreter_message(string) \ log_warn(0, "%s:%ld: Parse Error: %s", in->path, in->line_num, string) const char *ccp = &in->line[0]; char *id = NULL; char *arg = NULL; if (!isalnum(*ccp) && *ccp != '_') { interpreter_message("Unexpected leading character"); goto die; } id = copy_identifier(ccp); while (isalnum(*ccp) || *ccp == '_') { ccp++; } adv_while_isspace(&ccp); if (*ccp++ != '=') { interpreter_message("Expected expression after identifier"); goto die; } adv_while_isspace(&ccp); if (*ccp++ != '\"') { interpreter_message("Expected statement after expression"); goto die; } else if ((arg = copy_argument(ccp)) == NULL) { interpreter_message("Lacks ending quote for the argument"); goto die; } else { ; } while (*ccp++ != '\"') { ; } adv_while_isspace(&ccp); if (*ccp++ != ';') { interpreter_message("No line terminator"); goto die; } adv_while_isspace(&ccp); if (*ccp && *ccp != '#') { interpreter_message("Implicit data after line terminator"); goto die; } else if ( !(in->validator_func(id)) ) { /* Unrecognized identifier. */ #if IGNORE_UNRECOGNIZED_IDENTIFIERS ; #else interpreter_message("No such identifier"); goto die; #endif } else if ((errno = in->install_func(id, arg)) != 0) { log_warn(errno, "%s:%ld: install_func returned %d", in->path, in->line_num, errno); goto die; } else { ; } free_not_null(id); free_not_null(arg); return; die: free_not_null(id); free_not_null(arg); abort(); }
/** Decrypt the encrypted introduction points in <b>ipos_encrypted</b> of * length <b>ipos_encrypted_size</b> using <b>descriptor_cookie</b> and * write the result to a newly allocated string that is pointed to by * <b>ipos_decrypted</b> and its length to <b>ipos_decrypted_size</b>. * Return 0 if decryption was successful and -1 otherwise. */ int rend_decrypt_introduction_points(char **ipos_decrypted, size_t *ipos_decrypted_size, const char *descriptor_cookie, const char *ipos_encrypted, size_t ipos_encrypted_size) { tor_assert(ipos_encrypted); tor_assert(descriptor_cookie); if (ipos_encrypted_size < 2) { log_warn(LD_REND, "Size of encrypted introduction points is too " "small."); return -1; } if (ipos_encrypted[0] == (int)REND_BASIC_AUTH) { char iv[CIPHER_IV_LEN], client_id[REND_BASIC_AUTH_CLIENT_ID_LEN], session_key[CIPHER_KEY_LEN], *dec; int declen, client_blocks; size_t pos = 0, len, client_entries_len; crypto_digest_t *digest; crypto_cipher_t *cipher; client_blocks = (int) ipos_encrypted[1]; client_entries_len = client_blocks * REND_BASIC_AUTH_CLIENT_MULTIPLE * REND_BASIC_AUTH_CLIENT_ENTRY_LEN; if (ipos_encrypted_size < 2 + client_entries_len + CIPHER_IV_LEN + 1) { log_warn(LD_REND, "Size of encrypted introduction points is too " "small."); return -1; } memcpy(iv, ipos_encrypted + 2 + client_entries_len, CIPHER_IV_LEN); digest = crypto_digest_new(); crypto_digest_add_bytes(digest, descriptor_cookie, REND_DESC_COOKIE_LEN); crypto_digest_add_bytes(digest, iv, CIPHER_IV_LEN); crypto_digest_get_digest(digest, client_id, REND_BASIC_AUTH_CLIENT_ID_LEN); crypto_digest_free(digest); for (pos = 2; pos < 2 + client_entries_len; pos += REND_BASIC_AUTH_CLIENT_ENTRY_LEN) { if (tor_memeq(ipos_encrypted + pos, client_id, REND_BASIC_AUTH_CLIENT_ID_LEN)) { /* Attempt to decrypt introduction points. */ cipher = crypto_cipher_new(descriptor_cookie); if (crypto_cipher_decrypt(cipher, session_key, ipos_encrypted + pos + REND_BASIC_AUTH_CLIENT_ID_LEN, CIPHER_KEY_LEN) < 0) { log_warn(LD_REND, "Could not decrypt session key for client."); crypto_cipher_free(cipher); return -1; } crypto_cipher_free(cipher); len = ipos_encrypted_size - 2 - client_entries_len - CIPHER_IV_LEN; dec = tor_malloc_zero(len + 1); declen = crypto_cipher_decrypt_with_iv(session_key, dec, len, ipos_encrypted + 2 + client_entries_len, ipos_encrypted_size - 2 - client_entries_len); if (declen < 0) { log_warn(LD_REND, "Could not decrypt introduction point string."); tor_free(dec); return -1; } if (fast_memcmpstart(dec, declen, "introduction-point ")) { log_warn(LD_REND, "Decrypted introduction points don't " "look like we could parse them."); tor_free(dec); continue; } *ipos_decrypted = dec; *ipos_decrypted_size = declen; return 0; } } log_warn(LD_REND, "Could not decrypt introduction points. Please " "check your authorization for this service!"); return -1; } else if (ipos_encrypted[0] == (int)REND_STEALTH_AUTH) { char *dec; int declen; if (ipos_encrypted_size < CIPHER_IV_LEN + 2) { log_warn(LD_REND, "Size of encrypted introduction points is too " "small."); return -1; } dec = tor_malloc_zero(ipos_encrypted_size - CIPHER_IV_LEN - 1 + 1); declen = crypto_cipher_decrypt_with_iv(descriptor_cookie, dec, ipos_encrypted_size - CIPHER_IV_LEN - 1, ipos_encrypted + 1, ipos_encrypted_size - 1); if (declen < 0) { log_warn(LD_REND, "Decrypting introduction points failed!"); tor_free(dec); return -1; } *ipos_decrypted = dec; *ipos_decrypted_size = declen; return 0; } else { log_warn(LD_REND, "Unknown authorization type number: %d", ipos_encrypted[0]); return -1; } }
static struct config * config_load(const char *path) { struct config *conf; FILE *fp; size_t flen; char *key, *value, *buf, *lbuf; const char *e; long long ll; lbuf = NULL; conf = calloc(1, sizeof(*conf)); if (conf == NULL) { log_warn("warn: table-mysql: calloc"); return (NULL); } dict_init(&conf->conf); dict_init(&conf->sources); conf->source_refresh = DEFAULT_REFRESH; conf->source_expire = DEFAULT_EXPIRE; fp = fopen(path, "r"); if (fp == NULL) { log_warn("warn: table-mysql: fopen"); goto end; } while ((buf = fgetln(fp, &flen))) { if (buf[flen - 1] == '\n') buf[flen - 1] = '\0'; else { lbuf = malloc(flen + 1); if (lbuf == NULL) { log_warn("warn: table-mysql: malloc"); goto end; } memcpy(lbuf, buf, flen); lbuf[flen] = '\0'; buf = lbuf; } key = buf; while (isspace((unsigned char)*key)) ++key; if (*key == '\0' || *key == '#') continue; value = key; strsep(&value, " \t:"); if (value) { while (*value) { if (!isspace((unsigned char)*value) && !(*value == ':' && isspace((unsigned char)*(value + 1)))) break; ++value; } if (*value == '\0') value = NULL; } if (value == NULL) { log_warnx("warn: table-mysql: missing value for key %s", key); goto end; } if (dict_check(&conf->conf, key)) { log_warnx("warn: table-mysql: duplicate key %s", key); goto end; } value = strdup(value); if (value == NULL) { log_warn("warn: table-mysql: malloc"); goto end; } dict_set(&conf->conf, key, value); } if ((value = dict_get(&conf->conf, "fetch_source_expire"))) { e = NULL; ll = strtonum(value, 0, INT_MAX, &e); if (e) { log_warnx("warn: table-mysql: bad value for fetch_source_expire: %s", e); goto end; } conf->source_expire = ll; } if ((value = dict_get(&conf->conf, "fetch_source_refresh"))) { e = NULL; ll = strtonum(value, 0, INT_MAX, &e); if (e) { log_warnx("warn: table-mysql: bad value for fetch_source_refresh: %s", e); goto end; } conf->source_refresh = ll; } free(lbuf); fclose(fp); return (conf); end: free(lbuf); if (fp) fclose(fp); config_free(conf); return (NULL); }
/** Parse the encoded introduction points in <b>intro_points_encoded</b> of * length <b>intro_points_encoded_size</b> and write the result to the * descriptor in <b>parsed</b>; return the number of successfully parsed * introduction points or -1 in case of a failure. */ int rend_parse_introduction_points(rend_service_descriptor_t *parsed, const char *intro_points_encoded, size_t intro_points_encoded_size) { const char *current_ipo, *end_of_intro_points; smartlist_t *tokens = NULL; directory_token_t *tok; rend_intro_point_t *intro; extend_info_t *info; int result, num_ok=1; memarea_t *area = NULL; tor_assert(parsed); /** Function may only be invoked once. */ tor_assert(!parsed->intro_nodes); if (!intro_points_encoded || intro_points_encoded_size == 0) { log_warn(LD_REND, "Empty or zero size introduction point list"); goto err; } /* Consider one intro point after the other. */ current_ipo = intro_points_encoded; end_of_intro_points = intro_points_encoded + intro_points_encoded_size; tokens = smartlist_new(); parsed->intro_nodes = smartlist_new(); area = memarea_new(); while (!fast_memcmpstart(current_ipo, end_of_intro_points-current_ipo, "introduction-point ")) { /* Determine end of string. */ const char *eos = tor_memstr(current_ipo, end_of_intro_points-current_ipo, "\nintroduction-point "); if (!eos) eos = end_of_intro_points; else eos = eos+1; tor_assert(eos <= intro_points_encoded+intro_points_encoded_size); /* Free tokens and clear token list. */ SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t)); smartlist_clear(tokens); memarea_clear(area); /* Tokenize string. */ if (tokenize_string(area, current_ipo, eos, tokens, ipo_token_table, 0)) { log_warn(LD_REND, "Error tokenizing introduction point"); goto err; } /* Advance to next introduction point, if available. */ current_ipo = eos; /* Check minimum allowed length of introduction point. */ if (smartlist_len(tokens) < 5) { log_warn(LD_REND, "Impossibly short introduction point."); goto err; } /* Allocate new intro point and extend info. */ intro = tor_malloc_zero(sizeof(rend_intro_point_t)); info = intro->extend_info = tor_malloc_zero(sizeof(extend_info_t)); /* Parse identifier. */ tok = find_by_keyword(tokens, R_IPO_IDENTIFIER); if (base32_decode(info->identity_digest, DIGEST_LEN, tok->args[0], REND_INTRO_POINT_ID_LEN_BASE32) < 0) { log_warn(LD_REND, "Identity digest contains illegal characters: %s", tok->args[0]); rend_intro_point_free(intro); goto err; } /* Write identifier to nickname. */ info->nickname[0] = '$'; base16_encode(info->nickname + 1, sizeof(info->nickname) - 1, info->identity_digest, DIGEST_LEN); /* Parse IP address. */ tok = find_by_keyword(tokens, R_IPO_IP_ADDRESS); if (tor_addr_parse(&info->addr, tok->args[0])<0) { log_warn(LD_REND, "Could not parse introduction point address."); rend_intro_point_free(intro); goto err; } if (tor_addr_family(&info->addr) != AF_INET) { log_warn(LD_REND, "Introduction point address was not ipv4."); rend_intro_point_free(intro); goto err; } /* Parse onion port. */ tok = find_by_keyword(tokens, R_IPO_ONION_PORT); info->port = (uint16_t) tor_parse_long(tok->args[0],10,1,65535, &num_ok,NULL); if (!info->port || !num_ok) { log_warn(LD_REND, "Introduction point onion port %s is invalid", escaped(tok->args[0])); rend_intro_point_free(intro); goto err; } /* Parse onion key. */ tok = find_by_keyword(tokens, R_IPO_ONION_KEY); if (!crypto_pk_public_exponent_ok(tok->key)) { log_warn(LD_REND, "Introduction point's onion key had invalid exponent."); rend_intro_point_free(intro); goto err; } info->onion_key = tok->key; tok->key = NULL; /* Prevent free */ /* Parse service key. */ tok = find_by_keyword(tokens, R_IPO_SERVICE_KEY); if (!crypto_pk_public_exponent_ok(tok->key)) { log_warn(LD_REND, "Introduction point key had invalid exponent."); rend_intro_point_free(intro); goto err; } intro->intro_key = tok->key; tok->key = NULL; /* Prevent free */ /* Add extend info to list of introduction points. */ smartlist_add(parsed->intro_nodes, intro); } result = smartlist_len(parsed->intro_nodes); goto done; err: result = -1; done: /* Free tokens and clear token list. */ if (tokens) { SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t)); smartlist_free(tokens); } if (area) memarea_drop_all(area); return result; }
static rstatus_t conf_validate_pool(struct conf *cf, struct conf_pool *cp) { rstatus_t status; ASSERT(!cp->valid); ASSERT(!string_empty(&cp->name)); if (!cp->listen.valid) { log_error("conf: directive \"listen:\" is missing"); return NC_ERROR; } /* set default values for unset directives */ if (cp->distribution == CONF_UNSET_DIST) { cp->distribution = CONF_DEFAULT_DIST; } if (cp->hash == CONF_UNSET_HASH) { cp->hash = CONF_DEFAULT_HASH; } if (cp->timeout == CONF_UNSET_NUM) { cp->timeout = CONF_DEFAULT_TIMEOUT; } if (cp->backlog == CONF_UNSET_NUM) { cp->backlog = CONF_DEFAULT_LISTEN_BACKLOG; } cp->client_connections = CONF_DEFAULT_CLIENT_CONNECTIONS; if (cp->redis != CONF_UNSET_NUM) { log_warn("conf: directive \"redis:\" is deprecated, " "use \"protocol:\" instead"); if (cp->proto != CONF_UNSET_PROTO && (cp->redis || cp->proto != PROTO_MEMCACHED) && (!cp->redis || cp->proto != PROTO_REDIS)) { log_error("conf: directive \"redis: %s\" is incompatible with " "directive \"protocol: %s\"", cp->redis ? "true" : "false", proto_type_string(cp->proto)); return NC_ERROR; } cp->proto = cp->redis ? PROTO_REDIS : PROTO_MEMCACHED; } if (cp->proto == CONF_UNSET_PROTO) { cp->proto = CONF_DEFAULT_PROTO; } if (cp->tcpkeepalive == CONF_UNSET_NUM) { cp->tcpkeepalive = CONF_DEFAULT_TCPKEEPALIVE; } if (cp->redis_db == CONF_UNSET_NUM) { cp->redis_db = CONF_DEFAULT_REDIS_DB; } if (cp->preconnect == CONF_UNSET_NUM) { cp->preconnect = CONF_DEFAULT_PRECONNECT; } if (cp->auto_eject_hosts == CONF_UNSET_NUM) { cp->auto_eject_hosts = CONF_DEFAULT_AUTO_EJECT_HOSTS; } if (cp->server_connections == CONF_UNSET_NUM) { cp->server_connections = CONF_DEFAULT_SERVER_CONNECTIONS; } else if (cp->server_connections == 0) { log_error("conf: directive \"server_connections:\" cannot be 0"); return NC_ERROR; } if (cp->server_retry_timeout == CONF_UNSET_NUM) { cp->server_retry_timeout = CONF_DEFAULT_SERVER_RETRY_TIMEOUT; } if (cp->server_failure_limit == CONF_UNSET_NUM) { cp->server_failure_limit = CONF_DEFAULT_SERVER_FAILURE_LIMIT; } if (!cp->redis && cp->redis_auth.len > 0) { log_error("conf: directive \"redis_auth:\" is only valid for a redis pool"); return NC_ERROR; } status = conf_validate_server(cf, cp); if (status != NC_OK) { return status; } cp->valid = 1; return NC_OK; }
static void dps_statistics_process(void) { PyObject *strret, *strargs; PyGILState_STATE gstate; char *domain_list_ret = NULL, *domain_list = NULL; char *str, *saveptr, *token; int domain; json_t *js_stats = NULL; /* json statistics array of each domain */ dps_object_load_balancing_t load_balancing; do { saveptr = NULL; /* No need to send the statistics */ if(dps_statistics_send == 0){ log_debug(PythonDataHandlerLogLevel, "Statistics has been set to NOT SENDING!"); break; } // Ensure the PYTHON Global Interpreter Lock gstate = PyGILState_Ensure(); // Domain_List_Get(self): strargs = Py_BuildValue("()"); if (strargs == NULL) { // Release the PYTHON Global Interpreter Lock PyGILState_Release(gstate); log_warn(PythonDataHandlerLogLevel, "Py_BuildValue returns NULL"); break; } // Invoke the Domain_List_Get call strret = PyEval_CallObject(Statistics_Interface.Domain_List_Get, strargs); Py_DECREF(strargs); if (strret == NULL) { // Release the PYTHON Global Interpreter Lock PyGILState_Release(gstate); log_warn(PythonDataHandlerLogLevel, "PyEval_CallObject Domain_List_Get returns NULL"); break; } //@return: The string of all Domain IDs //@rtype: String PyArg_Parse(strret, "z", &domain_list_ret); domain_list = strdup(domain_list_ret); // Lose the reference on all parameters and return arguments since they // are no longer needed. Py_DECREF(strret); // Release the PYTHON Global Interpreter Lock PyGILState_Release(gstate); if (!statistics_need_send_to_leader) { log_info(RESTHandlerLogLevel, "Not sending stats to leader"); break; } js_stats = json_array(); if(js_stats == NULL) { log_warn(RESTHandlerLogLevel, "Cannot allocate json_array"); break; } //Parse domain list and collect statistics for every domain for (str = domain_list; ; str = NULL) { if ((token = strtok_r(str, ",", &saveptr)) == NULL) { break; } domain = atoi(token); dps_statistics_update_per_domain(domain); //TODO: Get statistics and push it to requestor //Currently the pushing action is OK, but now it is turned off, //it should be turned on when the system is actually deployed memset(&load_balancing, 0, sizeof(load_balancing)); load_balancing.domain_id = domain; dps_statistics_domain_load_balancing_get(&load_balancing); if(dps_statistics_array_append(js_stats, &load_balancing) != DOVE_STATUS_OK) { log_error(RESTHandlerLogLevel, "Cannot append statistics for domain %d", domain); json_decref(js_stats); js_stats = NULL; break; } } if (js_stats == NULL) { break; } log_info(RESTHandlerLogLevel, "Send statistics to LEADER!"); dps_statistics_report_to_cluster_leader(js_stats); }while(0); if (domain_list != NULL) { free(domain_list); } return; }