📄 pluto_crypt.c
字号:
passert(w->pcw_pid != -1); passert(w->pcw_pipe != -1); passert(w->pcw_work > 0); DBG(DBG_CONTROL , DBG_log("asking helper %d to do %s op on seq: %u" , w->pcw_helpernum , enum_show(&pluto_cryptoop_names, r->pcr_type) , r->pcr_id)); /* send the request, and then mark the work as having more work */ cnt = write(w->pcw_pipe, r, r->pcr_len); if(cnt == -1) { /* XXX invoke callback with failure */ passert(0); return; } w->pcw_work++; }}bool pluto_crypt_handle_dead_child(int pid, int status UNUSED){ int cnt; struct pluto_crypto_worker *w = pc_workers; for(cnt = 0; cnt < pc_workers_cnt; cnt++, w++) { if(w->pcw_pid == pid) { w->pcw_reaped = TRUE; if(w->pcw_dead == TRUE) { cleanup_crypto_helper(w); } return TRUE; } } return FALSE;} /* * this function is called when there is a helper pipe that is ready. * we read the request from the pipe, and find the associated continuation, * and dispatch to that continuation. * * this function should process only a single answer, and then go back * to the select call to get called again. This is not most efficient, * but is is most fair. * */void handle_helper_comm(struct pluto_crypto_worker *w){ char reqbuf[PCR_REQ_SIZE]; struct pluto_crypto_req *r; int restlen; int actlen; struct pluto_crypto_req_cont *cn, **cnp; /* we can accept more work now that we are about to read from the pipe */ w->pcw_work--; DBG(DBG_CRYPT, DBG_log("helper %u has work (cnt now %d)" ,w->pcw_helpernum ,w->pcw_work)); /* read from the pipe */ actlen = read(w->pcw_pipe, reqbuf, sizeof(r->pcr_len)); if(actlen != sizeof(r->pcr_len)) { if(actlen != 0) { loglog(RC_LOG_SERIOUS, "read failed with %d: %s" , actlen, strerror(errno)); } /* * eof, mark worker as dead. If already reaped, then free. */ w->pcw_dead = TRUE; if(w->pcw_reaped) { cleanup_crypto_helper(w); } return; } r = (struct pluto_crypto_req *)reqbuf; if(r->pcr_len > sizeof(reqbuf)) { loglog(RC_LOG_SERIOUS, "helper(%d) pid=%d screwed up length: %lu > %lu, killing it" , w->pcw_helpernum , w->pcw_pid, (unsigned long)r->pcr_len , (unsigned long)sizeof(reqbuf)); kill(w->pcw_pid, SIGTERM); w->pcw_dead = TRUE; return; } restlen = r->pcr_len-sizeof(r->pcr_len); /* okay, got a basic size, read the rest of it */ if((actlen= read(w->pcw_pipe , reqbuf+sizeof(r->pcr_len) , restlen)) != restlen) { /* faulty read. die, parent will restart us */ loglog(RC_LOG_SERIOUS , "cryptographic handler(%d) read(%d)=%d failed: %s\n" , w->pcw_pipe, restlen, actlen, strerror(errno)); return; } DBG(DBG_CRYPT, DBG_log("helper %u replies to sequence %u" ,w->pcw_helpernum ,r->pcr_id)); /* * if there is work queued, then send it off after reading, since this * avoids the most deadlocks */ crypto_send_backlog(w); /* now match up request to continuation, and invoke it */ cn = w->pcw_cont; cnp = &w->pcw_cont; while(cn && r->pcr_id != cn->pcrc_id) { cnp = &cn->pcrc_next; cn = cn->pcrc_next; } if(cn == NULL) { loglog(RC_LOG_SERIOUS , "failed to find continuation associated with req %u\n", (unsigned int)r->pcr_id); return; } /* unlink it */ *cnp = cn->pcrc_next; cn->pcrc_next = NULL; passert(cn->pcrc_func != NULL); DBG(DBG_CRYPT, DBG_log("calling callback function %p" ,cn->pcrc_func)); /* call the continuation */ (*cn->pcrc_func)(cn, r, NULL); /* now free up the continuation */ pfree(cn);}/* * initialize a helper. */static void init_crypto_helper(struct pluto_crypto_worker *w, int n){ int fds[2]; int errno2; /* reset this */ w->pcw_pid = -1; if(socketpair(PF_UNIX, SOCK_STREAM, 0, fds) != 0) { loglog(RC_LOG_SERIOUS, "could not create socketpair for helpers: %s", strerror(errno)); return; } w->pcw_helpernum = n; w->pcw_pipe = fds[0]; w->pcw_maxbasicwork = 2; w->pcw_maxcritwork = 4; w->pcw_work = 0; w->pcw_reaped = FALSE; w->pcw_dead = FALSE; /* set the send/received queue length to be at least maxcritwork * times sizeof(pluto_crypto_req) in size */ { int qlen = w->pcw_maxcritwork * sizeof(struct pluto_crypto_req) + 10; if(setsockopt(fds[0], SOL_SOCKET, SO_SNDBUF,&qlen, sizeof(qlen))==-1 || setsockopt(fds[0],SOL_SOCKET,SO_SNDBUF,&qlen,sizeof(qlen))==-1 || setsockopt(fds[1],SOL_SOCKET,SO_RCVBUF,&qlen,sizeof(qlen))==-1 || setsockopt(fds[1],SOL_SOCKET,SO_RCVBUF,&qlen,sizeof(qlen))==-1) { loglog(RC_LOG_SERIOUS, "could not set socket queue to %d", qlen); return; } } /* flush various descriptors so that they don't get written twice */ fflush(stdout); fflush(stderr); close_log(); close_peerlog(); w->pcw_pid = fork(); errno2 = errno; if(w->pcw_pid == 0) { /* this is the CHILD */ int fd; int maxfd; struct rlimit nf; int i; /* diddle with our proc title */ memset(global_argv[0], '\0', strlen(global_argv[0])+1); sprintf(global_argv[0], "pluto helper %s #%3d ", pluto_ifn_inst, n); for(i = 1; i < global_argc; i++) { if(global_argv[i]) { int l = strlen(global_argv[i]); memset(global_argv[i], '\0', l); } global_argv[i]=NULL; } if(getenv("PLUTO_CRYPTO_HELPER_DEBUG")) { sprintf(global_argv[0], "pluto helper %s #%3d (waiting for GDB) " , pluto_ifn_inst, n); sleep(60); /* for debugger to attach */ sprintf(global_argv[0], "pluto helper %s #%3d " , pluto_ifn_inst, n); } if(getrlimit(RLIMIT_NOFILE, &nf) == -1) { maxfd = 256; } else { maxfd = nf.rlim_max; } /* in child process, close all non-essential fds */ for(fd = 3; fd < maxfd; fd++) { if(fd != fds[1]) close(fd); } pluto_init_log(); init_rnd_pool(); free_preshared_secrets(); openswan_passert_fail = helper_passert_fail; debug_prefix='!'; pluto_crypto_helper(fds[1], n); exit(0); /* NOTREACHED */ } /* open the log files again */ pluto_init_log(); if(w->pcw_pid == -1) { loglog(RC_LOG_SERIOUS, "failed to start child, error = %s" , strerror(errno2)); close(fds[1]); close(fds[0]); w->pcw_dead = TRUE; return; } /* PARENT */ openswan_log("started helper pid=%d (fd:%d)", w->pcw_pid, w->pcw_pipe); /* close client side of socket pair in parent */ close(fds[1]);}/* * clean up after a crypto helper */static void cleanup_crypto_helper(struct pluto_crypto_worker *w){ w->pcw_pid = -1; if(w->pcw_pipe) { loglog(RC_LOG_SERIOUS, "closing helper(%u) pid=%d fd=%d" , w->pcw_helpernum, w->pcw_pid, w->pcw_pipe); close(w->pcw_pipe); } w->pcw_reaped = FALSE; w->pcw_dead = FALSE; /* marking is not dead lets it live again */}/* * initialize the helpers. * * Later we will have to make provisions for helpers that have hardware * underneath them, in which case, they may be able to accept many * more requests than average. * */void init_crypto_helpers(int nhelpers){ int i; pc_workers = NULL; pc_workers_cnt = 0; pcw_id = 1; /* find out how many CPUs there are, if nhelpers is -1 */ /* if nhelpers == 0, then we do all the work ourselves */ if(nhelpers == -1) { int ncpu_online = sysconf(_SC_NPROCESSORS_ONLN); if(ncpu_online > 2) { nhelpers = ncpu_online - 1; } else { /* * if we have 2 CPUs or less, then create 1 helper, since * we still want to deal with head-of-queue problem. */ nhelpers = 1; } } if(nhelpers > 0) { openswan_log("starting up %d cryptographic helpers", nhelpers); pc_workers = alloc_bytes(sizeof(*pc_workers)*nhelpers , "pluto helpers"); pc_workers_cnt = nhelpers; for(i=0; i<nhelpers; i++) { init_crypto_helper(&pc_workers[i], i); } } else { openswan_log("no helpers will be started, all cryptographic operations will be done inline"); } pc_worker_num = 0;}void pluto_crypto_helper_sockets(fd_set *readfds){ int cnt; struct pluto_crypto_worker *w = pc_workers; for(cnt = 0; cnt < pc_workers_cnt; cnt++, w++) { if(w->pcw_pid != -1 && !w->pcw_dead) { passert(w->pcw_pipe > 0); FD_SET(w->pcw_pipe, readfds); } }}int pluto_crypto_helper_ready(fd_set *readfds){ int cnt; struct pluto_crypto_worker *w = pc_workers; int ndes; ndes = 0; for(cnt = 0; cnt < pc_workers_cnt; cnt++, w++) { if(w->pcw_pid != -1 && !w->pcw_dead) { passert(w->pcw_pipe > 0); if(FD_ISSET(w->pcw_pipe, readfds)) { handle_helper_comm(w); ndes++; } } } return ndes;}/* * Local Variables: * c-basic-offset:4 * c-style: pluto * End: */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -