I have a custom microcontroller that connects to an old MS-DOS PC with a serial port and I'm having that old PC connect to my router using RJ45 ethernet cable so other computers can connect and I'm making my own DOS webserver program to allow that connection to happen.
I'm using Trumpet sockets NTCPDRV for DOS interrupt routines to help me, but I am struggling with receiving maximum data.
First, this is the function I'm dealing with (as taken from TCP201.SPE file which may be downloaded from files within
http://wiki.freedos.org/wiki/index.php/Networking_FreeDOS_complete):
tcp_status get status of a TCP session
call
ah = 14H
al = option flags
0 = normal
128 = asynchronous. Notify by
event_call
bx = handle
return
dl = error code
bad_handle
dh = tcp_state
ax = bytes available for reading
cx = bytes still being transmitted
es:di = pointer to session info
ip_srce dword
ip_dest dword
ip_prot byte
active byte (> 0 is active)
And I have my code.
ES:DI is an address of a struct that's already been initialized.
Int 61h in this case points to the NTCPDRV routines.
A TCP handle has already been allocated before this call is made.
I'll comment my code as I go through it.
CS:BP+breadt is an internal variable in code space as our flag.
CS:BP+iptabls is an internal struct in code space to store extended IP data
;on entry, BP=start of this code offset
mov AX,[ES:DI+errc] ;Get error code as input option
cmp AX,0000h ;See if code is 0
je noherr
xor AX,AX ;Code is not 0 so reset internal read status
mov [CS:BP+breadt],AX
noherr:
mov BX,[ES:DI+handle] ;Get our TCP handle into BX
push ES ;Save our pointer so we don't corrupt results
push DI
mov ax,1400h ;get status normally (better than setting AH and AL separately)
int 61h ;Call driver interrupt.
push ES ; Driver returns its own ES:DI value for IP address info.
pop DS ; So we make DS:SI equal ES:DI for data extraction.
push DI
pop SI
push CS
pop ES ; Make ES our segment for internal ip address info data
add BP,iptbls
mov DI,BP ;Make ES:DI = location where the IP address info goes
movsd ; copy 10 bytes over
movsd
movsw
pop DI ;restore our struct address
pop ES
and DX,00FFh ;We don't care about tcp_state from driver, just the error code.
;This is where the problem lies???
mov BX,[CS:BP+breadt] ;load our last bytes available to read value
cmp BX,0000h ;See how much there is
je nobts
cmp AX,0000h ;Last time there was 1+ bytes available to read
jne nobts ;See if new bytes available is 1+
or DX,1000h ;New bytes available is 0 so we set high byte of error flag
nobts:
mov [ES:DI+errc],DX ;store TCP error code to our struct
mov [ES:DI+bsend],CX ;store bytes being sent to our struct
mov [ES:DI+bread],AX ;store bytes available to read to our struct
mov [CS:BP+breadt],AX ;save bytes available to read for the next time we are called
;End of possible problem section
ret
breadt:
dd 0
iptbls:
iptsrc dd 0h ;Source IP
iptdest dd 0h ;Dest IP
iptstat dw 0h ;IP table status. Low byte=active, High byte=protocol
Now with my code, I could get away with putting this call in an endless loop until the bytes available to read (returned in AX from the driver call) is > 0, but that only allows for one chunk of data to read, not necessarily all of it.
What I want to do is have this run until there are bytes available to read and then have this run again until there are no more bytes available to read so I know I got all chunks possible. Maybe I'll later enhance the lack of data with a timeout.
The problem is with my function when I run it, I do receive 0 for bytes available to read (AX return value) and error 0 (DX return value), but after a period of time, the error value (DX) is 1000h but bytes available to read (AX) is STILL 0!. I was expecting AX to be > 0 so I can read data then DX can be 1000h when AX returns to 0 again.
When I call the function at first, I used -1 for input error code to reset the internal bytes read status (defined as breadt) then on subsequent calls, I use 0 for input error code so we don't modify breadt directly.
Is there something in my code here that I'm doing wrong?