/ tea2adt_source / mmsessionout.sh
mmsessionout.sh
  1  #!/bin/bash
  2  
  3  # message types
  4  ###############
  5  : '
  6      [init]
  7      [init_ack_chat]
  8      [init_ack_shell]
  9      [init_ack_llm]
 10      [init_ack_file]
 11      [keepalive]
 12      <probe>
 13      <start_msg>
 14      <end_msg>   
 15                      <preamble> <seq_tx><seq_rx>[ack]                                       <trailer>
 16                      <preamble> <seq_tx><seq_rx>[data]<input_data>                          <trailer>
 17                      <preamble> <seq_tx><seq_rx>[file_name]<file_name>[file]<file_data>     <trailer>
 18                      <preamble> <seq_tx><seq_rx>[file_name]<file_name>[file_end]<file_data> <trailer>
 19                                 \_______________ _________________________________________/
 20                                                 V
 21                                             encrypted
 22  '
 23  
 24  # configuration
 25  ###############
 26  TMP_PATH=$(head -n 1 cfg/tmp_path)
 27  END_MSG=$(head -n 1 ${HOME}${TMP_PATH}/cfg/end_msg)
 28  START_MSG=$(head -n 1 ${HOME}${TMP_PATH}/cfg/start_msg)
 29  TRAILER=$(head -n 1 ${HOME}${TMP_PATH}/cfg/trailer)
 30  PREAMBLE=$(head -n 1 ${HOME}${TMP_PATH}/cfg/preamble)
 31  CIPHER_ALGO=$(head -n 1 ${HOME}${TMP_PATH}/cfg/cipher_algo)
 32  ARMOR=$(head -n 1 ${HOME}${TMP_PATH}/cfg/armor)
 33  BAUD=$(head -n 1 ${HOME}${TMP_PATH}/cfg/baud)
 34  SYNCBYTE=$(head -n 1 ${HOME}${TMP_PATH}/cfg/syncbyte)
 35  RETRANSMISSION_TIMEOUT_SEC=$(head -n 1 ${HOME}${TMP_PATH}/cfg/retransmission_timeout_sec)
 36  # convert RETRANSMISSION_TIMEOUT_SEC to ms:
 37  RETRANSMISSION_TIMEOUT_MS=$(echo ${RETRANSMISSION_TIMEOUT_SEC}*1000 | bc)
 38  # and now remove decimal values:
 39  RETRANSMISSION_TIMEOUT_MS=${RETRANSMISSION_TIMEOUT_MS%.*}
 40  TIMEOUT_POLL_SEC=$(head -n 1 ${HOME}${TMP_PATH}/cfg/timeout_poll_sec)
 41  MAX_RETRANSMISSIONS=$(head -n 1 ${HOME}${TMP_PATH}/cfg/max_retransmissions)
 42  REDUNDANT_TRANSMISSIONS=$(head -n 1 ${HOME}${TMP_PATH}/cfg/redundant_transmissions)
 43  NEED_ACK=$(head -n 1 ${HOME}${TMP_PATH}/cfg/need_ack)
 44  VERBOSE=$(head -n 1 ${HOME}${TMP_PATH}/cfg/verbose) # false
 45  SPLIT_TX_LINES=$(head -n 1 ${HOME}${TMP_PATH}/cfg/split_tx_lines)
 46  HALF_DUPLEX=$(head -n 1 ${HOME}${TMP_PATH}/cfg/half_duplex)
 47  MSGFILE="${HOME}${TMP_PATH}/tmp/msgtx.gpg"
 48  TMPFILE="${HOME}${TMP_PATH}/tmp/out.txt"
 49  
 50  # state
 51  #######
 52  SEQ_TX_FILE="${HOME}${TMP_PATH}/state/seq_tx"
 53  SEQ_TX_ACKED_FILE="${HOME}${TMP_PATH}/state/seq_tx_acked"
 54  SEQ_RX_FILE="${HOME}${TMP_PATH}/state/seq_rx"
 55  SESSION_ESTABLISHED_FILE="${HOME}${TMP_PATH}/state/session_established"
 56  INVALID_SEQ_NR=200
 57  SESSION_ESTABLISHED=$(head -n 1 "${SESSION_ESTABLISHED_FILE}")
 58  
 59  # the first argument is the password
 60  PASSWORD="$1"
 61  shift 1
 62  
 63  # further states
 64  ################
 65  # to show the correct initial values on the prompt
 66  SEQ_TX=$(head -n 1 ${SEQ_TX_FILE})
 67  SEQ_TX_ACKED=$(head -n 1 ${SEQ_TX_ACKED_FILE})
 68  SEQ_RX_NEW=$(head -n 1 ${SEQ_RX_FILE})            
 69  if [[ ${SEQ_RX_NEW} != ${INVALID_SEQ_NR} ]] ; then
 70      # clean state and update variable
 71      echo ${INVALID_SEQ_NR} > ${SEQ_RX_FILE}
 72      # SEQ_RX to be acknowledged
 73      SEQ_RX=${SEQ_RX_NEW}
 74  else
 75      SEQ_RX=0 # default is different to 1 which is the first value to be received
 76  fi
 77  seq_tx=$((SEQ_TX+33))
 78  seq_rx=$((SEQ_RX+33))
 79  seq_tx_ascii=$(printf "\x$(printf %x $seq_tx)") 
 80  seq_rx_ascii=$(printf "\x$(printf %x $seq_rx)") 
 81  
 82  # store session input in temporary file
 83  #######################################
 84  echo "$@" > ${TMPFILE};
 85  
 86  # update SEQ_TX
 87  ###############
 88  # we store the increased value later, after it was acknowledged
 89  SEQ_TX=$(((SEQ_TX+1)%94))  
 90  
 91  # split data
 92  ############
 93  if [[ ${SPLIT_TX_LINES} -gt 0 ]] ; then
 94      split -l ${SPLIT_TX_LINES} --numeric-suffixes ${TMPFILE} ${TMPFILE}"_split"
 95  else
 96      mv ${TMPFILE} ${TMPFILE}"_split00"
 97  fi
 98  
 99  # loop to send data-chunks
100  ##########################
101  for f in ${TMPFILE}"_split"*;
102  do           
103      # prepare before send
104      current_retransmissions=0
105      seq_tx=$((SEQ_TX+33))      
106      seq_tx_ascii=$(printf "\x$(printf %x $seq_tx)")   
107                           
108      # retransmission loop
109      #####################
110      # send message, wait ACK, and retransmit when needed up to max. retransmissions
111      while [[ ${current_retransmissions} -ge 0 ]]
112      do
113          # prepare send
114          ##############
115          SEQ_RX_NEW=$(head -n 1 ${SEQ_RX_FILE})            
116          if [[ ${SEQ_RX} != ${INVALID_SEQ_NR} ]] && [[ ${SEQ_RX_NEW} != ${INVALID_SEQ_NR} ]] ; then
117              # clean state and update variable
118              echo ${INVALID_SEQ_NR} > ${SEQ_RX_FILE}
119              # SEQ_RX to be acknowledged in data message
120              SEQ_RX=${SEQ_RX_NEW}
121              seq_rx=$((SEQ_RX+33))
122              seq_rx_ascii=$(printf "\x$(printf %x $seq_rx)") 
123          fi
124             
125          # build and encrypt data-chunk
126          ##############################
127          if [[ ${PREAMBLE} == "" && ${TRAILER} == "" ]] ; then
128              echo "${seq_tx_ascii}${seq_rx_ascii}[data]$(<${f} )" | source gpg.src
129          else
130              echo -n ${PREAMBLE} > ${MSGFILE}
131              echo "${seq_tx_ascii}${seq_rx_ascii}[data]$(<${f} )" | source gpgappend.src
132              if [ "${TRAILER}" != "" ] ; then
133                  echo ${TRAILER} >> ${MSGFILE}
134              fi
135          fi
136          
137          # send message with encrypted data-chunk
138          ########################################
139          if [ "${VERBOSE}" == true ] ; then
140              echo "> data[${SEQ_TX},${SEQ_RX}] try ${current_retransmissions}"
141          fi        
142          # send start_msg?
143          if [ "${START_MSG}" != "" ] ; then
144              echo "${START_MSG}" | source tx.src
145          fi
146          cat ${MSGFILE} | source tx.src
147          # add end_msg?
148          if [ "${END_MSG}" != "" ] ; then
149              echo "${END_MSG}" | source tx.src
150          fi
151          # show session output on local console
152          if [[ ${current_retransmissions} -eq 0 ]] ; then
153              cat ${f} >&1
154          fi
155          # send redundant messages
156          for ((i=1; i<=${REDUNDANT_TRANSMISSIONS}; i++))
157          do
158              if [ "${VERBOSE}" == true ] ; then
159                  echo ">> data[${SEQ_TX},${SEQ_RX}] transmitted redundant message times = ${i}"
160              fi
161              # NOTE: no start_msg needed for redundant messages
162              cat ${MSGFILE} | source tx.src
163              # add end_msg?
164              if [ "${END_MSG}" != "" ] ; then
165                  echo "${END_MSG}" | source tx.src
166              fi  
167          done          
168          start_poll_ms=$(date +%s%3N)            
169                  
170          # loop to poll retransmission timeout
171          #####################################
172          # wait ACK by polling state/seq_tx_acked
173          # in parallel check if need to send ACK
174          while sleep $TIMEOUT_POLL_SEC
175          do                        
176              # received ACK?
177              ###############
178              SEQ_TX_ACKED=$(head -n 1 ${SEQ_TX_ACKED_FILE})
179              now_ms=$(date +%s%3N)
180              elapsed_time_ms=$((now_ms-start_poll_ms))                    
181              if [ "${NEED_ACK}" == "false" ] || [[ ${SEQ_TX_ACKED} == ${SEQ_TX} ]] ; then
182                  # store SEQ_TX after it was acknowledged
183                  echo ${SEQ_TX} > ${SEQ_TX_FILE}
184                  # now increase SEQ_TX for next chunk
185                  SEQ_TX=$(((SEQ_TX+1)%94))
186                  if [ "${VERBOSE}" == true ] && [[ ${SEQ_TX_ACKED} == ${SEQ_TX} ]]; then
187                      total_elapsed_time_ms=$(echo ${current_retransmissions}*${RETRANSMISSION_TIMEOUT_MS}+${elapsed_time_ms} | bc)                      
188                  fi                        
189                  rm ${f}
190                  # signal to exit outer loop
191                  current_retransmissions=-1
192                  # send next chunk
193                  break                                        
194              # retransmit?
195              #############
196              # TODO: subtract TIMEOUT_POLL_SEC (in milliseconds) from RETRANSMISSION_TIMEOUT_MS
197              #       in order to always retransmit "before" RETRANSMISSION_TIMEOUT_MS expires?
198              elif [[ ${elapsed_time_ms} -gt ${RETRANSMISSION_TIMEOUT_MS} ]] ; then                    
199                  # max. retransmission exceeded?
200                  if [[ ${current_retransmissions} -gt ${MAX_RETRANSMISSIONS} ]] ; then
201                      # we exit with an error message
202                      echo "ERROR: maximum nr. of retransmissions (${MAX_RETRANSMISSIONS}) exceeded!"
203                      sleep 5
204                      # some error code between 1 and 255
205                      exit 200
206                      # TODO: check if we can continue here, but making sure that flags and counters remain consistent.
207                      # signal to exit outer loop
208                      # current_retransmissions=-1
209                      # break
210                  fi 
211                  current_retransmissions=$((current_retransmissions+1))
212                  # retransmit
213                  break                       
214              else
215                  : # continue polling if ACK received                            
216              fi      
217              # send ACK?
218        	    ###########
219              if [ "${NEED_ACK}" == "true" ] ; then
220                  SEQ_RX_NEW=$(head -n 1 ${SEQ_RX_FILE})            
221                  if [[ ${SEQ_RX} != ${INVALID_SEQ_NR} ]] && [[ ${SEQ_RX_NEW} != ${INVALID_SEQ_NR} ]] ; then
222                      # clean state
223                      echo ${INVALID_SEQ_NR} > ${SEQ_RX_FILE}
224                      # SEQ_RX to be acknowledged in ACK message
225                      SEQ_RX=${SEQ_RX_NEW}
226                      seq_rx=$((SEQ_RX+33))
227                      seq_rx_ascii=$(printf "\x$(printf %x $seq_rx)")
228                      # send ACK without data
229                      if [[ ${PREAMBLE} == "" && ${TRAILER} == "" ]] ; then
230                          echo "${seq_tx_ascii}${seq_rx_ascii}[ack]" | source gpg.src
231                      else
232                          echo -n ${PREAMBLE} > ${MSGFILE}
233                          echo echo "${seq_tx_ascii}${seq_rx_ascii}[ack]" | source gpgappend.src
234                          if [ "${TRAILER}" != "" ] ; then
235                              echo ${TRAILER} >> ${MSGFILE}
236                          fi
237                      fi
238                      # send message with encrypted data
239                      if [ "${VERBOSE}" == true ] ; then
240                          echo "> ack[${SEQ_TX},${SEQ_RX}]"
241                      fi                  
242                      # send start_msg?
243                      if [ "${START_MSG}" != "" ] ; then
244                          echo "${START_MSG}" | source tx.src
245                      fi
246                      # send ACK
247                      cat ${MSGFILE} | source tx.src
248                      # add end_msg?
249                      if [ "${END_MSG}" != "" ] ; then
250                          echo "${END_MSG}" | source tx.src
251                      fi
252        	        fi
253        	    fi                        
254          done # while poll ACK
255      done # while retransmissions
256  done # while TX data-chunks