⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 scratchp.c

📁 一个功能精简的TCP/IP协议栈
💻 C
📖 第 1 页 / 共 3 页
字号:
/* Scratch Protocol for 'TCP/IP Lean' (c) Iosoft Ltd. 2000

This software is only licensed for distribution with the book 'TCP/IP Lean',
and may only be used for personal experimentation by the purchaser
of that book, on condition that this copyright notice is retained.
For commercial licensing, contact license@iosoft.co.uk

This is experimental software; use it entirely at your own risk. The author
offers no warranties of any kind, including its fitness for purpose. */

/*
** v0.01 JPB 28/10/99
** v0.02 JPB 1/11/99  Removed 'flags' from packet format
** v0.03 JPB 2/11/99  Reintroduced sequencing flags
** v0.04 JPB 3/11/99  Added SLIP support
** v0.05 JPB 4/11/99  Added config-file support
** v0.06 JPB 5/11/99  Revamped packet driver to support multiple classes
** v0.07 JPB 8/1/99   Updated packet format to use command string
** v0.08 JPB 8/1/99   Adapted Tx, Rx so txlen and rxlen include header length
** v0.09 JPB 9/11/99  Added sequencing
** v0.10 JPB 9/11/99  Added data queues
** v0.11 JPB 11/11/99 Improved sequence logic
** v0.12 JPB 12/11/99 Added circular buffer option to packet driver
** v0.13 JPB 15/11/99 Added network Tx and Rx circular buffers
** v0.14 JPB 16/11/99 Improved support for direct-drive of NE2000 card
** v0.15 JPB 16/11/99 Added SCRATCHE for use with DJGPP compiler
** v0.16 JPB 17/11/99 Fixed reentrancy problem on receive
** v0.17 JPB 18/11/99 Removed references to min() and max()
** v0.18 JPB 19/11/99 Completely revamped state machine
** v0.19 JPB 22/11/99 Added timeouts
** v0.20 JPB 23/11/99 Added WIN32 support
** v0.21 JPB 25/11/99 Fixed SLIP interface
** v0.22 JPB 26/11/99 Improved SCRATCHP state-machine
** v0.23 JPB 29/11/99 Added 'dir' command
** v0.24 JPB 30/11/99 Added 'get' and 'put'
** v0.25 JPB 1/12/99  Promoted 'seq' and 'ack' to 32-bit values
** v0.26 JPB 6/12/99  Added 3COM driver
** v0.27 JPB 30/12/99 Improved DJGPP compatibility - removed MAXPATH definition
** v0.28 JPB 6/4/00   Updated to use latest version of net drivers
** v0.29 JPB 13/8/00  Updated copyright notice
*/

#define VERSION "0.29"              /* This software version */

#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <ctype.h>
#include <string.h>

/* Override the default circular buffer size used in TCPFS.H */
#define _CBUFFLEN_ 0x1000           /* Circ buffer size: MUST be power of 2 */

#include "ether.h"
#include "netutil.h"
#include "net.h"
#include "scratchp.h"

#define SCRATCHPVER 1               /* Protocol version number */
#define TESTLEN     SCRATCHPDLEN    /* Max size of 1 block of test data */
#define TESTBUFFLEN (TESTLEN*2)     /* Size of test data buffer */
#define TESTINC     1               /* Increment value for test data */
#define CFGFILE     "tcplean.cfg"   /* Default config filename */
#define NDIAGS      40              /* Number of diagnostic header entries */
#define DIAG_TX     1               /* Identifiers for diagnostic Tx, Rx hdrs */
#define DIAG_RX     2
#define ERRTIME     2               /* Error timeout in sec */
#define RETRIES     2               /* Number of error retries */
#define BLOCKLEN    255             /* Len of file xfer blk (excl. len byte) */
#define FILENAMELEN 40              /* Max length of get/put filename */

char cfgfile[MAXPATH+5]=CFGFILE;    /* Config filename */
BYTE testdata[TESTBUFFLEN];         /* Test data buffer */
LWORD testlen;
int txoff, rxoff;                   /* Tx, Rx offsets into test data */
GENFRAME genframe;                  /* Receive/transmit frame */
long txcount;                       /* Count of Rx bytes */
CBUFF txbuff={_CBUFFLEN_};          /* Circular buffer for transmit */
CBUFF rxbuff={_CBUFFLEN_};          /* Circular buffer for receive */
int statedebug, pktdebug, sigdebug; /* Flags to enable diagnostic printout */
char locid[IDLEN+1];                /* My (local) ident string */
char remid[IDLEN+1];                /* Remote node ident string */
BYTE remaddr[MACLEN];               /* Remote node address */
extern BYTE bcast[MACLEN];          /* Broadcast address */
char netcfg[40];                    /* Network config string */
int connstate;                      /* Network connection state */
int appstate;                       /* Application state */
char *connstates[]={STATENAMES};    /* Strings for connection states */
char *appstates[]={APPNAMES};       /* Diagnostic strings for states */
char *signames[] = {SIGNAMES};
BYTE apptemp[TESTLEN+1];            /* Temporary storage for app. data */
SCRATCHPHDR diaghdrs[NDIAGS];       /* Diagnostic storage of SCRATCHP headers */
int diagidx;                        /* Index into dignostic storage */
char kbuff[81];                     /* Keyboard buffer */
WORD errtimer, errcount;            /* Timer & counter for errors */
char *offon[] = {"off", "on"};      /* Off/on strings */
FILE *fhandle;                      /* File handle for GET and PUT */
char filename[FILENAMELEN+1];       /* File name for GET and PUT */
long filelen;                       /* File length for GET and PUT */
int breakflag;                      /* Flag to indicate ctrl-break pressed */

/* Prototypes */
int get_pkts(GENFRAME *nfp);
void prompt_user(void);
int do_scratchp(GENFRAME *nfp, int rxlen, int signal);
int do_apps(CBUFF *rxb, CBUFF *txb, int sig);
int do_dir(CBUFF *txb);
void newconnstate(int state);
void newappstate(int state);
void disp_sig(int sig);
int make_scratchp(GENFRAME *nfp, BYTE *dest, char *cmd, BYTE flags,
                  void *data, int dlen);
int make_scratchpds(GENFRAME *nfp, BYTE *dest, char *cmd, BYTE flags, char *str);
int put_scratchp(GENFRAME *nfp, WORD txlen);
int is_scratchp(GENFRAME *nfp, int len);
int swap_scratchp(GENFRAME *nfp);
void disp_scratchphdr(SCRATCHPHDR *sph);
void disp_scratchp(GENFRAME *nfp);
void dump_diags(void);
int read_cfg(char *fname);
int mygets(char *buff, int maxlen);

int main(int argc, char *argv[])
{
    char k, cmdkey=0;
    int i, keysig, connsig, sstep=0;
    WORD frametype, txlen=0;
    GENFRAME *nfp;

    printf("SCRATCHP v" VERSION "  ");      /* Sign on */
    if (!read_cfg(argc>1 ? argv[1] : 0))    /* Read config file */
    {
        printf("ERROR: invalid configuration file\n");
        exit(1);
    }
    printf("\n");                           /* Make random test data */
    for (i=0; i<TESTLEN; i++)
        testdata[i] = testdata[i+TESTLEN] = (BYTE)rand()&0xff;
    nfp = &genframe;                        /* Open net driver.. */
    nfp->g.dtype = frametype = open_net(netcfg);    /* ..get frame type */
    if (!frametype)
    {
        printf("ERROR: can't open network driver\n");
        exit(1);
    }
    else
    {
        newappstate(STATE_IDLE);            /* Set default states */
        newconnstate(APP_IDLE);
        timeout(&errtimer, 0);              /* Refresh timeout timer */
        while (!breakflag && cmdkey!='Q')   /* Main command loop.. */
        {
            txlen = keysig = connsig = 0;
            prompt_user();                  /* Prompt user on state change */
            if (sstep || kbhit())           /* If single-step or keypress..*/
            {
                k = getch();                /* ..get key */
                if (sstep)
                    timeout(&errtimer, 0);  /* If single-step, refresh timer */
                cmdkey = toupper(k);        /* Decode keystrokes.. */
                switch (cmdkey)             /* ..and generate signals */
                {
                case 'I':                   /* 'I': broadcast ident */
                    if (connstate != STATE_CONNECTED)
                        printf("Broadcast ident request\n");
                    keysig = SIG_USER_IDENT;
                    break;

                case 'O':                   /* 'O': open connection */
                    printf("Open connection: remote ident (RETURN if any)? ");
                    mygets(remid, IDLEN);
                    if (kbuff[0])
                        printf("Contacting '%s'..\n", remid);
                    else
                        printf("Contacting any node..\n");
                    keysig = SIG_USER_OPEN;
                    break;

                case 'D':                   /* 'D': directory */
                    printf("Directory of remote node\n");
                    if (connstate != STATE_CONNECTED)
                        printf("Error: not connected\n");
                    else
                        keysig = SIG_USER_DIR;
                    break;

                case 'E':                   /* 'E': echo data test */
                    if (connstate != STATE_CONNECTED)
                        printf("Error: not connected\n");
                    else
                    {
                        printf("Echo test\n");
                        keysig = SIG_USER_ECHO;
                    }
                    break;

                case 'G':                   /* 'G': get file from rmeote */
                    if (connstate != STATE_CONNECTED)
                        printf("Error: not connected\n");
                    else
                    {
                        printf("Filename to get? ");
                        if (mygets(filename, FILENAMELEN))
                            keysig = SIG_USER_GET;
                    }
                    break;

                case 'P':                   /* 'P': put file into remote */
                    if (connstate != STATE_CONNECTED)
                        printf("Error: not connected\n");
                    else
                    {
                        printf("Filename to put? ");
                        if (mygets(filename, FILENAMELEN))
                            keysig = SIG_USER_PUT;
                    }
                    break;

                case 'C':                   /* 'C': close connection */
                    printf("Closing connection..\n");
                    keysig = SIG_USER_CLOSE;
                    break;

                case 'S':                   /* 'S': single-step */
                    sstep = !sstep;
                    printf("Single-step %s\n", sstep ? "on" : "off");
                    break;

                case '?':                   /* '?': dump dignostic log */
                    printf("\n");
                    dump_diags();
                    break;
                }
            }                               /* Feed kbd signal to application */
            connsig = do_apps(&rxbuff, &txbuff, keysig);
            if (!connsig && connstate!=STATE_IDLE &&
                timeout(&errtimer, ERRTIME))/* If idle and timeout.. */
            {                               /* ..check error counter.. */
                if (errcount++ < RETRIES)
                    connsig = do_apps(&rxbuff, &txbuff, SIG_TIMEOUT);
                else                        /* ..signal 'timeout' or 'fail' */
                    connsig = do_apps(&rxbuff, &txbuff, SIG_FAIL);
            }                               /* Keep SCRATCHP alive */
            txlen = do_scratchp(nfp, 0, connsig);
            put_scratchp(nfp, txlen);       /* Transmit packet (if any) */
            txlen = get_pkts(nfp);          /* Check receive packets */
            put_scratchp(nfp, txlen);       /* Transmit response (if any) */
            poll_net(nfp->g.dtype);         /* Keep net drivers alive */
        }
        if (connstate)                      /* Shutdown: still connected? */
        {
            printf("Closing connection..");
            while (get_pkts(nfp))           /* Discard all receive packets.. */
                putchar(',');               /* ..then send 'stop' ..*/
            txlen = make_scratchp(nfp, remaddr, 0, FLAG_STOP, 0, 0);
            put_scratchp(nfp, txlen);
            while (get_pkts(nfp))           /* ..then discard any more.. */
                putchar('.');               /* (to ensure Tx buffer flushed) */
            putchar('\n');
            poll_net(nfp->g.dtype);         /* Keep net drivers alive */
        }
    }
    close_net(frametype);                   /* Close network drver */
    return(0);
}

/* Demultiplex incoming packets */
int get_pkts(GENFRAME *nfp)
{
    int rxlen, txlen=0;

    if ((rxlen=get_frame(nfp)) > 0)         /* If any packet received.. */
    {
        if (is_scratchp(nfp, rxlen))        /* If SCRATCHP.. */
        {
            swap_scratchp(nfp);                 /* ..do byte-swaps.. */
            txlen = do_scratchp(nfp, rxlen, 0); /* ..action it.. */
        }
    }                                       /* ..and maybe return a response */
    return(txlen);                          /* (using the same pkt buffer) */
}

/* Prompt user depending on connection & application states, & kbd signal */
void prompt_user(void)
{
    static int lastappstate=0, lastconnstate=-1;
    static long lastfilelen=0;

    if (lastfilelen != filelen)
        printf("%lu bytes     \r", filelen);
    lastfilelen = filelen;
    if (appstate != lastappstate)
    {
        if (appstate == APP_FILE_RECEIVER)
            printf("Receiving '%s'..\n", filename);
        if (appstate == APP_FILE_SENDER)
            printf("Sending '%s'..\n", filename);
        else if (lastappstate==APP_FILE_SENDER ||
                 lastappstate==APP_FILE_RECEIVER)
        {
            if (!filelen)
                printf("ERROR: file not found\n");
            else
                printf("%lu bytes transferred\n", filelen);
        }
        if (appstate == APP_ECHO_SERVER)
            printf("Echo server running... [C]lose connection?\n");
        else if (appstate == APP_ECHO_CLIENT)
            printf("Echo client running... [C]lose connection?\n");
        lastappstate = appstate;
    }
    else if (connstate != lastconnstate)
    {
        if (connstate == STATE_IDLE)
            printf("Connection closed: [I]dent, [O]pen, [Q]uit?\n");
        if (connstate == STATE_CONNECTED)
        {
            printf("Connected");
            if (*remid)
                printf(" to '%s'", remid);
            printf(": [D]ir [G]et [P]ut [E]cho [C]lose?\n");
        }
        lastconnstate = connstate;
    }
}

/* SCRATCHP connection state machine; given packet buffer and Rx len
** If Rx len is non-zero, process the incoming SCRATCHP packet,
** Otherwise, only check for state chamges or timeouts,
** Return non-zero packet length (incl. SCRATCHP hdr) if responding */
int do_scratchp(GENFRAME *nfp, int rxlen, int sig)
{
    WORD n, trylen, tx=0, txlen=0, crlen=0, dlen=0, txw;
    LWORD oldrx, rxw, acked=0;
    static LWORD txack;
    char *errstr=0, temps[22];

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -