📄 xcb+.c
字号:
/* xcb+.c -- CIS B+ Protocol module for XC This file uses 4-character tabstops */#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sys/types.h>#include <sys/stat.h>#include <unistd.h>#include <signal.h>#include <fcntl.h>#include <ctype.h>#define NODEBUG 1 /* prevents xc.h from defining DEBUG */#include "xc.h"#define min(x,y) ((int)(x)<(int)(y)?(x):(y))#define max(x,y) ((int)(x)>(int)(y)?(x):(y))#define MaskLowRange 0x01#define MaskHiRange 0x10#define Send_Ahead_Buffers 5enum { Check_B, Check_CRC } ;enum { Quote_Default, Quote_Not_NULL, Quote_Extended, Quote_Full, Quote_Mask } ;enum { Overwrite, Resume } ;enum { Resume_Allowed, Resume_Not_Allowed, Resume_Failed, Resume_Denied } ;typedef enum { S_Get_DLE, S_DLE_Seen, S_DLE_B_Seen, S_Get_Data, S_Get_check, S_Get_CRC, S_Verify_CRC, S_VErify_CKS, S_VerIfy_Packet, S_Send_NAK, S_SenD_ACK, S_SEnd_ENQ, S_Resend_Packets} Sender_Action;extern short cr_add;extern void cl_line();static char S_Buffer[2064], R_Buffer[2064], tdir[32];char Name[SM_BUFF];static unsigned char Mask[32];static unsigned Checksum;static Ch, /* last char read from remote */ Quoting, /* quoting level requested by the user */ Window_Size, /* Send size of send ahead window */ PackeT_Size, /* Maximum block size. */ R_BUffer_Len, S_Bytes, R_Bytes, Seq_Num, PendinG_Count, Next_Packet, Packets_Btwn_ACKs, Last_ACK, textmode, Last_Chr, Send_Errors, Read_Errors;static short Max_Errors=10, Abort_Flag, Not_Masked, Sent_ENQ, Actual_Check, Valid_To_Resume_Download, ValiD_To_Resume_Upload, Send_FIle_Information, Packet_Received, Result;static FILE *Data_File;static long already_have, data, total_read, total_sent, fsize, carriage_return;static time_t start;static struct { int Seq; int PackeT_Size; char *packet;} Pending[Send_Ahead_Buffers];extern unsigned short crc_xmodem_tab[256];static voidinit_check(){ Checksum=Actual_Check ? 0xffff : 0;}static voiddo_checksum(ch)unsigned ch;{ if (Actual_Check==Check_B){ Checksum<<=1; if (Checksum>255) Checksum=(Checksum&0xFF)+1; Checksum+=ch&0xFF; if (Checksum>255) Checksum=(Checksum&0xFF)+1; } else Checksum=(crc_xmodem_tab[((Checksum>>8)^ch)&0xff]^(Checksum<<8))&0xffff;}/* #define CIS_DEBUG */ /* for B+ logging */#ifdef CIS_DEBUGstatic FILE *bfp = NIL(FILE);static voidxclog(dir, val)char dir;int val;{ static int cnt, lastdir; if (!bfp) bfp=fopen("xc.log","w"), cnt=0, lastdir=dir; if (++cnt>20||lastdir!=dir) fputc('\n',bfp), cnt=1; if (lastdir!=dir) fputc('\n',bfp); if (val>'~'||val<' ') fprintf(bfp,"%c%1x%1x ",dir,val/16,val%16); else fprintf(bfp,"%c%c ",dir,val); lastdir=dir;}static voidWhy_NAK(reason)char *reason;{ sprintf(Msg,"Sending NAK, %s",reason); S0(Msg);}#else#define xclog(dir,val)#define Why_NAK(reason)#endifstatic voidstats(count)int count;{ int rate, minutes, sec, data_percent/*, rate_percent*/; long chars, rem; time_t elapsed, now; data+=count; if (!fsize) data_percent=0; else data_percent=100*(data+carriage_return)/fsize; if (data_percent>100) data_percent=100; now=mtime(); elapsed=now-start; chars=data+carriage_return-already_have-(tdir[0]=='T'?PackeT_Size:0); if (elapsed<1000 || !chars) ttgoto(LI-6,26), fputs("estimating",tfp); else rate=(1000*chars)/elapsed, rem=(fsize-(data+carriage_return-already_have))/rate, minutes=rem/60, sec=rem%60, ttgoto(LI-6,26), fprintf(tfp,"%8.1d:%2.2d",minutes,sec), elapsed/=1000, minutes=elapsed/60, sec=elapsed%60, ttgoto(LI-6,61), fprintf(tfp,"%8.1d:%2.2d",minutes,sec), ttgoto(LI-4,23), fprintf(tfp,"Rate: %d characters per second ", rate); ttgoto(LI-8,0), fprintf(tfp,"%8.1ld",total_sent), ttgoto(LI-8,20), fprintf(tfp,"%8.1ld",total_read), ttgoto(LI-8,40); if (!data_percent) fprintf(tfp,"%8.1ld",data); else fprintf(tfp,"%8.1ld %3.1u %%",data,data_percent); if (carriage_return) ttgoto(LI-8,60), fprintf(tfp,"%+7.1ld",carriage_return);}static voidshowmode(){ int l; sprintf(Msg,"%s %s (%ld bytes) as %s",tdir,Name,fsize, textmode?"ASCII":"BINARY"); ttgoto(LI-12,0); cl_line(); if ((l=strlen(Msg)) < CO) ttgoto(LI-12,(CO-l)/2 -1); fputs(Msg,tfp); start=mtime();}static voidDiscard_ACKed_Packets(){ int i, n; short Packet_Acked=FALSE; Last_ACK=Ch; n=(Next_Packet+PendinG_Count)%Send_Ahead_Buffers; for (i=PendinG_Count;i>0;i--){ n--; if (n<0) n+=5; if (Pending[n].Seq==Ch-'0') Packet_Acked=TRUE, Next_Packet=(n+1)%Send_Ahead_Buffers; if (Packet_Acked==TRUE) free(Pending[n].packet), Pending[n].packet=NIL(char), PendinG_Count--; }}static voidSend_Byte(ch)int ch;{ sendbyte(ch); total_sent++; xclog('>',ch);}static voidSend_Masked_Byte(ch)int ch;{ if (ch<0x20){ if (Quoting==Quote_Full||(Mask[ch]&MaskLowRange)) Send_Byte(DLE), ch+='@'; } else if (ch>=0x80&&ch<0xA0&& (Quoting==Quote_Full||(Mask[ch-0x80]&MaskHiRange))) Send_Byte(DLE), ch=ch+'`'-0x80; Send_Byte(ch);}static intRead_Byte(){ if ((Ch=readbyte(10))== -1) return FAILURE; total_read++; xclog('<',Ch); return SUCCESS;}static intRead_Masked_Byte(){ Not_Masked=TRUE; if (!Read_Byte()) return FAILURE; if (Ch==DLE){ if (!Read_Byte()) return FAILURE; Not_Masked=FALSE; if (Ch>='`') Ch+=0x80; Ch&=0x9F; } return SUCCESS;}static voidSend_ACK(){ Send_Byte(DLE); Send_Byte(Seq_Num+'0');}static voidInit(){ int i; R_BUffer_Len=Window_Size=PendinG_Count=Next_Packet= R_Bytes=S_Bytes=Seq_Num=Packets_Btwn_ACKs=Last_ACK=0; i=mrate(NIL(char)); PackeT_Size=(i>2400) ? 2048 : (i>1200) ? 1024 : 512; Quoting=Quote_Mask; for (i=0;i<Send_Ahead_Buffers;i++) Pending[i].packet=NIL(char); Actual_Check=Check_B; Abort_Flag=Sent_ENQ=FALSE; memset(Mask,0,32); Mask[ETX]=Mask[ENQ]=Mask[DLE]=Mask[NAK]=Mask[XON]=Mask[XOFF]=MaskLowRange; total_sent=total_read=data=fsize=Read_Errors=Send_Errors= already_have=carriage_return=0; fputs("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",tfp); ttgoto(LI-14,25); S1("CIS B-Plus Protocol Transfer"); ttgoto(LI-10,0); fputs("B+ Bytes Sent B+ Bytes Rcvd",tfp); ttgoto(LI-10,40); fputs("Data Bytes Carriage Returns",tfp); ttgoto(LI-6,10); fputs("Time Remaining:",tfp); ttgoto(LI-6,48); fputs("Elapsed Time:",tfp);}static voidXmit_Packet(Size, Seq, Packet)int Size, Seq;unsigned char *Packet;{ register I; init_check(); Send_Byte(DLE); Send_Byte('B'); Send_Byte(Seq+'0'); do_checksum(Seq+'0'); for (I=0;I<Size;I++) Send_Masked_Byte(Packet[I]), do_checksum(Packet[I]); Send_Byte(ETX); do_checksum(ETX); if (Actual_Check==Check_B) Send_Masked_Byte(Checksum); else Send_Masked_Byte(Checksum>>8), Send_Masked_Byte(Checksum&0xff);}static intWait_For_ACK(Have_DLE_B, Acknowledge, Resend)short Have_DLE_B, Acknowledge, Resend;{ Sender_Action Action; int i=0, n, RCV_Num=0, Errors=0; R_BUffer_Len=0; Packet_Received=FALSE; if (Have_DLE_B) Action=S_DLE_B_Seen; else Action=S_Get_DLE; while (Errors<Max_Errors) switch (Action){ case S_Get_Data: if (Read_Masked_Byte()==FAILURE){ Action=S_Send_NAK; Why_NAK("couldn't read next data byte"); } else if (Not_Masked && Ch==ETX) Action=S_Get_check; else if (Not_Masked && Ch==ENQ) Action=S_SenD_ACK; else if (i>PackeT_Size){ Action=S_Send_NAK; Why_NAK("incoming buffer overflow"); } else R_Buffer[i++]=Ch, do_checksum(Ch); break; case S_Get_DLE: if (Packets_Btwn_ACKs>Window_Size+2&&PendinG_Count){ Packets_Btwn_ACKs=0; Action=S_SEnd_ENQ; continue; } if (!Read_Byte()) Action=S_SEnd_ENQ; else if (Ch==DLE) Action=S_DLE_Seen; else if (Ch==NAK) Action=S_SEnd_ENQ; else if (Ch==ENQ) Action=S_SenD_ACK; else if (Ch==ETX){ Action=S_Send_NAK; Why_NAK("awaiting DLE, got ETX"); } break; case S_DLE_Seen: if (!Read_Byte()) Action=S_SEnd_ENQ; else if (Ch>='0'&&Ch<='9') if (Sent_ENQ&&Ch==Last_ACK){ Sent_ENQ=FALSE; if (!PendinG_Count) return SUCCESS; else Action=S_Resend_Packets; } else { Discard_ACKed_Packets(); if (Sent_ENQ) Action=S_Get_DLE; else return SUCCESS; } else if (Ch==';') Action=S_Get_DLE; else if (Ch=='B') Action=S_DLE_B_Seen; else if (Ch==ENQ) Action=S_SenD_ACK; else Action=S_Get_DLE; break; case S_DLE_B_Seen: if (!Read_Byte()){ Action=S_Send_NAK; Why_NAK("no data byte after DLE-B"); } else if (Ch==ENQ) Action=S_SenD_ACK; else { init_check(); RCV_Num=Ch-'0'; do_checksum(Ch); i=0; Action=S_Get_Data; } break; case S_Get_check: do_checksum(ETX); if (Read_Masked_Byte()==FAILURE){ Action=S_Send_NAK; Why_NAK("no incoming checksum"); } else if (Not_Masked&&Ch==ENQ) Action=S_SenD_ACK; else if (Actual_Check==Check_CRC) Action=S_Get_CRC; else Action=S_VErify_CKS; break; case S_Get_CRC: do_checksum(Ch); if (Read_Masked_Byte()==FAILURE){ Action=S_Send_NAK; Why_NAK("no incoming CRC value"); } else if (Not_Masked&&Ch==ENQ) Action=S_SenD_ACK; else Action=S_Verify_CRC; break; case S_Verify_CRC: do_checksum(Ch); if (!Checksum) Action=S_VerIfy_Packet; else { Action=S_Send_NAK; Why_NAK("CRC error"); } break; case S_VErify_CKS: if (Checksum==Ch) Action=S_VerIfy_Packet; else { Action=S_Send_NAK; Why_NAK("Checksum error"); } break; case S_VerIfy_Packet: if (RCV_Num==((Seq_Num+1)%10)||R_Buffer[0]=='F'){ Packets_Btwn_ACKs++; Seq_Num=RCV_Num; if (Acknowledge) Send_ACK(); R_BUffer_Len=i; Packet_Received=TRUE; return FAILURE; } else if (RCV_Num==Seq_Num) Action=S_SenD_ACK; else { Action=S_Send_NAK; Why_NAK("packet out of sequence"); } break; case S_Send_NAK: ttgoto(LI-2,20); sprintf(Msg,"Read Errors: %2.1d",++Read_Errors); S; Errors++; Send_Byte(NAK); Action=S_Get_DLE; break; case S_SenD_ACK: Send_ACK(); Action=S_Get_DLE; break; case S_SEnd_ENQ: ttgoto(LI-2,40); sprintf(Msg,"Send Errors: %2.1d",++Send_Errors); S; Errors++; Sent_ENQ=TRUE; Send_Byte(ENQ); Send_Byte(ENQ); Action=S_Get_DLE; break; case S_Resend_Packets: if (Resend) for (i=0;i<PendinG_Count;i++) n=(Next_Packet+i)%Send_Ahead_Buffers, Xmit_Packet( Pending[n].PackeT_Size, Pending[n].Seq, Pending[n].packet); else return FAILURE; Action=S_Get_DLE; break; } return FAILURE;}static voidSend_Failure(Code, Text)char Code;char *Text;{ int Len, Seq; S_Buffer[0]='F'; S_Buffer[1]=Code; Len=2; while (*Text) S_Buffer[Len++]= *Text++; Seq=(Seq_Num+1)%10; while (PendinG_Count&&Wait_For_ACK(FALSE,FALSE,FALSE)) ; Xmit_Packet(Len,Seq,S_Buffer); do Wait_For_ACK(FALSE,FALSE,FALSE); while (Packet_Received);}static intFlush_Pending(){ while (PendinG_Count) if (!Wait_For_ACK(FALSE,TRUE,TRUE)) return FAILURE; return SUCCESS;}static voidSend_Abort(){ fclose(Data_File); sprintf(Msg,"Transfer abort requested"); S0(Msg); Send_Failure('A',Msg);}static intSend_Packet(Size)int Size;{ int Next, Next_Seq; while ((PendinG_Count>Window_Size)) if (!Wait_For_ACK(FALSE,TRUE,TRUE)){ Send_Abort(); return FAILURE; } Next=(Next_Packet+PendinG_Count)%Send_Ahead_Buffers;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -