NEW
  AUTO 3,1
				.LIST OFF
				.OP	65C02
				.OR	$2000
				.TF sbin/httpd
*--------------------------------------
				.INB inc/macros.i
				.INB inc/a2osx.i
				.INB inc/mli.i
				.INB inc/mli.e.i
				.INB inc/eth.i
				.INB inc/libtcpip.i
				.INB inc/net.http.i
*--------------------------------------
TIMEOUT.MAX		.EQ 30					30 sec.
CONN.MAX		.EQ 16
*--------------------------------------
				.DUMMY
				.OR ZPBIN
ZS.START
ZPPtr1			.BS 2
ZPPtr2			.BS 2
ZPSktPtr		.BS 2
hFile			.BS 1
hLineBuf		.BS 1

hSrvSocket		.BS 1
TimeOut			.BS 1
hSrvName		.BS 1
ZPSrvNamePtr	.BS 2
hRootdir		.BS 1
ZPRootDirPtr	.BS 2

ZPRequestPtr	.BS 2
ZPnRequestLen	.BS 2
ZPLinePtr		.BS 2
ZPRepPtr		.BS 2

CLN.hSocket		.BS 1
REP.hBuf		.BS 1
REQ.hFile		.BS 1
REQ.KeepAlive	.BS 1
REQ.MimeType	.BS 1
REQ.hReq		.BS 1

ZS.END			.ED
*--------------------------------------
*			File Header (16 Bytes)
*--------------------------------------
CS.START		cld
				jmp (.1,x)
				.DA #$61				6502,Level 1 (65c02)
				.DA #1					BIN Layout Version 1
				.DA #S.PS.F.EVENT
				.DA #0
				.DA CS.END-CS.START		CS
				.DA DS.END-DS.START		DS
				.DA #64					SS
				.DA #ZS.END-ZS.START	Zero Page Size
				.DA 0
*--------------------------------------
* Relocation Table
*--------------------------------------
.1				.DA CS.INIT
				.DA CS.RUN
				.DA CS.DOEVENT
				.DA	CS.QUIT
L.LIBTCPIP		.DA LIBTCPIP
L.ETCHTTPDCONF	.DA ETCHTTPDCONF
L.KEYWORDS.CONF	.DA KEYWORDS.CONF
J.KEYWORDS.CONF	.DA CS.RUN.CONF.SERVERNAME
				.DA CS.RUN.CONF.LISTEN
				.DA CS.RUN.CONF.DOCUMENTROOT
L.SA.LOCAL		.DA SA.LOCAL
L.MSG.TCPWAIT	.DA MSG.TCPWAIT
L.MSG.TCPIPERR	.DA MSG.TCPIPERR
L.MSG.INITCONF	.DA MSG.INITCONF
L.MSG.INITOK	.DA MSG.INITOK
L.MSG.SKTERR	.DA MSG.SKTERR
L.MSG.INCOMING	.DA MSG.INCOMING
L.MSG.REQ		.DA MSG.REQ
L.MSG.FILE		.DA MSG.FILE
L.MSG.SKTCLOSE	.DA MSG.SKTCLOSE
L.KEYWORDS.REQ	.DA KEYWORDS.REQ
J.KEYWORDS.REQ	.DA CS.RUN.REQ.GET
L.INDEX.HTML	.DA INDEX.HTML
L.MIME.TYPES	.DA MIME.TYPES
T.MIME			.DA MIME.HTML
				.DA MIME.TXT
				.DA MIME.TTF
				.DA MIME.ICO
				.DA MIME.PNG
				.DA MIME.JPG
L.MIME.DEFAULT	.DA MIME.DEFAULT
L.HTTP.200		.DA HTTP.200
L.HTTP.404		.DA HTTP.404
				.DA 0
*--------------------------------------
CS.INIT			>LDYA L.LIBTCPIP
				>SYSCALL LoadLib
				bcs .9
				sta hLIBTCPIP

.9				rts
*--------------------------------------
CS.RUN			>LDYA L.MSG.TCPWAIT
				>SYSCALL PutS

				lda #TIMEOUT.MAX
				sta TimeOut

.1				>SLEEP
				>LIBCALL hLIBTCPIP,LIBTCPIP.GETCFG	is TCPIP loaded ?
				bcs .99

				>STYA ZPPtr1
				lda (ZPPtr1)			Configured ?
				bmi CS.RUN.INIT

				lda TimeOut
				bcs .99

				ldy #S.PS.hStdIn
				lda (pPS),y
				>SYSCALL FEOF
				bcs CS.RUN.RTS			I/O err

				tay
				bne .1

				>SYSCALL GetChar
				bcs CS.RUN.RTS

				cmp #3					Ctrl-C
				bne .1

				sec
				rts

.99				>LDYA L.MSG.TCPIPERR
				>SYSCALL PutS
CS.RUN.SYN
				lda #E.SYN
				sec
CS.RUN.RTS		rts
*--------------------------------------
CS.RUN.INIT		ldx #3
				ldy #S.IPCFG.IP+3

.1				lda (ZPPtr1),y
				sta SA.LOCAL+S.SOCKADDR.ADDR,x
				dey
				dex
				bpl .1

				>LDYAI 256
				>SYSCALL GetMem
				bcs CS.RUN.RTS

				>STYA ZPLinePtr
				stx hLineBuf

				>PUSHW L.MSG.INITCONF
				>PUSHW L.ETCHTTPDCONF
				>PUSHBI 2

				>SYSCALL PrintF
				bcs CS.RUN.RTS

				jsr CS.RUN.CONF
				bcs CS.RUN.RTS

				>PUSHBI S.SOCKET.T.SEQPKT
				>PUSHBI 0				no protocol
				>LIBCALL hLIBTCPIP,LIBTCPIP.Socket
				bcs CS.RUN.RTS

				sta hSrvSocket

				>PUSHB hSrvSocket
				>PUSHW L.SA.LOCAL
				>LIBCALL hLIBTCPIP,LIBTCPIP.Bind
				bcs CS.RUN.ERR

				lda hSrvSocket
				>LIBCALL hLIBTCPIP,LIBTCPIP.Listen
				bcs CS.RUN.ERR

				>PUSHW L.MSG.INITOK
				>PUSHW SA.LOCAL+S.SOCKADDR.PORT
				>PUSHW ZPRootDirPtr
				>PUSHBI 4

				>SYSCALL PrintF
*--------------------------------------
CS.RUN.LOOP		>SLEEP
				jsr CS.RUN.SERVER
				bcs CS.RUN.ERR
				bra CS.RUN.LOOP

CS.RUN.ERR		>LDYA L.MSG.SKTERR
				>SYSCALL PutS
				lda #E.SYN
				sec
				rts
*--------------------------------------
CS.RUN.CONF		>PUSHW L.ETCHTTPDCONF
				>PUSHBI	O.RDONLY+O.TEXT
				>PUSHBI S.FI.T.TXT
				>PUSHWZ
				>SYSCALL FOpen
				bcs .99

				sta hFile

.1				>PUSHB hFile
				>PUSHW ZPLinePtr
				>PUSHWI 256
				>SYSCALL FGetS
				bcs .8

				tya
				beq .1

				lda (ZPLinePtr)
				cmp #'#'
				beq .1

				>LDYA L.KEYWORDS.CONF
				>STYA ZPPtr1

				ldx #0

.2				ldy #0

.3				lda (ZPPtr1),y
				cmp	(ZPLinePtr),y
				bne .4

				iny
				cmp #C.SPACE
				bne .3

				jsr CS.RUN.CONF.JMP
				bcc .1

				bra .97

.4				inx
				inx

				ldy #0

.5				iny
				lda (ZPPtr1),y
				cmp #C.SPACE
				bne .5

				tya
				sec
				adc ZPPtr1
				sta ZPPtr1
				bcc .6
				inc ZPPtr1+1

.6				lda	(ZPPtr1)
				bne .2

.97				lda #E.SYN

.98				pha
				jsr .8
				pla
				sec
.99				rts

.8				lda hFile
				>SYSCALL FClose
				rts
*--------------------------------------
CS.RUN.CONF.JMP	tya
				clc
				adc ZPLinePtr
				sta ZPPtr1
				tay
				lda #0
				adc ZPLinePtr+1
				sta ZPPtr1+1

				jmp (J.KEYWORDS.CONF,x)

CS.RUN.CONF.SERVERNAME
				>SYSCALL StrDup
				bcs .9

				>STYA ZPSrvNamePtr
				stx hSrvName

.9				rts
CS.RUN.CONF.LISTEN
				>SYSCALL AToI
				bcs .9

				>STYA SA.LOCAL+S.SOCKADDR.PORT

.9				rts
CS.RUN.CONF.DOCUMENTROOT
				>PUSHYA
				>PUSHWI 0				Allocate
				>SYSCALL RealPath
				bcs .9

				>STYA ZPRootDirPtr
				stx hRootdir

.9				rts
*--------------------------------------
CS.RUN.SERVER	lda hSrvSocket
				>LIBCALL hLIBTCPIP,LIBTCPIP.Accept
				bcs .8

				sta CLN.hSocket
				>SYSCALL GetMemPtr
				>STYA ZPSktPtr

				>PUSHW L.MSG.INCOMING

				>PUSHB CLN.hSocket

				ldx #3
				ldy #S.SOCKET.REM.ADDR

.1				>PUSHB (ZPSktPtr),y
				iny
				dex
				bpl .1

				>PUSHBI 5
				>SYSCALL PrintF

				jsr CS.RUN.CLIENT

				>PUSHW L.MSG.SKTCLOSE
				>PUSHB CLN.hSocket
				>PUSHBI 1
				>SYSCALL PrintF

				lda CLN.hSocket
				>LIBCALL hLIBTCPIP,LIBTCPIP.Shutdown

.8				clc
.9
CS.RUN.SERVER.RTS
				rts
*--------------------------------------
CS.RUN.CLIENT	>LDYAI 1024
				>SYSCALL GetMem
				bcs CS.RUN.SERVER.RTS

				>STYA ZPRepPtr
				stx REP.hBuf

.10				>STZ.G REQ.FullPath
				stz REQ.hReq
				stz REQ.KeepAlive
				stz REQ.hFile

.1				>SLEEP

				lda CLN.hSocket
				>LIBCALL hLIBTCPIP,LIBTCPIP.Recv
				bcc .2

				cmp #E.NODATA
				beq .1

				jmp .99

.2				jsr CS.RUN.REQ.GetReq

.3				jsr CS.RUN.REQ.GetLine
				bcs .4

				>LDYA ZPLinePtr
				>STYA ZPPtr2

				>LDYA L.KEYWORDS.REQ
				jsr CS.RUN.GET.KW
				bcs .3

				jsr CS.RUN.REQ.JMP
				bcc .3
				bcs .98

.4				lda REQ.hReq
				>SYSCALL FreeMem

				stz REQ.hReq

				>LDA.G REQ.FullPath
				beq .9

				jsr CS.RUN.OpenFile
				bcs .9

				jsr CS.RUN.SendFile
				bcs .99

				bra .8

.9				>PUSHB CLN.hSocket
				>PUSHW L.HTTP.404
				>PUSHWI HTTP.404.len
				>LIBCALL hLIBTCPIP,LIBTCPIP.Send

.8				bit REQ.KeepAlive
				bpl .99
				jmp .10

.98				lda REQ.hReq
				beq .99

				>SYSCALL FreeMem

.99				lda REP.hBuf
				>SYSCALL FreeMem

				rts
*--------------------------------------
CS.RUN.REQ.GetReq
				sta REQ.hReq
				>SYSCALL GetMemPtr
				>STYA ZPRequestPtr

				>PUSHW L.MSG.REQ
				>PUSHB REQ.hReq
				>PUSHB CLN.hSocket
				>PUSHBI 2
				>SYSCALL PrintF

				ldy #S.IP.TOTAL.LENGTH+1
				lda (ZPRequestPtr),y
				sec
				sbc #S.TCP-S.IP
				eor #$ff
				sta ZPnRequestLen

				dey

				lda (ZPRequestPtr),y
				sbc /S.TCP-S.IP
				eor #$ff
				sta ZPnRequestLen+1

				lda ZPRequestPtr
				clc
				adc #S.TCP
				sta ZPRequestPtr
				bcc .8

				inc ZPRequestPtr+1
.8				rts
*--------------------------------------
CS.RUN.REQ.GetLine
				ldy #0

.1				inc ZPnRequestLen
				bne .2
				inc ZPnRequestLen+1
				beq .9

.2				lda (ZPRequestPtr)
				inc ZPRequestPtr
				bne .21
				inc ZPRequestPtr+1

.21				cmp #C.CR
				bne .4

				inc ZPnRequestLen
				bne .3
				inc ZPnRequestLen+1
				beq .9

.3				lda (ZPRequestPtr)
				inc ZPRequestPtr
				bne .31
				inc ZPRequestPtr+1

.31				eor #C.LF
				bne .9

				sta (ZPLinePtr),y		Y,A = StrLen
				clc
				rts

.4				sta (ZPLinePtr),y
				iny
				bra .1

.9				sec
				rts
*--------------------------------------
CS.RUN.OpenFile	>PUSHW L.MSG.FILE
				>PUSHB CLN.hSocket
				>PUSHEA.G REQ.FullPath
				>PUSHBI 3
				>SYSCALL PrintF

				>PUSHEA.G REQ.FullPath
				>PUSHBI	O.RDONLY
				>PUSHBI 0				type
				>PUSHWZ					Aux type
				>SYSCALL FOpen
				bcs .9

				stx REQ.hFile

				>PUSHA
				>PUSHEA.G REQ.Stat
				>SYSCALL FStat

				>LEA.G REQ.FullPath
				>STYA ZPPtr2

				ldx #$ff
				ldy #$ff

.1				iny
				lda (ZPPtr2),y
				beq .2

				cmp #'.'
				bne .1

				tya
				tax
				bra .1

.2				txa
				bpl .3

				lda #MIME.DEFAULT.ID
				bra .8

.3				sec

				adc ZPPtr2
				sta ZPPtr2
				bcc .4

				inc ZPPtr2+1

.4				>LDYA L.MIME.TYPES
				jsr CS.RUN.GET.KW

				txa

.8				sta REQ.MimeType

				clc
.9				rts
*--------------------------------------
CS.RUN.SendFile	>PUSHW ZPRepPtr
				>PUSHW L.HTTP.200

				ldx REQ.MimeType
				>PUSHW T.MIME,x
				>PUSHL.G REQ.Stat+S.STAT.SIZE
				>PUSHBI 6

				>SYSCALL SPrintF
				bcs .9

				jsr CS.RUN.SendBuf		Y,A = car count

.1				>PUSHB REQ.hFile
				>PUSHW ZPRepPtr
				>PUSHWI 1024
				>SYSCALL FRead
				bcs .8

				jsr CS.RUN.SendBuf
				bcs .9

				bra .1

.8				cmp #MLI.E.EOF
				bne .9

				clc

.9				php
				pha
				lda REQ.hFile
				>SYSCALL FClose
				pla
				plp
				rts
*--------------------------------------
CS.RUN.SendBuf	pha
				>PUSHB CLN.hSocket
				>PUSHW ZPRepPtr
				pla
				>PUSHYA
				>LIBCALL hLIBTCPIP,LIBTCPIP.Send
				rts
*--------------------------------------
CS.RUN.REQ.JMP	jmp (J.KEYWORDS.REQ,x)
*--------------------------------------
CS.RUN.REQ.GET	ldy #0

.1				iny
				lda (ZPPtr2),y

				eor #C.SPACE
				bne .1

				sta (ZPPtr2),y

				lda (ZPPtr2)

				cmp #'/'
				bne .4

				>PUSHEA.G REQ.FullPath
				>PUSHW ZPRootDirPtr
				>SYSCALL StrCpy

				>PUSHEA.G REQ.FullPath

				ldy #1
				lda (ZPPtr2),y
				bne .2

				>LDYA L.INDEX.HTML
				bra .3

.2				>LDYA ZPPtr2

.3				>PUSHYA
				>SYSCALL StrCat
				rts

.4				>PUSHW ZPPtr2
				>PUSHEA.G REQ.FullPath
				>SYSCALL RealPath
.9				rts
*--------------------------------------
CS.RUN.REQ.Connection
				lda (ZPPtr2)
				eor #'k'
				beq .1


				lda #$ff

.1				sta REQ.KeepAlive

				clc
				rts
*--------------------------------------
CS.RUN.GET.KW	>STYA ZPPtr1

				ldx #0

.2				ldy #$ff

.3				iny
				lda (ZPPtr1),y
				cmp	(ZPPtr2),y
				bne .4

				cmp #0
				beq .33

				cmp #C.SPACE
				bne .3

.33				tya
				sec
				adc ZPPtr2
				sta ZPPtr2
				bcc .8
				inc ZPPtr2+1

.8				clc
				rts

.4				inx
				inx

				ldy #0

.5				iny
				lda (ZPPtr1),y
				bne .5

				tya
				sec
				adc ZPPtr1
				sta ZPPtr1
				bcc .6
				inc ZPPtr1+1

.6				lda	(ZPPtr1)
				bne .2

				sec
				rts
*--------------------------------------
CS.DOEVENT		lda (pEvent)
				bpl .9					is it a TIMER event?
				lda TimeOut
				beq .9
				dec TimeOut

.9				sec						do not discard TIMER event
				rts
*--------------------------------------
CS.QUIT			lda hSrvSocket
				beq .1

				>LIBCALL hLIBTCPIP,LIBTCPIP.Shutdown

.1				lda hLineBuf
				beq .2

				>SYSCALL FreeMem


.2
				lda hLIBTCPIP
				beq .8

				>SYSCALL UnloadLib

.8				clc
				rts
*--------------------------------------
CS.END
*--------------------------------------
hLIBTCPIP		.BS 1
LIBTCPIP		.AZ "libtcpip"
ETCHTTPDCONF	.AZ "${BOOT}etc/httpd.conf"
*--------------------------------------
KEYWORDS.CONF	.AS "ServerName "
				.AS "Listen "
				.AS "DocumentRoot "
				.DA #0
*--------------------------------------
MSG.TCPWAIT		.AZ "HTTPD:Waiting for TCP/IP initializing..."
MSG.TCPIPERR	.AZ "HTTPD:TCP/IP Not initialized properly."
MSG.INITCONF	.AZ "HTTPD:Reading %s file...\r\n"
MSG.INITOK		.AZ "HTTPD:Listening on port %D, root dir: %s.\r\n"
MSG.SKTERR		.AZ "HTTPD:Skt Bind Error."
MSG.INCOMING	.AZ "HTTPD:Skt $%h Opened From %d.%d.%d.%d\r\n"
MSG.REQ			.AZ "HTTPD:Req $%h From Skt $%h\r\n"
MSG.FILE		.AZ "HTTPD:Skt $%h File %s\r\n"
MSG.SKTCLOSE	.AZ "HTTPD:Skt $%h Close\r\n"
*--------------------------------------
KEYWORDS.REQ	.AS "GET "
				.AS "Connection: "
				.DA #0
*--------------------------------------
INDEX.HTML		.AS "/index."			html
*--------------------------------------
MIME.TYPES		.AZ "html"
				.AZ "txt"
				.AZ "ttf"
				.AZ "ico"
				.AZ "png"
				.AZ "jpg"
				.DA #0
MIME.HTML		.AZ "text/html"
MIME.TXT		.AZ "text/plain"
MIME.TTF		.AZ "font/truetype"
MIME.ICO 		.AZ "image/vnd.microsoft.icon"			"image/x-icon"
MIME.PNG		.AZ "image/png"
MIME.JPG		.AZ "image/jpeg"
MIME.DEFAULT	.AZ "application/octet-stream"
MIME.DEFAULT.ID	.EQ 12
*--------------------------------------
HTTP.200		.AS "HTTP/1.1 200 OK"
				.DA #C.CR,#C.LF
				.AS "Server: A2osX-HTTPD 0.94"
				.DA #C.CR,#C.LF
				.AS "Content-Type: %s"
				.DA #C.CR,#C.LF
				.AS "Content-Length: %u"
				.DA #C.CR,#C.LF
				.DA #C.CR,#C.LF
				.DA #0
*--------------------------------------
HTTP.404		.AS "HTTP/1.1 404 Not Found"
				.DA #C.CR,#C.LF
				.AS "Server: A2osX-HTTPD 0.94"
				.DA #C.CR,#C.LF
				.AS "Content-Type: text/html"
				.DA #C.CR,#C.LF
				.AS "Content-Length: 47"
				.DA #C.CR,#C.LF
				.AS "Connection: Close"
				.DA #C.CR,#C.LF
				.DA #C.CR,#C.LF
				.AS "<HTML><BODY><B>404:NOT FOUND<B></BODY></HTML>"
				.DA #C.CR,#C.LF
HTTP.404.len	.EQ *-HTTP.404
*--------------------------------------
SA.LOCAL		.DA #AF.INET			S.SOCKADDR.AF
				.BS 1
				.BS 4					S.SOCKADDR.ADDR
				.DA TCP.PORT.HTTP
*--------------------------------------
				.DUMMY
				.OR 0
DS.START
REQ.FullPath	.BS MLI.MAXPATH+1
REQ.Stat		.BS S.STAT
DS.END
				.ED
*--------------------------------------
MAN
SAVE usr/src/sbin/httpd.s
ASM
