/ 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