/*=r=************************************************************************/ static void m__previous (NAK *nak_ptr, NODE *current, NODE **previous) /* WHAT IT DOES: Given a Nak-list ('nak') and a node ('current'), * it attempts to locate the node previous to 'current'. If successful, * '*previous' contains a pointer to that node; otherwise, '*previous' is * null. */ { NODE *p; /*------------------------------------------------------------*/ /* Initialize '*previous' to indicate failure */ *previous = NULL; if (current == nak_ptr->head) /* There is no 'previous' node for the list-head */ return; /* Walk through the list, looking for a node which points to the * given node. */ for (p=nak_ptr->head; p!=NULL; p=p->next) if (p->next == current) /* We found it. */ break; /* Validate that the given node was on the list */ ASSERT__ (p != NULL); /* Return the result. If the walk completed without finding the * node (assertion fired) the result will be NULL, which * is the best answer we can give. */ *previous = p; }
/*=r=************************************************************************/ static void m__incorporate_gap (NAK *nak_ptr, u_int_4 begin, u_int_4 end) /* WHAT IT DOES: To avoid 'losing' the knowledge of this gap forever, * extend the end-point of the last gap to include this one. * On the bad side, this results in retransmission of data that * was already received. On the good side, the transaction is able * to complete successfully, because all data gaps are remembered. */ { GAP *p; /*------------------------------------------------------------*/ /* Before doing anything, validate the input pointer */ ASSERT__ (nak_ptr->head != NULL); if (nak_ptr->head == NULL) /* Avoid crashing if engine user continues after assertion fires */ return; /* Move to the last node (gap) on the given list */ for (p=nak_ptr->head; p->next!=NULL; p=p->next) ; p->end = end; if (end > nak_ptr->end_of_scope) /* Extend the scope of this Nak */ nak_ptr->end_of_scope = end; }
/*=r=************************************************************************/ static void m__remove_node (NAK *nak_ptr, NODE *obsolete) /* WHAT IT DOES: Removes the given node from the given nak-list. */ { NODE *node_before_obsolete; /*------------------------------------------------------------*/ /* (The nak-list should never be empty at this point) */ ASSERT__ (nak_ptr->head != NULL); if (nak_ptr->head == NULL) /* Avoid crashing if engine user continues after assertion fires */ return; if (obsolete == nak_ptr->head) /* Remove node from front of list */ { nak_ptr->head = obsolete->next; nak_mem__free (nak_ptr, obsolete); } else /* Remove node from interior/end of list */ { /* Find the node that is previous to the obsolete node, * and have that node point around the obsolete node (so that all * nodes are still linked together). * Then the obsolete node can be deleted safely. */ m__previous (nak_ptr, obsolete, &node_before_obsolete); ASSERT__ (node_before_obsolete != NULL); if (node_before_obsolete == NULL) /* Avoid crashing if engine user continues after assertion fires */ return; node_before_obsolete->next = obsolete->next; nak_mem__free (nak_ptr, obsolete); } }
/*=r=************************************************************************/ static boolean m__intercept_secret_commands (char *user_input) #define MAX_ANSWER_LENGTH 80 { u_int_4 active_count; char answer [MAX_ANSWER_LENGTH+1]; char arg1 [64]; char arg2 [64]; char arg3 [64]; char arg4 [64]; CONDITION_CODE code; int i; u_int_4 number; boolean secret = NO; SUMMARY_STATUS summary; /*------------------------------------------------------------*/ /* Extract all args (tokens) from the given input, and convert * some of them to lowercase. */ memset (arg1, 0, sizeof(arg1)); memset (arg2, 0, sizeof(arg2)); memset (arg3, 0, sizeof(arg3)); memset (arg4, 0, sizeof(arg4)); sscanf (user_input, "%64s %64s %64s %64s", arg1, arg2, arg3, arg4); for (i=0; i<strlen(arg1); i++) arg1[i] = tolower(arg1[i]); for (i=0; i<strlen(arg2); i++) arg2[i] = tolower(arg2[i]); if ((!strcmp (arg1, "use_pipes")) || (!strcmp (arg1, "p"))) { secret = YES; if (!m_are_pipes_enabled) { m__create_and_open_output_pipe (); m__create_and_open_input_pipe (); } m_are_pipes_enabled = YES; } else if (!strcmp (arg1, "how_many_active_transactions?")) { secret = YES; summary = cfdp_summary_status (); active_count = summary.how_many_senders + summary.how_many_receivers; sprintf (answer, "%lu", active_count); ASSERT__ (strlen(answer) <= MAX_ANSWER_LENGTH); if (m_debug_pipe) msg__ ("Pipe output: %s\n", answer); /* ^^^ sleep (1);*/ /* Kludge!!! Needed for back-to-back msgs to named-pipe */ fprintf (m_fp_out, "%s\n", answer); fflush (m_fp_out); } else if (!strcmp (arg1, "last_condition_code?")) { secret = YES; code = cfdp_last_condition_code(); if (code == NO_ERROR) strcpy (answer, "No_error"); else if (code == CANCEL_REQUEST_RECEIVED) strcpy (answer, "Cancel_request_received"); else if (code == POSITIVE_ACK_LIMIT_REACHED) strcpy (answer, "Positive_ack_limit_reached"); else if (code == NAK_LIMIT_REACHED) strcpy (answer, "Nak_limit_reached"); else if (code == INACTIVITY_DETECTED) strcpy (answer, "Inactivity_detected"); else if (code == FILESTORE_REJECTION) strcpy (answer, "Filestore_rejection"); else if (code == FILE_CHECKSUM_FAILURE) strcpy (answer, "File_checksum_failure"); else if (code == FILE_SIZE_ERROR) strcpy (answer, "File_size_error"); else strcpy (answer, "?"); if (m_debug_pipe) msg__ ("Pipe output: %s\n", answer); /* ^^^ sleep (1);*/ /* Kludge!!! Needed for back-to-back msgs to named-pipe */ fprintf (m_fp_out, "%s\n", answer); fflush (m_fp_out); } else if (!strcmp (arg1, "cancelling?")) { secret = YES; if (cfdp_is_a_trans_being_cancelled ()) strcpy (answer, "Yes"); else strcpy (answer, "No"); if (m_debug_pipe) msg__ ("Pipe output: %s\n", answer); /* ^^^ sleep (1);*/ /* Kludge!!! Needed for back-to-back msgs to named-pipe */ fprintf (m_fp_out, "%s\n", answer); fflush (m_fp_out); } else if (!strcmp (arg1, "last_transaction_abandoned?")) { secret = YES; if (m_was_last_trans_abandoned) strcpy (answer, "Yes"); else strcpy (answer, "No"); if (m_debug_pipe) msg__ ("Pipe output: %s\n", answer); /* ^^^ sleep (1);*/ /* Kludge!!! Needed for back-to-back msgs to named-pipe */ fprintf (m_fp_out, "%s\n", answer); fflush (m_fp_out); } else if (!strcmp (arg1, "date")) { secret = YES; system ("date"); } else if (!strcmp (arg1, "print")) { secret = YES; msg__ ("\n\n\n%s %s %s\n", arg2, arg3, arg4); } else if (!strcmp (arg1, "set_trans_seq_num")) { secret = YES; number = atoi (arg2); cfdp_set_trans_seq_num (number); msg__ ("Trans_seq_num set to %lu.\n", number); } return (secret); }
/*=r=*************************************************************************/ static void m__all_data_has_been_received (MACHINE *m) /* WHAT IT DOES: Performs the actions required after all data has * been delivered. Typically, validates the delivered file, moves * it to the destination specified in the Metadata PDU, and * builds/queues an outgoing Finished-No-error PDU. */ { TRANS_STATUS *mp = &(m->publik); /* useful shorthand */ /*------------------------------------------------------------*/ /* IMPORTANT: The program will crash if the actions in this routine are * carried out more than once, so prevent that from happening. */ if (mp->delivery_code == DATA_COMPLETE) /* Return immediately! */ { w_msg__ ("cfdp_engine: 'all_data_has_been_received' called 2+ times.\n"); return; } /* We've received everything, so delivery is complete... */ mp->delivery_code = DATA_COMPLETE; /* ... and there is no need to send a Nak back to the sender. */ m->is_outgoing_nak_buffered = NO; timer__cancel (&m->nak_timer); /* If a file has been transferred, do something with it */ if (mp->md.file_transfer) { /* If the temporary file is still open, then close it */ if (m->is_there_an_open_file) { ASSERT__ (m->fp != NULL); if (m->fp == NULL) /* This should never happen, but if it does, avoid crashing */ ; else fclose_callback (m->fp); m->is_there_an_open_file = NO; } /* Validate the received file (via the checksum) */ if (!aaa__is_file_checksum_valid (m)) { if (!m__fault_handler (m, FILE_CHECKSUM_FAILURE)) return; } /* Move the temporary file to the real destination */ if (!rename_callback (mp->temp_file_name, mp->md.dest_file_name)) /* Success */ m->is_there_a_temp_file = NO; else /* Oops. Our attempt to move the file failed. */ { e_msg__ ("cfdp_engine: unable to rename '%s' to '%s'.\n", mp->temp_file_name, mp->md.dest_file_name); e_msg__ ("cfdp_engine: are they on separate filesystems?\n"); if (!m__fault_handler (m, FILESTORE_REJECTION)) return; } } /* <NOT_SUPPORTED> Filestore Requests (executed here) */ /* Build and queue a Finished Pdu */ m->fin = aaa__build_fin (NO_ERROR, mp->delivery_code); m->is_outgoing_fin_buffered = YES; mp->attempts = 0; }