yppush.c
来自「<B>Digital的Unix操作系统VAX 4.2源码</B>」· C语言 代码 · 共 844 行 · 第 1/2 页
C
844 行
name[namelen] = '\0'; (void) strcpy(ps->name, name); ps->state = SSTAT_INIT; ps->status = 0; ps->oldvers = FALSE; if (h = (struct hostent *) gethostbyname(name) ) { ps->domb.dom_server_addr.sin_addr = *((struct in_addr *) h->h_addr); ps->domb.dom_server_addr.sin_family = AF_INET; ps->domb.dom_server_addr.sin_port = 0; ps->domb.dom_server_port = 0; ps->domb.dom_socket = RPC_ANYSOCK; ps->xactid = xactid + seq++; ps->pnext = server_list; server_list = ps; } else { (void) fprintf(stderr, "Can't get an address for server %s.\n", name); free(ps); }}/* * This sets the base range for the transaction ids used in speaking the the * server ypxfr processes. */voidxactid_seed(xactid)unsigned long *xactid;{ struct timeval t; if (gettimeofday(&t, (struct timezone *) NULL) == -1) { perror("yppush gettimeofday failure"); *xactid = 1234567; } else { *xactid = t.tv_sec; }}/* * This generates the udp channel which will be used as the listener process' * service rendezvous point, and comes up with a transient program number * for the use of the RPC messages from the ypxfr processes. */voidgenerate_callback(program, port, transport) unsigned long *program; unsigned short *port; SVCXPRT **transport;{ struct sockaddr_in a; long unsigned prognum; SVCXPRT *xport; if ((xport = svcudp_create(RPC_ANYSOCK) ) == (SVCXPRT *) NULL) { (void) fprintf(stderr, "Can't set up as a udp server.\n"); exit(1); } *port = xport->xp_port; *transport = xport; prognum = 0x40000000; while (!pmap_set(prognum++, YPPUSHVERS, IPPROTO_UDP, xport->xp_port) ) { ; } *program = --prognum;}/* * This is the main loop. Send messages to each server, * and then wait for a response. */voidmain_loop(program, port) unsigned long program; unsigned short port;{ int readfds; register struct server *ps; long error; if (!svc_register(transport, program, YPPUSHVERS, listener_dispatch, 0) ) { (void) fprintf(stderr, "Can't set up transient callback server.\n"); } signal(SIGALRM, set_time_up); signal(SIGHUP, set_interrupt); signal(SIGINT, set_interrupt); signal(SIGQUIT, set_interrupt); signal(SIGTERM, set_interrupt); for (ps = server_list; ps; ps = ps->pnext) { ps->state = send_message(ps, program, port, &error); print_state_msg(ps, error); if (ps->state != SSTAT_CALLED) continue; callback_timeout = FALSE; (void) alarm(GRACE_PERIOD); while ( callback_timeout == FALSE && ps->state == SSTAT_CALLED ) { readfds = svc_fds; errno = 0; switch ( (int) select(32, &readfds, NULL, NULL, NULL) ) { case -1: if (errno != EINTR) { (void) perror("main loop select"); callback_timeout = TRUE; } break; case 0: (void) fprintf (stderr, "Invalid timeout in main loop select.\n"); break; default: svc_getreq(readfds); break; } /* switch */ } /* while */ (void) alarm(0); if (ps->state == SSTAT_CALLED && !INTERRUPT) (void) fprintf( stderr, "No response from ypxfr on %s\n", ps->name); if (INTERRUPT) { (void) fprintf(stderr,"\nyppush: Operation interrupted, exiting..\n"); listener_exit(program, -1); } } /* for each server */}/* * This does the listener process cleanup and process exit. */voidlistener_exit(program, stat) unsigned long program; int stat;{ (void) pmap_unset(program, YPPUSHVERS); exit(stat);}/* * This is the listener process' RPC service dispatcher. */voidlistener_dispatch(rqstp, transp) struct svc_req *rqstp; SVCXPRT *transp;{ switch (rqstp->rq_proc) { case YPPUSHPROC_NULL: if (!svc_sendreply(transp, xdr_void, 0) ) { (void) fprintf(stderr, "Can't reply to rpc call.\n"); } break; case YPPUSHPROC_XFRRESP: get_xfr_response(rqstp, transp); break; default: svcerr_noproc(transp); break; }}/* * This dumps a server state message to stdout. It is called in cases where * we have no expectation of receiving a callback from the remote ypxfr. */voidprint_state_msg(s, e) struct server *s; long e;{ struct state_duple *sd; if (s->state == SSTAT_SYSTEM) return; /* already printed */ if (!verbose && ( s->state == SSTAT_RESPONDED || s->state == SSTAT_CALLED) ) return; for (sd = state_duples; sd->state_msg; sd++) { if (sd->state == s->state) { (void) printf(sd->state_msg, s->name); if (s->state == SSTAT_RPC) { rpcerr_msg((enum clnt_stat) e); } (void) printf("\n"); fflush(stdout); return; } } (void) fprintf(stderr, "yppush: Bad server state value %d.\n", s->state);}/* * This dumps a transfer status message to stdout. It is called in * response to a received RPC message from the called ypxfr. */voidprint_callback_msg(s) struct server *s;{ register struct status_duple *sd; if (!verbose && (s->status==YPPUSH_AGE) || (s->status==YPPUSH_SUCC)) return; for (sd = status_duples; sd->status_msg; sd++) { if (sd->status == s->status) { (void) printf( "Status received from ypxfr on %s:\n\t%s\n", s->name, sd->status_msg); fflush(stdout); return; } } (void) fprintf(stderr, "yppush listener: Garbage transaction status value from ypxfr on %s.\n", s->name);}/* * This dumps an RPC error message to stdout. This is basically a rewrite * of clnt_perrno, but writes to stdout instead of stderr. */voidrpcerr_msg(e) enum clnt_stat e;{ struct rpcerr_duple *rd; for (rd = rpcerr_duples; rd->rpc_msg; rd++) { if (rd->rpc_stat == e) { (void) printf(rd->rpc_msg); return; } } (void) fprintf(stderr,"Bad error code passed to rpcerr_msg: %d.\n",e);}/* * This picks up the response from the ypxfr process which has been started * up on the remote node. The response status must be non-zero, otherwise * the status will be set to "ypxfr error". */voidget_xfr_response(rqstp, transp) struct svc_req *rqstp; SVCXPRT *transp;{ struct yppushresp_xfr resp; register struct server *s; if (!svc_getargs(transp, xdr_yppushresp_xfr, &resp) ) { svcerr_decode(transp); return; } if (!svc_sendreply(transp, xdr_void, 0) ) { (void) fprintf(stderr, "Can't reply to rpc call.\n"); } for (s = server_list; s; s = s->pnext) { if (s->xactid == resp.transid) { s->status = resp.status ? resp.status: YPPUSH_XFRERR; print_callback_msg(s); s->state = SSTAT_RESPONDED; return; } }}/* * This is a UNIX signal handler which is called when the * timer expires waiting for a callback. */voidset_time_up(){ callback_timeout = TRUE;}/* Signal handler for "other" interruptions. Used so we don't * leave spurious registrations with the portmapper. */voidset_interrupt(){ set_time_up(); INTERRUPT = TRUE;}/* * This sends a message to a single ypserv process. The return value is * a state value. If the RPC call fails because of a version * mismatch, we'll assume that we're talking to a version 1 ypserv process, * and will send him an old "YPPROC_GET" request, as was defined in the * earlier version of yp_prot.h */unsigned shortsend_message(ps, program, port, err) struct server *ps; unsigned long program; unsigned short port; long *err;{ struct ypreq_xfr req; struct yprequest oldreq; enum clnt_stat s; char my_name[YPMAXPEER +1]; struct rpc_err rpcerr; if ((ps->domb.dom_client = clntudp_create(&(ps->domb.dom_server_addr), YPPROG, YPVERS, udp_intertry, &(ps->domb.dom_socket))) == NULL) { if (rpc_createerr.cf_stat == RPC_PROGNOTREGISTERED) { return(SSTAT_PROGNOTREG); } else { (void) printf("Error talking to %s: ",ps->name); rpcerr_msg(rpc_createerr.cf_stat); (void) printf("\n"); fflush(stdout); return(SSTAT_SYSTEM); } } if (gethostname(my_name, sizeof (my_name) ) == -1) { return(SSTAT_RSCRC); } req.ypxfr_domain = domain; req.ypxfr_map = map; req.ypxfr_ordernum = 0; req.ypxfr_owner = my_name; req.transid = ps->xactid; req.proto = program; req.port = port; s = (enum clnt_stat) clnt_call(ps->domb.dom_client, YPPROC_XFR, xdr_ypreq_xfr, &req, xdr_void, 0, udp_timeout); clnt_geterr(ps->domb.dom_client, &rpcerr); clnt_destroy(ps->domb.dom_client); close(ps->domb.dom_socket); if (s == RPC_SUCCESS) { return (SSTAT_CALLED); } else { if (s == RPC_PROGVERSMISMATCH) { ps->domb.dom_server_addr.sin_family = AF_INET; ps->domb.dom_server_addr.sin_port = 0; ps->domb.dom_server_port = 0; ps->domb.dom_socket = RPC_ANYSOCK; if ((ps->domb.dom_client = clntudp_create(&(ps->domb.dom_server_addr), YPPROG, (YPVERS - 1), udp_intertry, &(ps->domb.dom_socket))) == NULL) { if (rpc_createerr.cf_stat == RPC_PROGNOTREGISTERED) { return(SSTAT_PROGNOTREG); } else { (void) printf("V1 Error talking to %s: ", ps->name); rpcerr_msg(rpc_createerr.cf_stat); (void) printf("\n"); fflush(stdout); return(SSTAT_SYSTEM); } } oldreq.yp_reqtype = YPGET_REQTYPE; oldreq.ypget_req_domain = domain; oldreq.ypget_req_map = map; oldreq.ypget_req_ordernum = 0; oldreq.ypget_req_owner = my_name; s = (enum clnt_stat) clnt_call( ps->domb.dom_client, YPOLDPROC_GET, _xdr_yprequest, &oldreq, xdr_void, 0, udp_timeout); clnt_geterr(ps->domb.dom_client, &rpcerr); clnt_destroy(ps->domb.dom_client); close(ps->domb.dom_socket); } if (s == RPC_SUCCESS) { return (SSTAT_RESPONDED); } else { *err = (long) rpcerr.re_status; return (SSTAT_RPC); } }}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?