/* * The request send state. Here, the packet is actually transmitted * across the network. After setting up timeouts, the request * moves to the acknowledgement wait state. We return from the state * machine at this point, and let the request be received from the network. */ static p_action_t s_sendreq( proto_t * p, p_action_t action, pkt_t * pkt) { assert(p != NULL); (void)action; /* Quiet unused parameter warning */ (void)pkt; /* Quiet unused parameter warning */ if (security_sendpkt(p->security_handle, &p->req) < 0) { /* XXX should retry */ security_seterror(p->security_handle, _("error sending REQ: %s"), security_geterror(p->security_handle)); return (PA_ABORT); } /* * Remember when this request was first sent */ p->curtime = CURTIME; /* * Move to the ackwait state */ p->state = s_ackwait; p->timeout = ACK_WAIT; return (PA_PENDING); }
static void handle_result( G_GNUC_UNUSED void *datap, pkt_t * pkt, security_handle_t * sech) { char *line; char *s; int ch; if (pkt == NULL) { g_fprintf(stdout, _("Request failed: %s\n"), security_geterror(sech)); remote_errors++; return; } s = pkt->body; ch = *s++; while(ch) { line = s - 1; skip_quoted_line(s, ch); if (s[-2] == '\n') { s[-2] = '\0'; } fprintf(stdout, "%s\n", line); } fprintf(stdout, "\n"); }
/* * The reply wait state. We enter here much like we do with s_ackwait. */ static p_action_t s_repwait( proto_t * p, p_action_t action, pkt_t * pkt) { pkt_t ack; /* * Timeout waiting for a reply. */ if (action == PA_TIMEOUT) { assert(pkt == NULL); /* * If we've blown our timeout limit, free up this packet and * return. */ if (p->resettries == 0 || DROP_DEAD_TIME(p->origtime)) { security_seterror(p->security_handle, _("timeout waiting for REP")); return (PA_ABORT); } /* * We still have some tries left. Resend the request. */ p->resettries--; p->state = s_sendreq; p->reqtries = getconf_int(CNF_REQ_TRIES); return (PA_CONTINUE); } assert(action == PA_RCVDATA); /* Finish if we get a NAK */ if (pkt->type == P_NAK) return (PA_FINISH); /* * We've received some data. If we didn't get a reply, * requeue the packet and retry. Otherwise, acknowledge * the reply, cleanup this packet, and return. */ if (pkt->type != P_REP && pkt->type != P_PREP) return (PA_PENDING); if(pkt->type == P_REP) { pkt_init_empty(&ack, P_ACK); if (security_sendpkt(p->security_handle, &ack) < 0) { /* XXX should retry */ amfree(ack.body); security_seterror(p->security_handle, _("error sending ACK: %s"), security_geterror(p->security_handle)); return (PA_ABORT); } amfree(ack.body); return (PA_FINISH); } else if(pkt->type == P_PREP) { p->timeout = p->repwait - CURTIME + p->curtime + 1; if (p->timeout <= 0) p->timeout = 1; return (PA_CONTPEND); } /* should never go here, shut up compiler warning */ return (PA_FINISH); }
static void amindexd_response( void *datap, pkt_t *pkt, security_handle_t *sech) { int ports[NSTREAMS], *response_error = datap; guint i; char *p; char *tok; char *extra = NULL; assert(response_error != NULL); assert(sech != NULL); if (pkt == NULL) { errstr = newvstrallocf(errstr, _("[request failed: %s]"), security_geterror(sech)); *response_error = 1; return; } if (pkt->type == P_NAK) { #if defined(PACKET_DEBUG) dbprintf(_("got nak response:\n----\n%s\n----\n\n"), pkt->body); #endif tok = strtok(pkt->body, " "); if (tok == NULL || strcmp(tok, "ERROR") != 0) goto bad_nak; tok = strtok(NULL, "\n"); if (tok != NULL) { errstr = newvstrallocf(errstr, "NAK: %s", tok); *response_error = 1; } else { bad_nak: errstr = newvstrallocf(errstr, _("request NAK")); *response_error = 2; } return; } if (pkt->type != P_REP) { errstr = newvstrallocf(errstr, _("received strange packet type %s: %s"), pkt_type2str(pkt->type), pkt->body); *response_error = 1; return; } #if defined(PACKET_DEBUG) g_fprintf(stderr, _("got response:\n----\n%s\n----\n\n"), pkt->body); #endif for(i = 0; i < NSTREAMS; i++) { ports[i] = -1; streams[i].fd = NULL; } p = pkt->body; while((tok = strtok(p, " \n")) != NULL) { p = NULL; /* * Error response packets have "ERROR" followed by the error message * followed by a newline. */ if (strcmp(tok, "ERROR") == 0) { tok = strtok(NULL, "\n"); if (tok == NULL) { errstr = newvstrallocf(errstr, _("[bogus error packet]")); } else { errstr = newvstrallocf(errstr, "%s", tok); } *response_error = 2; return; } /* * Regular packets have CONNECT followed by three streams */ if (strcmp(tok, "CONNECT") == 0) { /* * Parse the three stream specifiers out of the packet. */ for (i = 0; i < NSTREAMS; i++) { tok = strtok(NULL, " "); if (tok == NULL || strcmp(tok, streams[i].name) != 0) { extra = g_strdup_printf( _("CONNECT token is \"%s\": expected \"%s\""), tok ? tok : _("(null)"), streams[i].name); goto parse_error; } tok = strtok(NULL, " \n"); if (tok == NULL || sscanf(tok, "%d", &ports[i]) != 1) { extra = g_strdup_printf( _("CONNECT %s token is \"%s\" expected a port number"), streams[i].name, tok ? tok : _("(null)")); goto parse_error; } } continue; } /* * OPTIONS [options string] '\n' */ if (strcmp(tok, "OPTIONS") == 0) { tok = strtok(NULL, "\n"); if (tok == NULL) { extra = g_strdup(_("OPTIONS token is missing")); goto parse_error; } #if 0 tok_end = tok + strlen(tok); while((p = strchr(tok, ';')) != NULL) { *p++ = '\0'; if(strncmp_const(tok, "features=") == 0) { tok += sizeof("features=") - 1; am_release_feature_set(their_features); if((their_features = am_string_to_feature(tok)) == NULL) { errstr = newvstrallocf(errstr, _("OPTIONS: bad features value: %s"), tok); goto parse_error; } } tok = p; } #endif continue; } #if 0 extra = g_strdup_printf(_("next token is \"%s\": expected \"CONNECT\", \"ERROR\" or \"OPTIONS\""), tok ? tok : _("(null)")); goto parse_error; #endif } /* * Connect the streams to their remote ports */ for (i = 0; i < NSTREAMS; i++) { /*@i@*/ if (ports[i] == -1) continue; streams[i].fd = security_stream_client(sech, ports[i]); if (streams[i].fd == NULL) { errstr = newvstrallocf(errstr, _("[could not connect %s stream: %s]"), streams[i].name, security_geterror(sech)); goto connect_error; } } /* * Authenticate the streams */ for (i = 0; i < NSTREAMS; i++) { if (streams[i].fd == NULL) continue; if (security_stream_auth(streams[i].fd) < 0) { errstr = newvstrallocf(errstr, _("[could not authenticate %s stream: %s]"), streams[i].name, security_stream_geterror(streams[i].fd)); goto connect_error; } } /* * The MESGFD and DATAFD streams are mandatory. If we didn't get * them, complain. */ if (streams[MESGFD].fd == NULL) { errstr = newvstrallocf(errstr, _("[couldn't open MESG streams]")); goto connect_error; } /* everything worked */ *response_error = 0; amindexd_alive = 1; return; parse_error: errstr = newvstrallocf(errstr, _("[parse of reply message failed: %s]"), extra ? extra : _("(no additional information)")); amfree(extra); *response_error = 2; return; connect_error: stop_amindexd(); *response_error = 1; }