📄 sel_svc.c
字号:
/* * Give_holder: clients ask for a holder for the service as they start up */static voidseln_svc_give_holder(transport) SVCXPRT *transport; { Seln_holder hold; hold.rank = SELN_UNKNOWN; hold.state = SELN_NONE; hold.access = clients.access; (void) svc_sendreply(transport, xdr_seln_holder, (char *)(LINT_CAST(&hold))); } /* Procedures by which the service resonds to requests about * files it's acting as the holder of *//* seln_svc_do_function: respond to a function-key release when * service holds a file as a selection or shelf. *//*ARGSUSED*/static voidseln_svc_do_function(private, buffer) caddr_t private; Seln_function_buffer *buffer;{ Seln_holder **hold = NULL; if (seln_figure_response(buffer, hold) != SELN_IGNORE) { complain("Service asked to to perform meaningless operation on a file-selection?" ); }}/* seln_svc_do_reply: respond to a request concerning a selection * for which selection service holds a file. */static Seln_resultseln_svc_do_reply(item, context, len) Seln_attribute item; Seln_replier_data *context; int len;{ struct stat stat_buf; int fd, count, size; char *destp; extern long lseek(); if ((int) item >= ord(SELN_TRACE_ACQUIRE) && (int) item <= ord(SELN_TRACE_DUMP)) { *context->response_pointer++ = (char *) seln_svc_debug(item, (u_int)(LINT_CAST( *context->request_pointer))); return SELN_SUCCESS; } if ((int) item == SELN_SET_NOTIFY_SUPPRESSION || (int) item == SELN_GET_NOTIFY_SUPPRESSION) { *context->response_pointer++ = seln_svc_notify_suppression(item, (u_int)(LINT_CAST(*context->request_pointer))); return SELN_SUCCESS; } if (holder[ord(context->rank)].state != SELN_FILE) { return SELN_DIDNT_HAVE; } fd = held_file[ord(context->rank)]; if (fstat(fd, &stat_buf) != 0) { perror("Selection service couldn't reply about a file"); return SELN_FAILED; } if (context->context == 0) { if (lseek(fd, 0L, 0) == (long)-1) { perror("Selection service couldn't reset to start of file"); return SELN_FAILED; } } switch (item) { case SELN_REQ_BYTESIZE: *context->response_pointer++ = (char *) stat_buf.st_size; return SELN_SUCCESS; case SELN_REQ_CONTENTS_ASCII: size = stat_buf.st_size - (int) context->context; if (size > len) { count = read(fd,(char *)(LINT_CAST(context->response_pointer)), len); if (count != len) { goto terminate_buffer; } context->response_pointer = (char **) (LINT_CAST( ((char *) (LINT_CAST(context->response_pointer)) + count))); context->context += count; return SELN_CONTINUED; } else { count = read(fd,(char*)(LINT_CAST(context->response_pointer)), size); terminate_buffer: destp = (char *) context->response_pointer; destp += count; while ((int) destp % 4 != 0) { *destp++ = '\0'; } context->response_pointer = (char **) (LINT_CAST(destp)); *context->response_pointer++ = (char *) 0; return SELN_SUCCESS; } case SELN_REQ_YIELD: *context->response_pointer++ = (char *) seln_svc_do_yield(context->rank); return SELN_SUCCESS; case SELN_REQ_END_REQUEST: return SELN_SUCCESS; default: return SELN_UNRECOGNIZED; }}/* seln_svc_do_yield: respond to a yield request when * service holds a file as a selection or shelf. */static Seln_resultseln_svc_do_yield(input) Seln_rank input;{ Seln_result result; if (trace_yield) { (void)fprintf(stderr, "Service told to yield "); seln_dump_rank(stderr, &input); (void)fprintf(stderr, " selection.\n"); } if (ord(input) < ord(SELN_PRIMARY) || ord(input) > ord(SELN_SHELF) || holder[ord(input)].state != SELN_FILE) { result = SELN_DIDNT_HAVE; } else if (seln_function_pending && ord(input) == ord(SELN_PRIMARY)) { result = SELN_WRONG_RANK; } else { /* reset state, but not access, to preserve the fact that * this selection was made */ holder[ord(input)].state = SELN_NONE; (void)close(held_file[ord(input)]); held_file[ord(input)] = 0; result = SELN_SUCCESS; } if (trace_yield) { (void)fprintf(stderr, "Service yield returns "); seln_dump_result(stderr, &result); (void)fprintf(stderr, "\n"); } return result;}/* * Init_access: fill in the service_access struct so we can * respond to requests for file-selections. */static voidseln_svc_init_access(access) Seln_access *access;{ if ((seln_my_udp_transport = svcudp_bufcreate(RPC_ANYSOCK, SELN_RPC_BUFSIZE, SELN_RPC_BUFSIZE)) == (SVCXPRT *) NULL) { perror("selection_service"); (void)fprintf(stderr, "Couldn't start selection service.\n"); return; } seln_my_udp_socket = seln_my_udp_transport->xp_sock; (void) seln_svc_unmap(); if (!svc_register(seln_my_udp_transport, seln_svc_program, SELN_VERSION, seln_svc_dispatch, IPPROTO_UDP)) { perror("selection_service"); (void)fprintf(stderr, "Couldn't start selection service.\n"); (void)close(seln_my_udp_socket); svc_destroy(seln_my_udp_transport); return; } access->pid = getpid(); access->program = seln_svc_program; get_myaddress(&access->udp_address); access->udp_address.sin_port = htons(seln_my_udp_transport->xp_port); access->client = (caddr_t) &clients; old_func = notify_set_input_func((Notify_client) seln_my_udp_transport, seln_listener, seln_my_udp_socket); if (seln_get_tcp(seln_svc_program, seln_svc_dispatch) != SELN_SUCCESS) { (void)close(seln_my_udp_socket); svc_destroy(seln_my_udp_transport); return; } access->tcp_address = access->udp_address; access->tcp_address.sin_port = htons(seln_my_tcp_transport->xp_port);}/* * Tell holders of data selections that a function key has gone up, * & who they should contact about it. This routine returns the * buffer (and doesn't send it to the informing client) to prevent * race where the informer might get a button click between informing * the service and getting its notification. This way, it acts on the * return value from seln_inform, before going back to the notifier. */static Seln_function_bufferseln_execute_fn(args) Seln_inform_args *args;{ static Seln_rank informer; Seln_function_buffer buffer; buffer.function = args->function; buffer.caret = holder[ord(SELN_CARET)]; buffer.primary = holder[ord(SELN_PRIMARY)]; buffer.secondary = holder[ord(SELN_SECONDARY)]; buffer.shelf = holder[ord(SELN_SHELF)]; informer = SELN_UNKNOWN; if (!full_notifications) { /* New style: 1 notification */ register Seln_rank recipient; switch (args->function) { case SELN_FN_GET: case SELN_FN_FIND: recipient = SELN_CARET; break; case SELN_FN_PUT: case SELN_FN_DELETE: if (buffer.secondary.state == SELN_EXISTS) { recipient = SELN_SECONDARY; } else { recipient = SELN_PRIMARY; } break; default: return seln_null_function; } if (holder[ord(recipient)].state != SELN_EXISTS) return seln_null_function; /* if the informer is the intended recipient, tell him in the * return value. Otherwise, send a notification and give the * informer a no-op return. */ if (seln_equal_access(&args->holder.access, &holder[ord(recipient)].access)) { buffer.addressee_rank = recipient; return buffer; } else { (void) seln_send_msg(recipient, &buffer); return seln_null_function; } } else { /* Old style: 1 - 4 notifications */ if (holder[ord(SELN_CARET)].state != SELN_NONE) { if (seln_equal_access(&args->holder.access, &buffer.caret.access)) { informer = SELN_CARET; } else { if (seln_send_msg(SELN_CARET, &buffer) != SELN_SUCCESS) { return seln_null_function; } } } if (holder[ord(SELN_PRIMARY)].state != SELN_NONE && !seln_equal_access(&buffer.primary.access, &buffer.caret.access)) { if (seln_equal_access(&args->holder.access, &buffer.primary.access)) { informer = SELN_PRIMARY; } else { if (seln_send_msg(SELN_PRIMARY, &buffer) != SELN_SUCCESS) { return seln_null_function; } } } if (holder[ord(SELN_SECONDARY)].state != SELN_NONE && !seln_equal_access(&buffer.secondary.access, &buffer.caret.access) && !seln_equal_access(&buffer.secondary.access, &buffer.primary.access)) { if (seln_equal_access(&args->holder.access, &buffer.secondary.access)) { informer = SELN_SECONDARY; } else { if (seln_send_msg(SELN_SECONDARY, &buffer) != SELN_SUCCESS) { return seln_null_function; } } } if (holder[ord(SELN_SHELF)].state != SELN_NONE && !seln_equal_access(&buffer.shelf.access, &buffer.caret.access) && !seln_equal_access(&buffer.shelf.access, &buffer.primary.access) && !seln_equal_access(&buffer.shelf.access, &buffer.secondary.access)) { if (seln_equal_access(&args->holder.access, &buffer.shelf.access)) { informer = SELN_SHELF; } else { if (seln_send_msg(SELN_SHELF, &buffer) != SELN_SUCCESS) { return seln_null_function; } } } } if (informer == SELN_UNKNOWN) { return seln_null_function; } else { buffer.addressee_rank = informer; return buffer; }}static Seln_resultseln_send_msg(rank, buffer) Seln_rank rank; Seln_function_buffer *buffer;{ register Seln_holder *recipient; register CLIENT *client; struct timeval timeout; enum clnt_stat result; int socket = RPC_ANYSOCK; timeout.tv_sec = 0; timeout.tv_usec = 0; recipient = &holder[ord(rank)]; buffer->addressee_rank = rank; if ((client = clntudp_bufcreate(&recipient->access.udp_address, recipient->access.program, SELN_VERSION, timeout, &socket, SELN_RPC_BUFSIZE, SELN_RPC_BUFSIZE)) == (CLIENT *) NULL) { return SELN_FAILED; } if (trace_inform) { (void)fprintf(stderr, "\tfunction-key notification sent to "); seln_dump_rank(stderr, &rank); (void)fprintf(stderr, " holder.\n"); } result = clnt_call(client, SELN_CLNT_DO_FUNCTION, xdr_seln_function, buffer, xdr_void, 0, timeout); clnt_destroy(client); (void)close(socket); /* no, clnt_destroy didn't close it.... */ if (result == RPC_TIMEDOUT || result == RPC_SUCCESS) { if (trace_inform) { (void)fprintf(stderr, " notification returns Success\n"); } return SELN_SUCCESS; } else { if (trace_inform) { (void)fprintf(stderr, " notification returns Failure\n"); } return SELN_FAILED; }}static char *seln_svc_debug(attr, value) Seln_attribute attr; u_int value;{ if (attr == SELN_TRACE_DUMP) { return (char *) seln_dump_service(stderr, holder, (Seln_rank)value); } (void)fprintf(stderr, "Selection service trace %s for ", (value ? "on" : "off")); switch (attr) { case SELN_TRACE_ACQUIRE: (void)fprintf(stderr, "acquire.\n"); if (value == TRUE) { return (char *) (trace_acquire = TRUE); } else { return (char *) (trace_acquire = FALSE); } case SELN_TRACE_DONE: (void)fprintf(stderr, "done.\n"); if (value == TRUE) { return (char *) (trace_done = TRUE); } else { return (char *) (trace_done = FALSE); } case SELN_TRACE_HOLD_FILE: (void)fprintf(stderr, "hold file.\n"); if (value == TRUE) { return (char *) (trace_hold_file = TRUE); } else { return (char *) (trace_hold_file = FALSE); } case SELN_TRACE_INFORM: (void)fprintf(stderr, "inform.\n"); if (value == TRUE) { return (char *) (trace_inform = TRUE); } else { return (char *) (trace_inform = FALSE); } case SELN_TRACE_INQUIRE: (void)fprintf(stderr, "inquire.\n"); if (value == TRUE) { return (char *) (trace_inquire = TRUE); } else { return (char *) (trace_inquire = FALSE); } case SELN_TRACE_YIELD: (void)fprintf(stderr, "yield.\n"); if (value == TRUE) { return (char *) (trace_yield = TRUE); } else { return (char *) (trace_yield = FALSE); } case SELN_TRACE_STOP: (void)fprintf(stderr, "stop.\n"); if (value == TRUE) { return (char *) (trace_stop = TRUE); } else { return (char *) (trace_stop = FALSE); } /*NOTREACHED*/ } /*NOTREACHED*/}/* return or modify the flag which controls how many notifications * are sent on a function-button up (in response to a SELN_INFORM). */static char *seln_svc_notify_suppression(item, context, len) Seln_attribute item; Seln_replier_data *context; int len;{ int old; if (item == SELN_GET_NOTIFY_SUPPRESSION) { return (char *)full_notifications; } else { old = full_notifications; full_notifications = (int) *context->response_pointer; return (char *)old; }}/* how many interfaces could there be on a computer? */#define MAX_LOCAL 64static struct in_addr addrs[MAX_LOCAL];bool_tchklocal(taddr) struct in_addr taddr;{ int i; struct in_addr iaddr; int num_local; if (taddr.s_addr == INADDR_LOOPBACK) return (TRUE); num_local = getlocal(); for (i = 0; i < num_local; i++) { iaddr.s_addr = ntohl(addrs[i].s_addr); if (bcmp((char *) &taddr, (char *) &(iaddr), sizeof (struct in_addr)) == 0) return (TRUE); } return (FALSE);}intgetlocal(){ struct ifconf ifc; struct ifreq ifreq, *ifr; int n, j, sock; char buf[UDPMSGSIZE]; ifc.ifc_len = UDPMSGSIZE; ifc.ifc_buf = buf; sock = socket(PF_INET, SOCK_DGRAM, 0); if (sock < 0) return (FALSE); if (ioctl(sock, SIOCGIFCONF, (char *) &ifc) < 0) { perror("sel_svc:ioctl SIOCGIFCONF"); (void) close(sock); return (FALSE); } ifr = ifc.ifc_req; j = 0; for (n = ifc.ifc_len / sizeof (struct ifreq); n > 0; n--, ifr++) { ifreq = *ifr; if (ioctl(sock, SIOCGIFFLAGS, (char *) &ifreq) < 0) { perror("sel_svc:ioctl SIOCGIFFLAGS"); continue; } if ((ifreq.ifr_flags & IFF_UP) && ifr->ifr_addr.sa_family == AF_INET) { if (ioctl(sock, SIOCGIFADDR, (char *) &ifreq) < 0) { perror("SIOCGIFADDR"); } else { addrs[j] = ((struct sockaddr_in *) & ifreq.ifr_addr)->sin_addr; j++; } } if (j >= (MAX_LOCAL - 1)) break; } (void) close(sock); return (j);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -