mirror of
https://github.com/dschmenk/PLASMA.git
synced 2025-01-08 22:30:48 +00:00
Very preliminary HTTP server
This commit is contained in:
parent
175898913c
commit
9686ef8ca6
@ -7,9 +7,24 @@ import cmdsys
|
||||
predef heapmark, heapallocalign, heapalloc, heaprelease
|
||||
byte MACHID
|
||||
end
|
||||
//
|
||||
// Net object
|
||||
//
|
||||
import inet
|
||||
predef swab, sendUDP, openUDP, closeUDP, serviceIP
|
||||
predef setInterfaceIP, getInterfaceHA
|
||||
word iNet
|
||||
end
|
||||
struc t_inet
|
||||
word initIP
|
||||
word serviceIP
|
||||
word openUDP
|
||||
word sendUDP
|
||||
word closeUDP
|
||||
word listenTCP
|
||||
word connectTCP
|
||||
word sendTCP
|
||||
word closeTCP
|
||||
word setInterfaceIP
|
||||
word getInterfaceHA
|
||||
end
|
||||
//
|
||||
// Needed to init subnet
|
||||
@ -178,7 +193,7 @@ def recvDHCP(remip, remport, pkt, len, param)
|
||||
memcpy(@optsDHCP.5, @pkt->dhcp_yourip, 4)
|
||||
memcpy(@optsDHCP.11, @pkt->dhcp_serverip, 4)
|
||||
memcpy(@DHCP.dhcp_serverip, @pkt->dhcp_serverip, 4)
|
||||
sendUDP(portDHCP, 0, DHCP_SERVER_PORT, @DHCP, t_dhcp)
|
||||
iNet:sendUDP(portDHCP, 0, DHCP_SERVER_PORT, @DHCP, t_dhcp)
|
||||
break
|
||||
is DHCP_ACK
|
||||
stateDHCP = DHCP_ACK
|
||||
@ -204,15 +219,15 @@ end
|
||||
//
|
||||
// Get the local hardware address into the DHCP packet
|
||||
//
|
||||
getInterfaceHA(@DHCP.dhcp_clientha)
|
||||
iNet:getInterfaceHA(@DHCP.dhcp_clientha)
|
||||
//
|
||||
// Clear our local IP address
|
||||
//
|
||||
setInterfaceIP(@zeros,@ones, @zeros)
|
||||
iNet:setInterfaceIP(@zeros,@ones, @zeros)
|
||||
//
|
||||
// Prepare to receive DHCP packets from a server
|
||||
//
|
||||
portDHCP = openUDP(DHCP_CLIENT_PORT, @recvDHCP, 0)
|
||||
portDHCP = iNet:openUDP(DHCP_CLIENT_PORT, @recvDHCP, 0)
|
||||
//
|
||||
// Service IP
|
||||
//
|
||||
@ -220,24 +235,17 @@ while retry < 3 and stateDHCP <> DHCP_ACK
|
||||
//
|
||||
// Broadcast DHCP DISCOVER message
|
||||
//
|
||||
sendUDP(portDHCP, 0, DHCP_SERVER_PORT, @DHCP, t_dhcp)
|
||||
iNet:sendUDP(portDHCP, 0, DHCP_SERVER_PORT, @DHCP, t_dhcp)
|
||||
for timeout = 1 to 1000
|
||||
serviceIP
|
||||
iNet:serviceIP()
|
||||
if stateDHCP == DHCP_ACK
|
||||
break
|
||||
fin
|
||||
next
|
||||
retry = retry + 1
|
||||
loop
|
||||
closeUDP(portDHCP)
|
||||
setInterfaceIP(@localip, @localnet, @localgw)
|
||||
iNet:closeUDP(portDHCP)
|
||||
iNet:setInterfaceIP(@localip, @localnet, @localgw)
|
||||
puts(@boundstr);putip(@localip);putc('/');putip(@localnet);putln
|
||||
//
|
||||
// Service IP
|
||||
//
|
||||
repeat
|
||||
serviceIP
|
||||
until ^$C000 > 127
|
||||
^$C010
|
||||
|
||||
done
|
@ -4,16 +4,35 @@ import cmdsys
|
||||
predef memset, memcpy, modaddr, modexec
|
||||
predef heapmark, heapallocalign, heapalloc, heaprelease, heapavail
|
||||
byte MACHID
|
||||
//
|
||||
// Module don't free memory
|
||||
//
|
||||
const modkeep = $2000
|
||||
const modinitkeep = $4000
|
||||
end
|
||||
//
|
||||
// Module don't free memory
|
||||
// Net object
|
||||
//
|
||||
const modkeep = $2000
|
||||
const modinitkeep = $4000
|
||||
import inet
|
||||
word iNet
|
||||
end
|
||||
struc t_inet
|
||||
word initIP
|
||||
word serviceIP
|
||||
word openUDP
|
||||
word sendUDP
|
||||
word closeUDP
|
||||
word listenTCP
|
||||
word connectTCP
|
||||
word sendTCP
|
||||
word closeTCP
|
||||
word setInterfaceIP
|
||||
word getInterfaceHA
|
||||
end
|
||||
//
|
||||
// Predefine service routine
|
||||
//
|
||||
predef serviceIP
|
||||
predef etherServiceIP
|
||||
//
|
||||
// Segment list element
|
||||
//
|
||||
@ -183,7 +202,7 @@ end
|
||||
//
|
||||
// Swap bytes in word
|
||||
//
|
||||
export asm swab
|
||||
asm swab
|
||||
LDA ESTKL,X
|
||||
LDY ESTKH,X
|
||||
STA ESTKH,X
|
||||
@ -194,7 +213,7 @@ end
|
||||
// 1'S COMPLIMENT SUM BE format
|
||||
// sum1(PREVSUM, BUF, LEN)
|
||||
//
|
||||
export asm sum1
|
||||
asm sum1
|
||||
LDY #$00
|
||||
LDA ESTKL+1,X
|
||||
STA SRCL
|
||||
@ -242,7 +261,7 @@ end
|
||||
//
|
||||
// Send IP datagram
|
||||
//
|
||||
export def sendIP(ipdst, proto, seglist, size)
|
||||
def etherSendIP(ipdst, proto, seglist, size)
|
||||
byte[t_iphdr] hdr
|
||||
byte retry
|
||||
word timeout
|
||||
@ -275,7 +294,7 @@ export def sendIP(ipdst, proto, seglist, size)
|
||||
setFrameLen(t_earp)
|
||||
writeFrame(@eFrame, t_earp)
|
||||
for timeout = 1000 downto 0
|
||||
serviceIP
|
||||
etherServiceIP
|
||||
if remoteha:0 | remoteha:2 | remoteha:4
|
||||
break
|
||||
fin
|
||||
@ -312,7 +331,7 @@ end
|
||||
//
|
||||
// Send UDP datagram
|
||||
//
|
||||
export def sendUDP(port, ipdst, portdst, data, len)
|
||||
def etherSendUDP(port, ipdst, portdst, data, len)
|
||||
word[8] seglist // list of data and header segments
|
||||
byte[t_udphdr] hdr
|
||||
|
||||
@ -324,12 +343,12 @@ export def sendUDP(port, ipdst, portdst, data, len)
|
||||
seglist:0:seg_len = t_udphdr
|
||||
seglist:4:seg_buf = data
|
||||
seglist:4:seg_len = len
|
||||
return sendIP(ipdst, IP_PROTO_UDP, @seglist, t_udphdr + len)
|
||||
return etherSendIP(ipdst, IP_PROTO_UDP, @seglist, t_udphdr + len)
|
||||
end
|
||||
//
|
||||
// Notify on UDP datagram received
|
||||
//
|
||||
export def openUDP(localport, callback, param)
|
||||
def etherOpenUDP(localport, callback, param)
|
||||
word port
|
||||
byte i
|
||||
|
||||
@ -363,7 +382,7 @@ end
|
||||
//
|
||||
// Clear notify on UDP port
|
||||
//
|
||||
export def closeUDP(port)
|
||||
def etherCloseUDP(port)
|
||||
word port
|
||||
byte i
|
||||
|
||||
@ -382,9 +401,29 @@ export def closeUDP(port)
|
||||
return -1
|
||||
end
|
||||
//
|
||||
// Open TCP socket in SERVER mode
|
||||
//
|
||||
def etherListenTCP(lclport, callback, param)
|
||||
end
|
||||
//
|
||||
// Open TCP socket in CLIENT mode
|
||||
//
|
||||
def etherConnectTCP(remip, remport, lclport, callback, param)
|
||||
end
|
||||
//
|
||||
// Write to TCP socket
|
||||
//
|
||||
def etherSendTCP(wiz, data, len)
|
||||
end
|
||||
//
|
||||
// Close TCP socket
|
||||
//
|
||||
def etherCloseTCP(wiz)
|
||||
end
|
||||
//
|
||||
// Service incoming packets
|
||||
//
|
||||
export def serviceIP
|
||||
def etherServiceIP
|
||||
word rxsize, rxpacket, rxptr
|
||||
word iphdr, opt, optlen, port, lclport, remport
|
||||
byte i, echolen
|
||||
@ -470,7 +509,7 @@ export def serviceIP
|
||||
echo_reply:icmp_chksm = 0
|
||||
seglist:seg_buf = @echo_reply
|
||||
seglist:seg_len = echolen
|
||||
sendIP(@iphdr=>ip_src, IP_PROTO_ICMP, @seglist, echolen)
|
||||
etherSendIP(@iphdr=>ip_src, IP_PROTO_ICMP, @seglist, echolen)
|
||||
fin
|
||||
if hookICMP
|
||||
hookICMP(@iphdr=>ip_src, rxptr, rxsize)
|
||||
@ -516,7 +555,7 @@ end
|
||||
//
|
||||
// Set the local IP addresses
|
||||
//
|
||||
export def setInterfaceIP(newIP, newSubnet, newGateway)
|
||||
def setEtherIP(newIP, newSubnet, newGateway)
|
||||
if newIP; memcpy(@localip, newIP, IP4ADR_SIZE); fin
|
||||
if newSubnet; memcpy(@subnet, newSubnet, IP4ADR_SIZE); fin
|
||||
if newGateway; memcpy(@gateway, newGateway, IP4ADR_SIZE); fin
|
||||
@ -524,9 +563,22 @@ end
|
||||
//
|
||||
// Get the interface hardware address
|
||||
//
|
||||
export def getInterfaceHA(ha)
|
||||
def getEtherHA(ha)
|
||||
if ha; memcpy(ha, @myMAC, MAC_SIZE); fin
|
||||
return MAC_SIZE
|
||||
end
|
||||
|
||||
//
|
||||
// Fill in Net class
|
||||
//
|
||||
iNet:serviceIP = @etherServiceIP
|
||||
iNet:openUDP = @etherOpenUDP
|
||||
iNet:sendUDP = @etherSendUDP
|
||||
iNet:closeUDP = @etherCloseUDP
|
||||
iNet:listenTCP = @etherListenTCP
|
||||
iNet:connectTCP = @etherConnectTCP
|
||||
iNet:sendTCP = @etherSendTCP
|
||||
iNet:closeTCP = @etherCloseTCP
|
||||
iNet:setInterfaceIP = @setEtherIP
|
||||
iNet:getInterfaceHA = @getEtherHA
|
||||
done
|
||||
|
@ -5,6 +5,31 @@ import cmdsys
|
||||
byte MACHID
|
||||
end
|
||||
//
|
||||
// Module don't free memory
|
||||
//
|
||||
const modkeep = $2000
|
||||
const modinitkeep = $4000
|
||||
//
|
||||
// Net object
|
||||
//
|
||||
struc t_inet
|
||||
word initIP
|
||||
word serviceIP
|
||||
word openUDP
|
||||
word sendUDP
|
||||
word closeUDP
|
||||
word listenTCP
|
||||
word connectTCP
|
||||
word sendTCP
|
||||
word closeTCP
|
||||
word setInterfaceIP
|
||||
word getInterfaceHA
|
||||
end
|
||||
//
|
||||
// External interface to net class. Must be first.
|
||||
//
|
||||
export byte[t_inet] iNet
|
||||
//
|
||||
// List of loadable network device drivers
|
||||
//
|
||||
byte netDrivers = "WIZNET"
|
||||
@ -15,22 +40,28 @@ word driver = @netDrivers
|
||||
// DHCP module to load
|
||||
//
|
||||
byte dhcp = "DHCP"
|
||||
//
|
||||
// Look for net hardware
|
||||
//
|
||||
while ^driver
|
||||
puts(driver);putln
|
||||
if modexec(driver) >= 0
|
||||
break
|
||||
|
||||
export def iNetInit
|
||||
//
|
||||
// Look for net hardware
|
||||
//
|
||||
while ^driver
|
||||
//puts(driver);putln
|
||||
if modexec(driver) >= 0
|
||||
break
|
||||
fin
|
||||
driver = driver + ^driver + 1
|
||||
loop
|
||||
if !^driver
|
||||
return 0
|
||||
fin
|
||||
driver = driver + ^driver + 1
|
||||
loop
|
||||
if !^driver
|
||||
return -1
|
||||
fin
|
||||
//
|
||||
// Get an IP address
|
||||
//
|
||||
modexec(@dhcp)
|
||||
//
|
||||
// Get an IP address
|
||||
//
|
||||
modexec(@dhcp)
|
||||
return @iNet
|
||||
end
|
||||
|
||||
iNet:initIP = @iNetInit
|
||||
|
||||
done
|
@ -12,6 +12,25 @@ import cmdsys
|
||||
byte MACHID
|
||||
end
|
||||
//
|
||||
// Net object
|
||||
//
|
||||
import inet
|
||||
word iNet
|
||||
end
|
||||
struc t_inet
|
||||
word initIP
|
||||
word serviceIP
|
||||
word openUDP
|
||||
word sendUDP
|
||||
word closeUDP
|
||||
word listenTCP
|
||||
word connectTCP
|
||||
word sendTCP
|
||||
word closeTCP
|
||||
word setInterfaceIP
|
||||
word getInterfaceHA
|
||||
end
|
||||
//
|
||||
// Module don't free memory
|
||||
//
|
||||
const modkeep = $2000
|
||||
@ -96,7 +115,7 @@ byte[4] gateway
|
||||
//
|
||||
// Predefine service routine
|
||||
//
|
||||
predef serviceIP
|
||||
predef wizServiceIP
|
||||
//
|
||||
// Segment list element
|
||||
//
|
||||
@ -190,18 +209,35 @@ end
|
||||
//
|
||||
const MAX_WIZ_CHANNELS = 4
|
||||
//
|
||||
// Channel protocols
|
||||
//
|
||||
const WIZ_PROTO_CLOSED = 0
|
||||
const WIZ_PROTO_TCP = 1
|
||||
const WIZ_PROTO_UDP = 2
|
||||
const WIZ_PROTO_IP = 3
|
||||
const WIZ_PROTO_RAW = 4
|
||||
//
|
||||
// State transistions
|
||||
//
|
||||
const TCP_STATE_CLOSED = 0
|
||||
const TCP_STATE_CLOSING = 1
|
||||
const TCP_STATE_LISTEN = 2
|
||||
const TCP_STATE_CONNECT = 3
|
||||
const TCP_STATE_OPEN = 4
|
||||
//
|
||||
// HW channels
|
||||
//
|
||||
struc t_channel
|
||||
byte channel_proto
|
||||
word channel_regs
|
||||
word channel_txmem
|
||||
word channel_rxmem
|
||||
word channel_lclport
|
||||
word channel_remport
|
||||
word channel_remip
|
||||
word channel_recv_func
|
||||
word channel_recv_parm
|
||||
byte channel_proto
|
||||
byte channel_state
|
||||
word channel_regs
|
||||
word channel_txmem
|
||||
word channel_rxmem
|
||||
word channel_lclport
|
||||
word channel_remport
|
||||
byte[4] channel_remip
|
||||
word channel_recv_func
|
||||
word channel_recv_parm
|
||||
end
|
||||
byte[t_channel * MAX_WIZ_CHANNELS] wizChannel
|
||||
//
|
||||
@ -217,7 +253,7 @@ end
|
||||
//
|
||||
// Swap bytes in word
|
||||
//
|
||||
export asm swab
|
||||
asm swab
|
||||
LDA ESTKL,X
|
||||
LDY ESTKH,X
|
||||
STA ESTKH,X
|
||||
@ -225,55 +261,6 @@ export asm swab
|
||||
RTS
|
||||
end
|
||||
//
|
||||
// 1'S COMPLIMENT SUM BE format
|
||||
// sum1(PREVSUM, BUF, LEN)
|
||||
//
|
||||
export asm sum1
|
||||
LDY #$00
|
||||
LDA ESTKL+1,X
|
||||
STA SRCL
|
||||
LDA ESTKH+1,X
|
||||
STA SRCH
|
||||
LSR ESTKH,X ; CONVERT BYTE LEN TO WORD LEN
|
||||
LDA ESTKL,X
|
||||
ROR
|
||||
ADC #$00
|
||||
STA ESTKL,X
|
||||
BEQ +
|
||||
INC ESTKH,X
|
||||
BCC CHKLP
|
||||
INC ESTKH,X
|
||||
CLC
|
||||
CHKLP LDA (SRC),Y
|
||||
PHA
|
||||
INY
|
||||
BNE +
|
||||
INC SRCH
|
||||
+ LDA (SRC),Y
|
||||
ADC ESTKH+2,X
|
||||
STA ESTKH+2,X
|
||||
PLA
|
||||
ADC ESTKL+2,X
|
||||
STA ESTKL+2,X
|
||||
INY
|
||||
BNE +
|
||||
INC SRCH
|
||||
+ DEC ESTKL,X
|
||||
BNE CHKLP
|
||||
DEC ESTKH,X
|
||||
BNE CHKLP
|
||||
- LDA #$00
|
||||
ADC ESTKH+2,X
|
||||
STA ESTKH+2,X
|
||||
LDA #$00
|
||||
ADC ESTKL+2,X
|
||||
STA ESTKL+2,X
|
||||
BCS -
|
||||
INX
|
||||
INX
|
||||
RTS
|
||||
end
|
||||
//
|
||||
// Wiznet I/O functions
|
||||
//
|
||||
// POKE WORD TO I/O SPACE
|
||||
@ -440,6 +427,7 @@ def peekregw(reg)
|
||||
|
||||
_pokeiow(reg)
|
||||
dataw.1 = _peekio()
|
||||
_pokeiow(reg + 1)
|
||||
dataw.0 = _peekio()
|
||||
return dataw
|
||||
end
|
||||
@ -475,7 +463,7 @@ end
|
||||
//
|
||||
// Send UDP datagram
|
||||
//
|
||||
export def sendUDP(wiz, ipdst, portdst, data, len)
|
||||
def wizSendUDP(wiz, ipdst, portdst, data, len)
|
||||
word wizregs, wizdata, txrr, txwr, splitlen
|
||||
|
||||
wizregs = wiz=>channel_regs
|
||||
@ -512,7 +500,7 @@ end
|
||||
//
|
||||
// Open UDP channel and set datagram received callback
|
||||
//
|
||||
export def openUDP(localport, callback, param)
|
||||
def wizOpenUDP(localport, callback, param)
|
||||
word wiz
|
||||
byte i
|
||||
|
||||
@ -520,6 +508,7 @@ export def openUDP(localport, callback, param)
|
||||
//
|
||||
// Look for an existing notification on localport
|
||||
//
|
||||
putc('O')
|
||||
wiz = @wizChannel
|
||||
for i = 1 to MAX_WIZ_CHANNELS
|
||||
if wiz->channel_proto == IP_PROTO_UDP and wiz=>channel_lclport == localport
|
||||
@ -542,10 +531,11 @@ export def openUDP(localport, callback, param)
|
||||
return 0
|
||||
fin
|
||||
fin
|
||||
putc('0' + i);putln
|
||||
//
|
||||
// Fill in this channel and open it
|
||||
//
|
||||
wiz->channel_proto = IP_PROTO_UDP
|
||||
wiz->channel_proto = WIZ_PROTO_UDP
|
||||
wiz=>channel_lclport = localport
|
||||
wiz=>channel_recv_func = callback
|
||||
wiz=>channel_recv_parm = param
|
||||
@ -557,14 +547,170 @@ end
|
||||
//
|
||||
// Close UDP port
|
||||
//
|
||||
export def closeUDP(wiz)
|
||||
if isuge(wiz, wizChannel) and isult(wiz, wizChannel + MAX_WIZ_CHANNELS * t_channel)
|
||||
def wizCloseUDP(wiz)
|
||||
putc('S')
|
||||
if isuge(wiz, @wizChannel) and isult(wiz, @wizChannel + MAX_WIZ_CHANNELS * t_channel)
|
||||
//
|
||||
// Clear notiications on this port
|
||||
//
|
||||
if wiz->channel_proto == IP_PROTO_UDP
|
||||
wiz->channel_proto = 0
|
||||
pokereg(wiz=>channel_regs + WIZ_SnCR, $00) // CLOSE
|
||||
if wiz->channel_proto == WIZ_PROTO_UDP
|
||||
putc('1' + ((wiz=>channel_regs - WIZ_SREGS) >> 8));putln
|
||||
wiz->channel_proto = WIZ_PROTO_CLOSED
|
||||
pokereg(wiz=>channel_regs + WIZ_SnCR, $10) // CLOSE
|
||||
return 0
|
||||
fin
|
||||
fin
|
||||
putc('!');putln
|
||||
//
|
||||
// Invalid port
|
||||
//
|
||||
return -1
|
||||
end
|
||||
//
|
||||
// Open TCP socket in SERVER mode
|
||||
//
|
||||
def wizListenTCP(lclport, callback, param)
|
||||
word wiz
|
||||
byte i
|
||||
|
||||
//
|
||||
// Look for an existing notification on localport
|
||||
//
|
||||
putc('L')
|
||||
wiz = @wizChannel
|
||||
for i = 1 to MAX_WIZ_CHANNELS
|
||||
if wiz->channel_proto == WIZ_PROTO_TCP and wiz->channel_state == TCP_STATE_LISTEN and wiz=>channel_lclport == lclport
|
||||
break
|
||||
fin
|
||||
wiz = wiz + t_channel
|
||||
next
|
||||
if i > MAX_WIZ_CHANNELS
|
||||
//
|
||||
// Add notification on localport if room
|
||||
//
|
||||
wiz = @wizChannel
|
||||
for i = 1 to MAX_WIZ_CHANNELS
|
||||
if !wiz->channel_proto
|
||||
break
|
||||
fin
|
||||
wiz = wiz + t_channel
|
||||
next
|
||||
if i > MAX_WIZ_CHANNELS
|
||||
return 0
|
||||
fin
|
||||
fin
|
||||
putc('0' + i);putln
|
||||
//
|
||||
// Fill in this channel and open it
|
||||
//
|
||||
wiz->channel_proto = WIZ_PROTO_TCP
|
||||
wiz->channel_state = TCP_STATE_LISTEN
|
||||
wiz=>channel_remip:0 = 0
|
||||
wiz=>channel_remip:2 = 0
|
||||
wiz=>channel_remport = 0
|
||||
wiz=>channel_lclport = lclport
|
||||
wiz=>channel_recv_func = callback
|
||||
wiz=>channel_recv_parm = param
|
||||
pokeregw(wiz=>channel_regs + WIZ_SnPORT, lclport)
|
||||
pokereg(wiz=>channel_regs + WIZ_SnMR, $01) // TCP protocol
|
||||
pokereg(wiz=>channel_regs + WIZ_SnCR, $02) // LISTEN
|
||||
return wiz
|
||||
end
|
||||
//
|
||||
// Open TCP socket in CLIENT mode
|
||||
//
|
||||
def wizConnectTCP(remip, remport, lclport, callback, param)
|
||||
word wiz
|
||||
byte i
|
||||
|
||||
//
|
||||
// Look for an existing notification on localport
|
||||
//
|
||||
wiz = @wizChannel
|
||||
for i = 1 to MAX_WIZ_CHANNELS
|
||||
if wiz->channel_proto == WIZ_PROTO_TCP and wiz->channel_state == TCP_STATE_CONNECT and wiz=>channel_lclport == lclport
|
||||
break
|
||||
fin
|
||||
wiz = wiz + t_channel
|
||||
next
|
||||
if i > MAX_WIZ_CHANNELS
|
||||
//
|
||||
// Add notification on localport if room
|
||||
//
|
||||
wiz = @wizChannel
|
||||
for i = 1 to MAX_WIZ_CHANNELS
|
||||
if !wiz->channel_proto
|
||||
break
|
||||
fin
|
||||
wiz = wiz + t_channel
|
||||
next
|
||||
if i > MAX_WIZ_CHANNELS
|
||||
return 0
|
||||
fin
|
||||
fin
|
||||
//
|
||||
// Fill in this channel and open it
|
||||
//
|
||||
wiz->channel_proto = WIZ_PROTO_TCP
|
||||
wiz->channel_state = TCP_STATE_CONNECT
|
||||
wiz=>channel_remip:0 = remip=>0
|
||||
wiz=>channel_remip:2 = remip=>2
|
||||
wiz=>channel_remport = remport
|
||||
wiz=>channel_lclport = lclport
|
||||
wiz=>channel_recv_func = callback
|
||||
wiz=>channel_recv_parm = param
|
||||
pokeregs(wiz=>channel_regs + WIZ_SnDIPR, remip, IP4ADR_SIZE)
|
||||
pokeregw(wiz=>channel_regs + WIZ_SnDPORT, remport)
|
||||
pokeregw(wiz=>channel_regs + WIZ_SnPORT, lclport)
|
||||
pokereg(wiz=>channel_regs + WIZ_SnMR, $01) // TCP protocol
|
||||
pokereg(wiz=>channel_regs + WIZ_SnCR, $04) // CONNECT
|
||||
return wiz
|
||||
end
|
||||
//
|
||||
// Write to TCP socket
|
||||
//
|
||||
def wizSendTCP(wiz, data, len)
|
||||
word wizregs, wizdata, txrr, txwr, splitlen
|
||||
|
||||
if wiz->channel_state <> TCP_STATE_OPEN; return -1; fin
|
||||
wizregs = wiz=>channel_regs
|
||||
wizdata = wiz=>channel_txmem
|
||||
//
|
||||
// Wait for Tx room
|
||||
//
|
||||
repeat
|
||||
txrr = peekregw(wizregs + WIZ_SnTXRD)
|
||||
txwr = peekregw(wizregs + WIZ_SnTXWR)
|
||||
until txrr == txwr
|
||||
//
|
||||
// Calc new write ptr, check for split
|
||||
//
|
||||
txwr = txrr + len
|
||||
if txwr >= WIZ_TXSIZE
|
||||
splitlen = WIZ_TXSIZE - txrr
|
||||
pokeregs(wizdata + txrr, data, splitlen)
|
||||
pokeregs(wizdata, data + splitlen, len - splitlen)
|
||||
else
|
||||
pokeregs(wizdata + txrr, data, len)
|
||||
fin
|
||||
pokeregw(wizregs + WIZ_SnTXWR, txwr)
|
||||
pokereg(wizregs + WIZ_SnCR, $20) // SEND
|
||||
end
|
||||
//
|
||||
// Close TCP socket
|
||||
//
|
||||
def wizCloseTCP(wiz)
|
||||
if isuge(wiz, @wizChannel) and isult(wiz, @wizChannel + MAX_WIZ_CHANNELS * t_channel)
|
||||
//
|
||||
// Clear notiications on this port
|
||||
//
|
||||
if wiz->channel_proto == WIZ_PROTO_TCP and (wiz->channel_state == TCP_STATE_OPEN or wiz->channel_state == TCP_STATE_CLOSING)
|
||||
wiz->channel_state = TCP_STATE_CLOSING
|
||||
pokereg(wiz=>channel_regs + WIZ_SnCR, $08) // DISCON
|
||||
repeat
|
||||
wizServiceIP()
|
||||
until wiz->channel_state == TCP_STATE_CLOSED
|
||||
wiz->channel_proto = WIZ_PROTO_CLOSED
|
||||
return 0
|
||||
fin
|
||||
fin
|
||||
@ -576,13 +722,13 @@ end
|
||||
//
|
||||
// Service incoming packets
|
||||
//
|
||||
export def serviceIP
|
||||
def wizServiceIP
|
||||
word wiz, wizregs, wizdata, rxlen, rxrr, rxwr, rxpkt, splitlen
|
||||
byte ir, i, sir
|
||||
|
||||
ir = peekreg(WIZ_IR)
|
||||
if ir and ir <> $FF // Ignore spurious read of IR
|
||||
//putc('I');putb(ir)
|
||||
putc('I');putb(ir)
|
||||
wiz = @wizChannel
|
||||
for i = 0 to 3
|
||||
when ir & (1 << i)
|
||||
@ -594,7 +740,86 @@ export def serviceIP
|
||||
wizdata = wiz=>channel_rxmem
|
||||
sir = peekreg(wizregs + WIZ_SnIR)
|
||||
when wiz->channel_proto
|
||||
is IP_PROTO_UDP
|
||||
is WIZ_PROTO_TCP
|
||||
if sir & $01
|
||||
putc('C')
|
||||
//
|
||||
// Connect TCP socket
|
||||
//
|
||||
when wiz->channel_state
|
||||
is TCP_STATE_LISTEN
|
||||
peekregs(wiz=>channel_regs + WIZ_SnDIPR, @wiz=>channel_remip, IP4ADR_SIZE)
|
||||
wiz=>channel_remport = peekregw(wiz=>channel_regs + WIZ_SnDPORT)
|
||||
is TCP_STATE_CONNECT
|
||||
wiz->channel_state = TCP_STATE_OPEN
|
||||
break
|
||||
otherwise
|
||||
putc('?')
|
||||
wend
|
||||
fin
|
||||
if sir & $04
|
||||
putc('R')
|
||||
//
|
||||
// Receive TCP packet
|
||||
//
|
||||
rxlen = peekregw(wizregs + WIZ_SnRSR)
|
||||
rxrr = peekregw(wizregs + WIZ_SnRXRD)
|
||||
rxwr = rxrr + rxlen
|
||||
rxpkt = heapalloc(rxlen)
|
||||
if rxwr >= WIZ_RXSIZE
|
||||
putc('!')
|
||||
splitlen = WIZ_RXSIZE - rxrr
|
||||
peekregs(wizdata + rxrr, rxpkt, splitlen)
|
||||
peekregs(wizdata, rxpkt + splitlen, rxlen - splitlen)
|
||||
else
|
||||
peekregs(wizdata + rxrr, rxpkt, rxlen)
|
||||
fin
|
||||
putc('=');putip(@wiz=>channel_remip);putc(':');puti(wiz=>channel_remport);putln
|
||||
pokeregw(wizregs + WIZ_SnRXRD, rxwr)
|
||||
pokereg(wizregs + WIZ_SnCR, $40) // RECV
|
||||
wiz=>channel_recv_func(@wiz=>channel_remip,wiz=>channel_remport,wiz=>channel_lclport,rxpkt,rxlen,wiz=>channel_recv_parm)
|
||||
heaprelease(rxpkt)
|
||||
fin
|
||||
if sir & $02
|
||||
putc('S')
|
||||
//
|
||||
// Close TCP socket
|
||||
//
|
||||
when wiz->channel_state
|
||||
is TCP_STATE_OPEN
|
||||
wiz->channel_state = TCP_STATE_CLOSING
|
||||
wiz=>channel_recv_func(@wiz=>channel_remip,wiz=>channel_remport,0,wiz=>channel_lclport,0,wiz=>channel_recv_parm)
|
||||
break
|
||||
is TCP_STATE_CLOSING
|
||||
wiz->channel_state = TCP_STATE_CLOSED
|
||||
pokereg(wiz=>channel_regs + WIZ_SnCR, $10) // CLOSE
|
||||
break
|
||||
otherwise
|
||||
putc('?')
|
||||
wend
|
||||
fin
|
||||
if sir & $08
|
||||
putc('T')
|
||||
//
|
||||
// Timeout on TCP socket
|
||||
//
|
||||
when wiz->channel_state
|
||||
is TCP_STATE_OPEN
|
||||
wiz->channel_state = TCP_STATE_CLOSING
|
||||
wiz=>channel_recv_func(@wiz=>channel_remip,wiz=>channel_remport,wiz=>channel_lclport,0,0,wiz=>channel_recv_parm)
|
||||
break
|
||||
is TCP_STATE_CONNECT
|
||||
wiz=>channel_recv_func(@wiz=>channel_remip,wiz=>channel_remport,wiz=>channel_lclport,0,0,wiz=>channel_recv_parm)
|
||||
is TCP_STATE_CLOSING
|
||||
wiz->channel_state = TCP_STATE_CLOSED
|
||||
pokereg(wiz=>channel_regs + WIZ_SnCR, $10) // CLOSE
|
||||
break
|
||||
otherwise
|
||||
putc('?')
|
||||
wend
|
||||
fin
|
||||
break
|
||||
is WIZ_PROTO_UDP
|
||||
//putc('U');putb(sir)
|
||||
if sir & $04
|
||||
//putc('R')
|
||||
@ -622,8 +847,6 @@ export def serviceIP
|
||||
heaprelease(rxpkt)
|
||||
fin
|
||||
break
|
||||
is IP_PROTO_TCP
|
||||
break
|
||||
otherwise
|
||||
wend
|
||||
pokereg(wiz=>channel_regs + WIZ_SnIR, sir) // Clear SnIR
|
||||
@ -643,7 +866,7 @@ end
|
||||
//
|
||||
// Set the local IP addresses
|
||||
//
|
||||
export def setInterfaceIP(newIP, newSubnet, newGateway)
|
||||
def setWizIP(newIP, newSubnet, newGateway)
|
||||
if newIP
|
||||
localip:0 = newIP=>0; localip:2 = newIP=>2
|
||||
pokeregs(WIZ_SIPR, newIP, IP4ADR_SIZE)
|
||||
@ -660,7 +883,7 @@ end
|
||||
//
|
||||
// Get the interface hardware address
|
||||
//
|
||||
export def getInterfaceHA(ha)
|
||||
def getWizHA(ha)
|
||||
if ha
|
||||
ha=>0 = wizMAC:0; ha=>2 = wizMAC:2; ha=>4 = wizMAC:4
|
||||
fin
|
||||
@ -708,6 +931,19 @@ for slot = $F0 downto $90 step $10
|
||||
saveidx=>channel_rxmem = WIZ_RXMEM + (WIZ_RXSIZE * slot)
|
||||
saveidx = saveidx + t_channel
|
||||
next
|
||||
//
|
||||
// Fill in Net class
|
||||
//
|
||||
iNet:serviceIP = @wizServiceIP
|
||||
iNet:openUDP = @wizOpenUDP
|
||||
iNet:sendUDP = @wizSendUDP
|
||||
iNet:closeUDP = @wizCloseUDP
|
||||
iNet:listenTCP = @wizListenTCP
|
||||
iNet:connectTCP = @wizConnectTCP
|
||||
iNet:sendTCP = @wizSendTCP
|
||||
iNet:closeTCP = @wizCloseTCP
|
||||
iNet:setInterfaceIP = @setWizIP
|
||||
iNet:getInterfaceHA = @getWizHA
|
||||
return modkeep
|
||||
fin
|
||||
fin
|
||||
|
@ -14,6 +14,7 @@ UTHERNET= UTHERNET\#FE1000
|
||||
ETHERIP = ETHERIP\#FE1000
|
||||
INET = INET\#FE1000
|
||||
DHCP = DHCP\#FE1000
|
||||
HTTPD = HTTPD\#FE1000
|
||||
ROGUE = ROGUE\#FE1000
|
||||
ROGUEIO = ROGUEIO\#FE1000
|
||||
ROGUEMAP= ROGUEMAP\#FE1000
|
||||
@ -46,7 +47,7 @@ TXTTYPE = .TXT
|
||||
#SYSTYPE = \#FF2000
|
||||
#TXTTYPE = \#040000
|
||||
|
||||
all: $(PLASM) $(PLVM) $(PLVM01) $(PLVM02) $(PLVM03) $(CMD) $(MEMMGR) $(MEMTEST) $(SB) $(MON) $(ROD) $(SIEVE) $(WIZNET) $(UTHERNET) $(ETHERIP) $(INET) $(DHCP) $(ROGUE) $(ROGUEMAP) $(ROGUECOMBAT) $(ROGUEIO) $(HGR1)
|
||||
all: $(PLASM) $(PLVM) $(PLVM01) $(PLVM02) $(PLVM03) $(CMD) $(MEMMGR) $(MEMTEST) $(SB) $(MON) $(ROD) $(SIEVE) $(WIZNET) $(UTHERNET) $(ETHERIP) $(INET) $(DHCP) $(HTTPD) $(ROGUE) $(ROGUEMAP) $(ROGUECOMBAT) $(ROGUEIO) $(HGR1)
|
||||
|
||||
clean:
|
||||
-rm *FE1000 *FF2000 $(PLASM) $(PLVM) $(PLVM01) $(PLVM02) $(PLVM03)
|
||||
@ -143,6 +144,10 @@ $(DHCP): libsrc/dhcp.pla $(PLVM02) $(PLASM)
|
||||
./$(PLASM) -AM < libsrc/dhcp.pla > libsrc/dhcp.a
|
||||
acme --setpc 4094 -o $(DHCP) libsrc/dhcp.a
|
||||
|
||||
$(HTTPD): samplesrc/httpd.pla $(PLVM02) $(PLASM)
|
||||
./$(PLASM) -AM < samplesrc/httpd.pla > samplesrc/httpd.a
|
||||
acme --setpc 4094 -o $(HTTPD) samplesrc/httpd.a
|
||||
|
||||
$(ROGUE): samplesrc/rogue.pla $(PLVM02) $(PLASM)
|
||||
./$(PLASM) -AM < samplesrc/rogue.pla > samplesrc/rogue.a
|
||||
acme --setpc 4094 -o $(ROGUE) samplesrc/rogue.a
|
||||
|
230
src/samplesrc/httpd.pla
Normal file
230
src/samplesrc/httpd.pla
Normal file
@ -0,0 +1,230 @@
|
||||
//
|
||||
// HTTP Daemon
|
||||
//
|
||||
import cmdsys
|
||||
predef syscall, call, getc, gets, putc, puts, putln
|
||||
predef memset, memcpy, modaddr, modexec
|
||||
predef heapmark, heapallocalign, heapalloc, heaprelease
|
||||
byte MACHID
|
||||
end
|
||||
//
|
||||
// Net object
|
||||
//
|
||||
import inet
|
||||
word iNet
|
||||
end
|
||||
struc t_inet
|
||||
word initIP
|
||||
word serviceIP
|
||||
word openUDP
|
||||
word sendUDP
|
||||
word closeUDP
|
||||
word listenTCP
|
||||
word connectTCP
|
||||
word sendTCP
|
||||
word closeTCP
|
||||
word setInterfaceIP
|
||||
word getInterfaceHA
|
||||
end
|
||||
|
||||
word socketHTTP
|
||||
byte[65] prefix
|
||||
byte perr
|
||||
word filebuff, iobuff
|
||||
byte hello = "Apple II Web Server"
|
||||
byte defhtml = "INDEX.HTML"
|
||||
//
|
||||
// HTTP response
|
||||
//
|
||||
byte httpOK = "HTTP/1.1 200 OK\n"
|
||||
byte = "Content-Type: text/html\n"
|
||||
byte = "Content-Length: "
|
||||
byte httpLen = " \n"
|
||||
byte = ""
|
||||
byte httpBAD = "HTTP/1.1 404 NOTFOUND\n"
|
||||
byte = "Content-Type: text/plain\n"
|
||||
byte = "Content-Length: 12\n"
|
||||
byte = "\n"
|
||||
byte = "Bad Request\n"
|
||||
byte = ""
|
||||
byte[] httpBAD_end
|
||||
//
|
||||
// ProDOS routines
|
||||
//
|
||||
def getpfx(path)
|
||||
byte params[3]
|
||||
|
||||
^path = 0
|
||||
params.0 = 1
|
||||
params:1 = path
|
||||
perr = syscall($C7, @params)
|
||||
return path
|
||||
end
|
||||
def setpfx(path)
|
||||
byte params[3]
|
||||
|
||||
params.0 = 1
|
||||
params:1 = path
|
||||
perr = syscall($C6, @params)
|
||||
return path
|
||||
end
|
||||
def open(path, buff)
|
||||
byte params[6]
|
||||
|
||||
params.0 = 3
|
||||
params:1 = path
|
||||
params:3 = buff
|
||||
params.5 = 0
|
||||
perr = syscall($C8, @params)
|
||||
return params.5
|
||||
end
|
||||
def close(refnum)
|
||||
byte params[2]
|
||||
|
||||
params.0 = 1
|
||||
params.1 = refnum
|
||||
perr = syscall($CC, @params)
|
||||
return perr
|
||||
end
|
||||
def read(refnum, buff, len)
|
||||
byte params[8]
|
||||
|
||||
params.0 = 4
|
||||
params.1 = refnum
|
||||
params:2 = buff
|
||||
params:4 = len
|
||||
params:6 = 0
|
||||
perr = syscall($CA, @params)
|
||||
return params:6
|
||||
end
|
||||
//
|
||||
// DEBUG
|
||||
//
|
||||
def putln
|
||||
return putc($0D)
|
||||
end
|
||||
def putb(hexb)
|
||||
return call($FDDA, hexb, 0, 0, 0)
|
||||
end
|
||||
def puth(hex)
|
||||
return call($F941, hex >> 8, hex, 0, 0)
|
||||
end
|
||||
def puti(i)
|
||||
if i < 0; putc('-'); i = -i; fin
|
||||
if i < 10
|
||||
putc(i + '0')
|
||||
else
|
||||
puti(i / 10)
|
||||
putc(i % 10 + '0')
|
||||
fin
|
||||
end
|
||||
def putip(ipptr)
|
||||
byte i
|
||||
|
||||
for i = 0 to 2
|
||||
puti(ipptr->[i]); putc('.')
|
||||
next
|
||||
return puti(ipptr->[i])
|
||||
end
|
||||
def dumpbytes(buf, len)
|
||||
word i
|
||||
|
||||
for i = 0 to len - 1
|
||||
putb(buf->[i])
|
||||
if i & 15 == 15
|
||||
putln
|
||||
else
|
||||
putc(' ')
|
||||
fin
|
||||
next
|
||||
end
|
||||
//
|
||||
// String functions
|
||||
//
|
||||
def strcat(dst, src1, src2)
|
||||
memcpy(dst + 1, src1 + 1, ^src1)
|
||||
memcpy(dst + 1 + ^src1, src2 + 1, ^src2)
|
||||
^dst = ^src1 + ^src2
|
||||
return dst
|
||||
end
|
||||
def itos(dst, i)
|
||||
if i < 0; ^dst = '-'; i = -i; dst = dst + 1; fin
|
||||
if i < 10
|
||||
^dst = i + '0'
|
||||
else
|
||||
dst = itos(dst, i / 10)
|
||||
^dst = i % 10 + '0'
|
||||
fin
|
||||
return dst + 1
|
||||
end
|
||||
//
|
||||
// Serve HTTP requests
|
||||
//
|
||||
def servHTTP(remip, remport, lclport, data, len, param)
|
||||
byte i
|
||||
byte[65] filename
|
||||
word url
|
||||
|
||||
//
|
||||
// Parse HTTP request
|
||||
//
|
||||
if len > 0
|
||||
//
|
||||
// Better be 'GET'
|
||||
//
|
||||
if data->0 == 'G' and data->1 == 'E' and data->2 == 'T' and data=>3 == ' '
|
||||
len = len - 1
|
||||
if len > 64
|
||||
len = 64
|
||||
fin
|
||||
for i = 4 to len
|
||||
if data->[i] <= ' '
|
||||
data->3= i - 4
|
||||
url = data + 3
|
||||
if url->1 == '/'
|
||||
if url->0 == 1
|
||||
url = @defhtml
|
||||
else
|
||||
url->1 = url->0 - 1
|
||||
url = url + 1
|
||||
fin
|
||||
fin
|
||||
strcat(@filename, @prefix, url)
|
||||
puts(@filename);putln
|
||||
return
|
||||
fin
|
||||
next
|
||||
else
|
||||
iNet:sendTCP(socketHTTP, @httpBAD, @httpBAD_end - @httpBAD)
|
||||
fin
|
||||
else
|
||||
iNet:closeTCP(socketHTTP)
|
||||
socketHTTP = 0
|
||||
fin
|
||||
end
|
||||
|
||||
if !iNet:initIP()
|
||||
return -1
|
||||
fin
|
||||
puts(@hello)
|
||||
getpfx(@prefix)
|
||||
//
|
||||
// Alloc aligned file/io buffers
|
||||
//
|
||||
filebuff = heapallocalign(1024, 8, 0)
|
||||
iobuff = heapallocalign(1024, 8, 0)
|
||||
//
|
||||
// Service IP
|
||||
//
|
||||
repeat
|
||||
//
|
||||
// (Re)Open HTTPD port
|
||||
//
|
||||
if !socketHTTP
|
||||
socketHTTP = iNet:listenTCP(80, @servHTTP, 0)
|
||||
fin
|
||||
iNet:serviceIP()
|
||||
until ^$C000 > 127
|
||||
^$C010
|
||||
|
||||
done
|
Loading…
Reference in New Issue
Block a user