📄 tcpip.java
字号:
package tcpip;/*** TcpIp.java: A minimalistic TCP/IP stack (with ICMP).** Copyright Martin Schoeberl.** This software may be used and distributed according to the terms* of the GNU General Public License, incorporated herein by reference.** The author may be reached as martin.schoeberl@chello.at** It's enough to handel a HTTP request (and nothing more)!*** Changelog:* 2002-03-16 works with ethernet* 2002-10-21 use Packet buffer, 4 bytes in one word***/import util.*;public class TcpIp { private static final int PROT_ICMP = 1; private static final int PROT_TCP = 6; static final int FL_URG = 0x20; static final int FL_ACK = 0x10; static final int FL_PSH = 0x8; static final int FL_RST = 0x4; static final int FL_SYN = 0x2; static final int FL_FIN = 0x1; static int ip_id, tcb_port; // ip id, tcp port static int tcb_st; // state static final int ST_LISTEN = 0; static final int ST_ESTAB = 2; static final int ST_FW1 = 3; static final int ST_FW2 = 4; static final int MTU = 1500-8; static final int WINDOW = 2680;/*** calc ip header check sum.* assume (32 bit) word boundries. rest of buffer is 0.* off offset in buffer (in words)* cnt length in bytes*/ // static int chkSum(int[] buf, int off, int cnt) {// for OEBBpublic static int chkSum(int[] buf, int off, int cnt) { int i; int sum = 0; cnt = (cnt+3)>>2; // word count while (cnt != 0) { i = buf[off]; sum += i & 0xffff; sum += i>>>16; ++off; --cnt; } while ((sum>>16) != 0) sum = (sum & 0xffff) + (sum >> 16); sum = (~sum) & 0xffff; return sum; } public static void init() { tcb_st = ST_LISTEN; // select(); ip_id = 0x12340000; Html.init(); }/*** process one ip packet.* change buffer and set length to get a packet sent back.* called from Eth.process().*/ public static void receive(Packet p) { int i, j; int ret = 0; int[] buf = p.buf; int len;/* Dbg.wr('\n'); Dbg.wr('I'); for (i=0; i<(p.len+3)>>2; ++i) { Dbg.hexVal(p.buf[i]); }*/ i = buf[0]; len = i & 0xffff; // len from IP header// NO options are assumed in ICMP/TCP/IP...// => copy it options present if (len > p.len || (i>>>24!=0x45)) { p.len = 0; // packet to short or ip options => drop it return; } else { p.len = len; // correct for to long packets } // TODO check version, header checksum // TODO fragmentation // TODO unique id for sent packet int prot = (buf[2]>>16) & 0xff; // protocol if (prot==PROT_ICMP) { doICMP(p); } else if (prot==PROT_TCP) { doTCP(p); } else if (prot==Udp.PROTOCOL) { Udp.process(p); } else { p.len = 0; } len = p.len; if (len != 0) { buf[0] = 0x45000000 + len; // ip length (header without options) buf[1] = ip_id; // identification, no fragmentation ip_id += 0x10000; // increment id (upper part of word) buf[2] = (0x20<<24) + (prot<<16); // ttl, protocol, clear checksum i = buf[3]; // swap ip addresses buf[3] = buf[4]; buf[4] = i; buf[2] |= chkSum(buf, 0, 20);/* Dbg.wr('\n'); Dbg.wr('i'); for (i=0; i<(p.len+3)>>2; ++i) { Dbg.hexVal(p.buf[i]); } Dbg.wr('\n');*/ } else { p.len = 0; // no response } return; }/*** the famous ping.*/ private static void doICMP(Packet p) {Dbg.wr('P'); if (p.buf[5]>>>16 == 0x0800) { // TODO check checksum p.buf[5] = 0; // echo replay plus clear checksu, p.buf[5] = chkSum(p.buf, 5, p.len-20); // echo replay (0x0000) plus checksum } else { p.len = 0; } }// TODO:!!!!!! do a real state machine,// end is wrong (sending ack in fw1 !!!) makes remote site crazy static void doTCP(Packet p) { int i; int datlen; int[] buf = p.buf; int rcvcnt, sndcnt; int fl;Dbg.wr('T'); // Find the payload i = buf[8]>>>16; int flags = i & 0xff; int hlen = i>>>12; datlen = p.len - 20 - (hlen<<2); // "TCB" // In a full tcp implementation we would keep track of this per connection. // This implementation only handles one connection at a time. // As a result, very little of this state is actually used after // the reply packet has been sent.// if (datlen < 0) return 0; // If it's not http, just drop it i = buf[5]; if ((i & 0xffff) != 80) { p.len = 0; return; } // Get source port tcb_port = i>>>16; rcvcnt = buf[6]; // sequence number sndcnt = buf[7]; // acknowledge number // sndcnt has to be incremented for SYN!!! fl = FL_ACK; p.len = 40; // Figure out what kind of packet this is, and respond if ((flags & FL_SYN) != 0) { // SYN sndcnt = -1; // start with -1 for SYN rcvcnt++; fl |= FL_SYN;// tcb_st = ST_ESTAB; } else if (datlen > 0) { // incoming data rcvcnt += datlen; // TODO get url if (sndcnt==0) { p.len += Html.setText(buf, 5+hlen, datlen, 10); // Send reply packet// if (len > MTU) len = MTU; // TODO MTU should be taken from tcp options // Read next segment of data into buffer } else { fl |= FL_FIN;// tcb_st = ST_FW1; } fl |= FL_PSH; } else if ((flags & FL_FIN) != 0) { // FIN rcvcnt++; // Don't bother with FIN-WAIT-2, TIME-WAIT, or CLOSED; they just cause trouble// tcb_st = ST_LISTEN; } else if ((flags & FL_ACK) != 0) { // ack with no data if (sndcnt > 0) { // calculate no of bytes left to send// i = len2send - sndnxti = 0; if (i == 0) { // EOF; send FIN fl |= FL_FIN;// tcb_st = ST_FW1; } else if (i > 0) { // not EOF; send next segment// len += i; fl |= FL_PSH; } else { // ***** this is never used! thats bad // ack of FIN; no reply p.len = 0; return; } } else { p.len = 0; return; // No reply packet } } else { p.len = 0; return; // drop it } // Fill in TCP header buf[5] = (80<<16) + tcb_port; buf[6] = sndcnt; buf[7] = rcvcnt; buf[8] = 0x50000000 + (fl<<16) + WINDOW; // hlen = 20, no options buf[9] = 0; // clear checksum field buf[2] = (PROT_TCP<<16) + p.len - 20; // set protocol and tcp length in iph checksum for tcp checksum buf[9] = chkSum(buf, 2, p.len-8)<<16; } private static final int IO_STATUS = 1; private static final int IO_UART = 2; private static final int IO_UART2 = 3; private static final int MSK_UA_TDRE = 1; private static final int MSK_UA2_TDRE = 4; static void xxx(int c) { while ((com.jopdesign.sys.Native.rd(IO_STATUS)&MSK_UA_TDRE)==0) ; com.jopdesign.sys.Native.wr(c, IO_UART); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -