diff --git a/client/examples/dumb_telnet.asm b/client/examples/dumb_telnet.asm deleted file mode 100644 index d32b2e5..0000000 --- a/client/examples/dumb_telnet.asm +++ /dev/null @@ -1,386 +0,0 @@ -;NB65 API example in DASM format (http://www.atari2600.org/DASM/) - processor 6502 - - include "../inc/nb65_constants.i" - - ;useful macros - mac ldax - lda [{1}] - ldx [{1}]+1 - endm - - mac ldaxi - lda #<[{1}] - ldx #>[{1}] - endm - - mac stax - sta [{1}] - stx [{1}]+1 - endm - - mac cout - lda [{1}] - jsr print_a - endm - - mac print_cr - cout #13 - jsr print_a - endm - - mac nb65call - ldy [{1}] - jsr NB65_DISPATCH_VECTOR - endm - - mac print - - ldaxi [{1}] - ldy #NB65_PRINT_ASCIIZ - jsr NB65_DISPATCH_VECTOR - endm - - -;some routines & zero page variables -print_a equ $ffd2 -temp_ptr equ $FB ; scratch space in page zero - - -;start of code -;NO BASIC stub! needs to be direct booted via TFTP - org $1000 - - ldaxi #NB65_CART_SIGNATURE ;where signature should be in cartridge (if cart is banked in) - jsr look_for_signature - bcc found_nb65_signature - - ldaxi #NB65_RAM_STUB_SIGNATURE ;where signature should be in a RAM stub - jsr look_for_signature - bcs nb65_signature_not_found - jsr NB65_RAM_STUB_ACTIVATE ;we need to turn on NB65 cartridge - jmp found_nb65_signature - -nb65_signature_not_found - ldaxi #nb65_api_not_found_message - jsr print_ax - rts - -found_nb65_signature - - lda NB65_API_VERSION - cmp #02 - bpl .version_ok - print incorrect_version - jmp reset_after_keypress -.version_ok - print #initializing - nb65call #NB65_INITIALIZE - bcc .init_ok - print_cr - print #failed - print_cr - jsr print_errorcode - jmp reset_after_keypress -.init_ok - -;if we got here, we have found the NB65 API and initialised the IP stack -;print out the current configuration - nb65call #NB65_PRINT_IP_CONFIG -;prompt for a hostname, then resolve to an IP address -.get_hostname - print #remote_host - nb65call #NB65_INPUT_HOSTNAME - bcc .host_entered - ;if no host entered, then bail. - rts -.host_entered - stax nb65_param_buffer - print_cr - print #resolving - ldax nb65_param_buffer - nb65call #NB65_PRINT_ASCIIZ - print_cr - ldaxi #nb65_param_buffer - nb65call #NB65_DNS_RESOLVE - bcc .resolved_ok - print #failed - print_cr - jsr print_errorcode - jmp .get_hostname -.resolved_ok -.get_port - print #remote_port - nb65call #NB65_INPUT_PORT_NUMBER - bcc .port_entered - ;if no port entered, then assume port 23 - ldaxi #23 -.port_entered - stax nb65_param_buffer+NB65_TCP_PORT - print_cr - - print #char_mode_prompt -.char_mode_input - jsr $ffe4 - cmp #"A" - beq .ascii_mode - cmp #"a" - beq .ascii_mode - - cmp #"P" - beq .petscii_mode - cmp #"p" - beq .petscii_mode - jmp .char_mode_input -.ascii_mode - lda #14 - jsr print_a ;switch to lower case - - lda #0 - jmp .character_mode_set -.petscii_mode - lda #142 - jsr print_a ;switch to upper case - lda #1 -.character_mode_set - sta character_mode - lda #147 ; 'CLR/HOME' - jsr print_a - ldaxi #tcp_callback - stax nb65_param_buffer+NB65_TCP_CALLBACK - print #connecting - lda character_mode - beq .a_mode - print #petscii - jmp .c_mode -.a_mode - print #ascii -.c_mode - print #mode - ldaxi #nb65_param_buffer - nb65call #NB65_TCP_CONNECT - bcc .connect_ok - print_cr - print #failed - jsr print_errorcode - jmp .get_hostname -.connect_ok - print #ok - print_cr - lda #0 - sta connection_closed -.main_polling_loop - jsr NB65_PERIODIC_PROCESSING_VECTOR - lda connection_closed - beq .not_disconnected - print #disconnected - jmp .get_hostname -.not_disconnected - ;is there anything in the input buffer? - lda $c6 ;NDX - chars in keyboard buffer - beq .main_polling_loop - lda #0 - sta nb65_param_buffer+NB65_TCP_PAYLOAD_LENGTH - sta nb65_param_buffer+NB65_TCP_PAYLOAD_LENGTH+1 -.get_next_char - jsr $ffe4 ;getkey - 0 means no input - tax - beq .no_more_input - cmp #$03 ;RUN/STOP - bne .not_runstop - lda #0 - sta $cb ;overwrite "current key pressed" else it's seen by the tcp stack and the close aborts - - print #closing_connection - nb65call #NB65_TCP_CLOSE_CONNECTION - bcs .error_on_disconnect - print #disconnected - jmp .get_hostname -.error_on_disconnect - jsr print_errorcode - print_cr - jmp .get_hostname -.not_runstop - lda character_mode - bne .no_conversion_required - lda petscii_to_ascii_table,x - tax -.no_conversion_required - txa - ldy nb65_param_buffer+NB65_TCP_PAYLOAD_LENGTH - sta output_buffer,y - inc nb65_param_buffer+NB65_TCP_PAYLOAD_LENGTH - jmp .get_next_char -.no_more_input - ldaxi #output_buffer - stax nb65_param_buffer+NB65_TCP_PAYLOAD_POINTER - ldaxi #nb65_param_buffer - nb65call #NB65_SEND_TCP_PACKET - bcs .error_on_send - jmp .main_polling_loop - -.error_on_send - print #transmission_error - jsr print_errorcode - jmp .get_hostname - -;tcp callback - will be executed whenever data arrives on the TCP connection -tcp_callback - ldaxi #nb65_param_buffer - nb65call #NB65_GET_INPUT_PACKET_INFO - - lda nb65_param_buffer+NB65_PAYLOAD_LENGTH+1 - cmp #$ff - bne .not_eof - lda #1 - sta connection_closed - rts -.not_eof - - ldax nb65_param_buffer+NB65_PAYLOAD_POINTER - stax temp_ptr - lda nb65_param_buffer+NB65_PAYLOAD_LENGTH ;assumes length of inbound data is < 255 - sta buffer_length - dec buffer_length - ldy #0 -.next_byte -; tya -; pha -; lda (temp_ptr),y -; nb65call #NB65_PRINT_HEX -; pla -; tay - lda (temp_ptr),y - tax - lda character_mode - bne .no_conversion_req - lda ascii_to_petscii_table,x - tax -.no_conversion_req - tya - pha - txa - jsr print_a - pla - tay - iny - dec buffer_length - bpl .next_byte - rts - -;look for NB65 signature at location pointed at by AX -look_for_signature subroutine - stax temp_ptr - ldy #3 -.check_one_byte - lda (temp_ptr),y - cmp nb65_signature,y - bne .bad_match - dey - bpl .check_one_byte - clc - rts -.bad_match - sec - rts - -print_ax subroutine - stax temp_ptr - ldy #0 -.next_char - lda (temp_ptr),y - beq .done - jsr print_a - iny - jmp .next_char -.done - rts - -get_key - jsr $ffe4 - cmp #0 - beq get_key - rts - -reset_after_keypress - print #press_a_key_to_continue - jsr get_key - jmp $fce2 ;do a cold start - - -print_errorcode - print #error_code - nb65call #NB65_GET_LAST_ERROR - nb65call #NB65_PRINT_HEX - print_cr - rts - - - -;constants -nb65_api_not_found_message dc.b "ERROR - NB65 API NOT FOUND.",13,0 -incorrect_version dc.b "ERROR - NB65 API MUST BE AT LEAST VERSION 2.",13,0 - -nb65_signature dc.b $4E,$42,$36,$35 ; "NB65" - API signature -initializing dc.b "INITIALIZING ",13,0 -error_code dc.b "ERROR CODE: $",0 -resolving dc.b "RESOLVING ",0 -closing_connection dc.b "CLOSING CONNECTION",13,0 -connecting dc.b "CONNECTING IN ",0 - -ascii dc.b "ASCII",0 -petscii dc.b "PETSCII",0 -mode dc.b " MODE",13,0 -disconnected dc.b 13,"CONNECTION CLOSED",13,0 -remote_host dc.b "REMOTE HOST - BLANK TO QUIT",13,": ",0 -remote_port dc.b "REMOTE PORT - BLANK FOR TELNET DEFAULT",13,": ",0 -char_mode_prompt dc.b "CHARACTER MODE - A=ASCII, P=PETSCII",13,0 -press_a_key_to_continue dc.b "PRESS A KEY TO CONTINUE",13,0 -failed dc.b "FAILED ", 0 -ok dc.b "OK ", 0 -transmission_error dc.b "ERROR WHILE SENDING ",0 -ascii_to_petscii_table - dc.b $00,$01,$02,$03,$04,$05,$06,$07,$14,$09,$0d,$11,$93,$0a,$0e,$0f - dc.b $10,$0b,$12,$13,$08,$15,$16,$17,$18,$19,$1a,$1b,$1c,$1d,$1e,$1f - dc.b $20,$21,$22,$23,$24,$25,$26,$27,$28,$29,$2a,$2b,$2c,$2d,$2e,$2f - dc.b $30,$31,$32,$33,$34,$35,$36,$37,$38,$39,$3a,$3b,$3c,$3d,$3e,$3f - dc.b $40,$c1,$c2,$c3,$c4,$c5,$c6,$c7,$c8,$c9,$ca,$cb,$cc,$cd,$ce,$cf - dc.b $d0,$d1,$d2,$d3,$d4,$d5,$d6,$d7,$d8,$d9,$da,$5b,$5c,$5d,$5e,$5f - dc.b $c0,$41,$42,$43,$44,$45,$46,$47,$48,$49,$4a,$4b,$4c,$4d,$4e,$4f - dc.b $50,$51,$52,$53,$54,$55,$56,$57,$58,$59,$5a,$db,$dc,$dd,$de,$df - dc.b $80,$81,$82,$83,$84,$85,$86,$87,$88,$89,$8a,$8b,$8c,$8d,$8e,$8f - dc.b $90,$91,$92,$0c,$94,$95,$96,$97,$98,$99,$9a,$9b,$9c,$9d,$9e,$9f - dc.b $a0,$a1,$a2,$a3,$a4,$a5,$a6,$a7,$a8,$a9,$aa,$ab,$ac,$ad,$ae,$af - dc.b $b0,$b1,$b2,$b3,$b4,$b5,$b6,$b7,$b8,$b9,$ba,$bb,$bc,$bd,$be,$bf - dc.b $60,$61,$62,$63,$64,$65,$66,$67,$68,$69,$6a,$6b,$6c,$6d,$6e,$6f - dc.b $70,$71,$72,$73,$74,$75,$76,$77,$78,$79,$7a,$7b,$7c,$7d,$7e,$7f - dc.b $e0,$e1,$e2,$e3,$e4,$e5,$e6,$e7,$e8,$e9,$ea,$eb,$ec,$ed,$ee,$ef - dc.b $f0,$f1,$f2,$f3,$f4,$f5,$f6,$f7,$f8,$f9,$fa,$fb,$fc,$fd,$fe,$ff - -petscii_to_ascii_table - dc.b $00,$01,$02,$03,$04,$05,$06,$07,$14,$09,$0d,$11,$93,$0a,$0e,$0f - dc.b $10,$0b,$12,$13,$08,$15,$16,$17,$18,$19,$1a,$1b,$1c,$1d,$1e,$1f - dc.b $20,$21,$22,$23,$24,$25,$26,$27,$28,$29,$2a,$2b,$2c,$2d,$2e,$2f - dc.b $30,$31,$32,$33,$34,$35,$36,$37,$38,$39,$3a,$3b,$3c,$3d,$3e,$3f - dc.b $40,$61,$62,$63,$64,$65,$66,$67,$68,$69,$6a,$6b,$6c,$6d,$6e,$6f - dc.b $70,$71,$72,$73,$74,$75,$76,$77,$78,$79,$7a,$5b,$5c,$5d,$5e,$5f - dc.b $c0,$c1,$c2,$c3,$c4,$c5,$c6,$c7,$c8,$c9,$ca,$cb,$cc,$cd,$ce,$cf - dc.b $d0,$d1,$d2,$d3,$d4,$d5,$d6,$d7,$d8,$d9,$da,$db,$dc,$dd,$de,$df - dc.b $80,$81,$82,$83,$84,$85,$86,$87,$88,$89,$8a,$8b,$8c,$8d,$8e,$8f - dc.b $90,$91,$92,$0c,$94,$95,$96,$97,$98,$99,$9a,$9b,$9c,$9d,$9e,$9f - dc.b $a0,$a1,$a2,$a3,$a4,$a5,$a6,$a7,$a8,$a9,$aa,$ab,$ac,$ad,$ae,$af - dc.b $b0,$b1,$b2,$b3,$b4,$b5,$b6,$b7,$b8,$b9,$ba,$bb,$bc,$bd,$be,$bf - dc.b $60,$41,$42,$43,$44,$45,$46,$47,$48,$49,$4a,$4b,$4c,$4d,$4e,$4f - dc.b $50,$51,$52,$53,$54,$55,$56,$57,$58,$59,$5a,$7b,$7c,$7d,$7e,$7f - dc.b $a0,$a1,$a2,$a3,$a4,$a5,$a6,$a7,$a8,$a9,$aa,$ab,$ac,$ad,$ae,$af - dc.b $b0,$b1,$b2,$b3,$b4,$b5,$b6,$b7,$b8,$b9,$ba,$bb,$bc,$bd,$be,$bf - - -;variables -connection_closed ds.b 1 -character_mode ds.b 1 -buffer_offset: ds.b 1 -nb65_param_buffer DS.B $20 -buffer_length: ds.b 2 - -output_buffer: DS.B $100 diff --git a/client/examples/httpd.asm b/client/examples/httpd.asm new file mode 100644 index 0000000..c0d41c9 --- /dev/null +++ b/client/examples/httpd.asm @@ -0,0 +1,208 @@ +;NB65 API example in DASM format (http://www.atari2600.org/DASM/) + processor 6502 + + include "../inc/nb65_constants.i" + + ;useful macros + mac ldax + lda [{1}] + ldx [{1}]+1 + endm + + mac ldaxi + lda #<[{1}] + ldx #>[{1}] + endm + + mac stax + sta [{1}] + stx [{1}]+1 + endm + + mac cout + lda [{1}] + jsr print_a + endm + + mac print_cr + cout #13 + jsr print_a + endm + + mac nb65call + ldy [{1}] + jsr NB65_DISPATCH_VECTOR + endm + + mac print + + ldaxi [{1}] + ldy #NB65_PRINT_ASCIIZ + jsr NB65_DISPATCH_VECTOR + endm + + +;some routines & zero page variables +print_a equ $ffd2 +temp_ptr equ $FB ; scratch space in page zero + + +;start of code +;NO BASIC stub! needs to be direct booted via TFTP + org $1000 + + ldaxi #NB65_CART_SIGNATURE ;where signature should be in cartridge (if cart is banked in) + jsr look_for_signature + bcc found_nb65_signature + + ldaxi #NB65_RAM_STUB_SIGNATURE ;where signature should be in a RAM stub + jsr look_for_signature + bcs nb65_signature_not_found + jsr NB65_RAM_STUB_ACTIVATE ;we need to turn on NB65 cartridge + jmp found_nb65_signature + +nb65_signature_not_found + ldaxi #nb65_api_not_found_message + jsr print_ax + rts + +found_nb65_signature + + lda NB65_API_VERSION + cmp #02 + bpl .version_ok + print incorrect_version + jmp reset_after_keypress +.version_ok + print #initializing + nb65call #NB65_INITIALIZE + bcc .init_ok + print_cr + print #failed + print_cr + jsr print_errorcode + jmp reset_after_keypress +.init_ok + +;if we got here, we have found the NB65 API and initialised the IP stack +;print out the current configuration + nb65call #NB65_PRINT_IP_CONFIG + +listen_on_port_80 + print #waiting + ldaxi #80 ;port number + stax nb65_param_buffer+NB65_TCP_PORT + stx nb65_param_buffer+NB65_TCP_REMOTE_IP + stx nb65_param_buffer+NB65_TCP_REMOTE_IP+1 + stx nb65_param_buffer+NB65_TCP_REMOTE_IP+2 + stx nb65_param_buffer+NB65_TCP_REMOTE_IP+3 + ldaxi #http_callback + stax nb65_param_buffer+NB65_TCP_CALLBACK + ldaxi #nb65_param_buffer + + nb65call #NB65_TCP_CONNECT ;wait for inbound connect + bcc .connected_ok + print #error_while_waiting + jsr print_errorcode + jmp reset_after_keypress +.connected_ok + print #ok + lda #0 + sta connection_closed + +.main_polling_loop + jsr NB65_PERIODIC_PROCESSING_VECTOR + lda connection_closed + beq .main_polling_loop + jmp listen_on_port_80 + + +;http callback - will be executed whenever data arrives on the TCP connection +http_callback + ldaxi #nb65_param_buffer + nb65call #NB65_GET_INPUT_PACKET_INFO + + lda nb65_param_buffer+NB65_PAYLOAD_LENGTH+1 + cmp #$ff + bne .not_eof + lda #1 + sta connection_closed + rts +.not_eof + + ldax nb65_param_buffer+NB65_PAYLOAD_POINTER + stax temp_ptr + lda nb65_param_buffer+NB65_PAYLOAD_LENGTH + sta buffer_length + rts + +;look for NB65 signature at location pointed at by AX +look_for_signature subroutine + stax temp_ptr + ldy #3 +.check_one_byte + lda (temp_ptr),y + cmp nb65_signature,y + bne .bad_match + dey + bpl .check_one_byte + clc + rts +.bad_match + sec + rts + +print_ax subroutine + stax temp_ptr + ldy #0 +.next_char + lda (temp_ptr),y + beq .done + jsr print_a + iny + jmp .next_char +.done + rts + +get_key + jsr $ffe4 + cmp #0 + beq get_key + rts + +reset_after_keypress + print #press_a_key_to_continue + jsr get_key + jmp $fce2 ;do a cold start + + +print_errorcode + print #error_code + nb65call #NB65_GET_LAST_ERROR + nb65call #NB65_PRINT_HEX + print_cr + rts + + + +;constants +nb65_api_not_found_message dc.b "ERROR - NB65 API NOT FOUND.",13,0 +incorrect_version dc.b "ERROR - NB65 API MUST BE AT LEAST VERSION 2.",13,0 + +nb65_signature dc.b $4E,$42,$36,$35 ; "NB65" - API signature +initializing dc.b "INITIALIZING ",13,0 +error_code dc.b "ERROR CODE: $",0 +error_while_waiting dc.b "ERROR WHILE " +waiting dc.b "WAITING FOR CLIENT CONNECTION",13,0 +press_a_key_to_continue dc.b "PRESS ANY KEY TO CONTINUE",0 +mode dc.b " MODE",13,0 +disconnected dc.b 13,"CONNECTION CLOSED",13,0 +failed dc.b "FAILED ", 0 +ok dc.b "OK ", 0 +transmission_error dc.b "ERROR WHILE SENDING ",0 +;variables +connection_closed ds.b 1 +nb65_param_buffer DS.B $20 +buffer_length: ds.b 2 +buffer_pointer: ds.b 2 +scratch_buffer: DS.B $1000 diff --git a/client/inc/gopher.i b/client/inc/gopher.i index b5287fa..88e3d61 100644 --- a/client/inc/gopher.i +++ b/client/inc/gopher.i @@ -33,6 +33,7 @@ .import cls .import get_filtered_input .import filter_dns + .import filter_text .segment "IP65ZP" : zeropage @@ -77,9 +78,11 @@ RESOURCE_HOSTNAME_MAX_LENGTH=64 current_resource: resource_hostname: .res RESOURCE_HOSTNAME_MAX_LENGTH resource_port: .res 2 -resource_selector: .res 160 +resource_selector: .res 128 resource_selector_length: .res 1 displayed_resource_type: .res 1 +query_string: .res 32 +query_string_length: .res 1 RESOURCE_HISTORY_ENTRIES=8 resource_history: @@ -144,8 +147,11 @@ display_resource_in_buffer: @next_line: jsr get_next_byte + cmp #0 + beq @last_line cmp #'.' bne @not_last_line +@last_line: lda #1 sta this_is_last_page jmp @done @@ -156,6 +162,8 @@ display_resource_in_buffer: beq @standard_resource cmp #'1' beq @standard_resource + cmp #'7' + beq @standard_resource ;if we got here, we know not what it is jmp @skip_to_end_of_line @@ -316,6 +324,7 @@ select_resource_from_current_directory: lda (buffer_ptr),y sta displayed_resource_type + @skip_to_next_tab: iny beq @done_skipping_over_tab @@ -380,6 +389,32 @@ select_resource_from_current_directory: : jmp @parse_port @end_of_port: + + lda displayed_resource_type + + cmp #'7' ;is it a 'search' resource? + bne @done + + ldax #query + jsr print +@get_query_string: + ldy #32 ;max chars + ldax #filter_text + jsr get_filtered_input + bcs @get_query_string + stax buffer_ptr + jsr print_cr + ldy #0 + sty query_string_length + lda #09 +@copy_one_char: + sta query_string,y + inc query_string_length + lda (buffer_ptr),y + beq @done_query_string + iny + jmp @copy_one_char +@done_query_string: @done: add_resource_to_history_and_display: @@ -461,8 +496,9 @@ load_resource_into_buffer: bcs :+ jsr dns_resolve : - bcs @error - + bcc @no_error + jmp @error +@no_error: ldx #3 ; save IP address just retrieved : lda dns_ip,x sta tcp_connect_ip,x @@ -493,6 +529,17 @@ load_resource_into_buffer: ldax #resource_selector jsr tcp_send + + ;send the tab and query string (if supplied) + lda displayed_resource_type + cmp #'7' ;is it a 'search' resource? + bne @send_cr_lf + ldax query_string_length + sta tcp_send_data_len + ldax #query_string + jsr tcp_send + +@send_cr_lf: ;send the CR/LF after the connector ldax #2 sta tcp_send_data_len @@ -552,10 +599,6 @@ gopher_download_callback: lda #'*' jsr print_a -; lda tcp_inbound_data_length+1 -; jsr print_hex -; lda tcp_inbound_data_length -; jsr print_hex rts @@ -647,6 +690,9 @@ server: .byte "SERVER :",0 selector: .byte "SELECTOR :",0 +query: +.byte "QUERY :",0 + any_key_to_continue: .byte "PRESS ANY KEY TO CONTINUE",0 diff --git a/client/inc/telnet.i b/client/inc/telnet.i index b2f30c9..124e766 100644 --- a/client/inc/telnet.i +++ b/client/inc/telnet.i @@ -95,21 +95,20 @@ telnet_main_entry: ldax #mode jsr print - ; tcp_connect_ip: destination ip address (4 bytes) -; AX: destination port (2 bytes) -; tcp_callback: vector to call when data arrives on this connection - telnet_connect: ldax #telnet_callback - stax tcp_callback + stax nb65_param_buffer+NB65_TCP_CALLBACK ldx #3 @copy_dest_ip: lda telnet_ip,x - sta tcp_connect_ip,x + sta nb65_param_buffer+NB65_TCP_REMOTE_IP,x dex bpl @copy_dest_ip ldax telnet_port - jsr tcp_connect + stax nb65_param_buffer+NB65_TCP_PORT + ldax #nb65_param_buffer + nb65call #NB65_TCP_CONNECT + bcc @connect_ok jsr print_cr print_failed diff --git a/client/ip65/function_dispatcher.s b/client/ip65/function_dispatcher.s index f8d6aa3..72b73b1 100644 --- a/client/ip65/function_dispatcher.s +++ b/client/ip65/function_dispatcher.s @@ -434,16 +434,23 @@ ip_configured: .segment "TCP_VARS" port_number: .res 2 + nonzero_octets: .res 1 .code cpy #NB65_TCP_CONNECT - bne :+ + bne :+ .import tcp_connect .import tcp_callback .import tcp_connect_ip + .import tcp_listen ldy #3 + lda #0 + sta nonzero_octets @copy_dest_ip: lda (nb65_params),y + beq @octet_was_zero + inc nonzero_octets +@octet_was_zero: sta tcp_connect_ip,y dey bpl @copy_dest_ip @@ -460,6 +467,11 @@ ip_configured: tax dey lda (nb65_params),y + ldy nonzero_octets + bne @outbound_tcp_connection + jmp tcp_listen + +@outbound_tcp_connection: jmp tcp_connect : diff --git a/client/ip65/tcp.s b/client/ip65/tcp.s index f4716f1..db51519 100644 --- a/client/ip65/tcp.s +++ b/client/ip65/tcp.s @@ -24,6 +24,7 @@ MAX_TCP_PACKETS_SENT=8 ;timeout after sending 8 messages will be about 7 sec .export tcp_send_data_len .export tcp_send .export tcp_close +.export tcp_listen .export tcp_inbound_data_ptr .export tcp_inbound_data_length @@ -68,9 +69,6 @@ MAX_TCP_PACKETS_SENT=8 ;timeout after sending 8 messages will be about 7 sec .import cfg_ip - -.segment "TCP_VARS" - tcp_cxn_state_closed = 0 tcp_cxn_state_listening = 1 ;(waiting for an inbound SYN) tcp_cxn_state_syn_sent = 2 ;(waiting for an inbound SYN/ACK) @@ -124,6 +122,8 @@ tcp_callback: .res 2 ;vector to routine to be called when data is received over tcp_flags: .res 1 tcp_fin_sent: .res 1 +tcp_listen_port: .res 1 + tcp_inbound_data_ptr: .res 2 ;pointer to data just recieved over tcp connection tcp_inbound_data_length: .res 2 ;length of data just received over tcp connection ;(if this is $ffff, that means "end of file", i.e. remote end has closed connection) @@ -141,6 +141,7 @@ tcp_timer: .res 1 tcp_loop_count: .res 1 tcp_packet_sent_count: .res 1 + .code ; initialize tcp @@ -155,6 +156,40 @@ tcp_init: jmp_to_callback: jmp (tcp_callback) +;listen for an inbound tcp connection +;this is a 'blocking' call, i.e. it will not return until a connection has been made +;inputs: +; AX: destination port (2 bytes) +; tcp_callback: vector to call when data arrives on this connection +;outputs: +; carry flag is set if an error occured, clear otherwise +tcp_listen: + stax tcp_listen_port + lda #tcp_cxn_state_listening + sta tcp_state + lda #0 ;reset the "packet sent" counter + sta tcp_packet_sent_count + sta tcp_fin_sent + + ;set the low word of seq number to $0000, high word to something random + sta tcp_connect_sequence_number + sta tcp_connect_sequence_number+1 + jsr ip65_random_word + stax tcp_connect_sequence_number+2 +@listen_loop: + jsr ip65_process + jsr check_for_abort_key + bcc @no_abort + lda #NB65_ERROR_ABORTED_BY_USER + sta ip65_error + rts +@no_abort: + lda #tcp_cxn_state_listening + cmp tcp_state + beq @listen_loop + clc + rts + ;make outbound tcp connection ;inputs: ; tcp_connect_ip: destination ip address (4 bytes) @@ -832,9 +867,60 @@ tcp_process: lda tcp_inp+tcp_flags_field cmp #tcp_flag_SYN - bne @not_syn -;for the moment, inbound connections not accepted. so send a RST + beq @syn + jmp @not_syn +@syn: + ;for the moment, inbound connections not accepted. so send a RST + + ;is this the port we are listening on? + lda tcp_inp+tcp_dest_port+1 + cmp tcp_listen_port + bne @decline_syn_with_reset + lda tcp_inp+tcp_dest_port + cmp tcp_listen_port+1 + bne @decline_syn_with_reset + + ;it's the right port - are we actually waiting for a connecting? + lda #tcp_cxn_state_listening + cmp tcp_state + beq @this_is_connection_we_are_waiting_for + + rts ;if we've currently got a connection open, then ignore any new requests + ;the sender will timeout and resend the SYN, by which time we may be + ;ready to accept it again. + +@this_is_connection_we_are_waiting_for: + ; copy sequence number to ack (in reverse order) and remote IP + ldx #3 + ldy #0 +: lda tcp_inp + tcp_seq,y + sta tcp_connect_ack_number,x + lda ip_inp+ip_src,x + sta tcp_connect_ip,x + iny + dex + bpl :- + + ;copy ports + ldax tcp_listen_port + stax tcp_connect_local_port + + lda tcp_inp+tcp_src_port+1 + sta tcp_connect_remote_port + lda tcp_inp+tcp_src_port + sta tcp_connect_remote_port+1 + + lda #tcp_cxn_state_established + sta tcp_state + + ldax #tcp_connect_ack_number + stax acc32 + ldax #$0001 ; + jsr add_16_32 ;increment the ACK counter by 1, for the SYN we just received + lda #tcp_flag_SYN+tcp_flag_ACK + jmp @send_packet + @decline_syn_with_reset: ;create a RST packet ldx #3 ; copy sequence number to ack (in reverse order) diff --git a/client/test/Makefile b/client/test/Makefile index b3dde21..92ce1bc 100644 --- a/client/test/Makefile +++ b/client/test/Makefile @@ -42,8 +42,8 @@ all: \ test_tcp.prg: test_tcp.o $(IP65TCPLIB) $(C64PROGLIB) $(INCFILES) ../cfg/c64prg.cfg $(LD) -m test_tcp.map -vm -C ../cfg/c64prg.cfg -o test_tcp.prg $(AFLAGS) $< $(IP65TCPLIB) $(C64PROGLIB) -gopher_browser.prg: gopher_browser.o $(IP65TCPLIB) $(C64PROGLIB) $(INCFILES) ../cfg/c64prg.cfg ../inc/gopher.i - $(LD) -m gopher_browser.map -vm -C ../cfg/c64prg.cfg -o gopher_browser.prg $(AFLAGS) $< $(IP65TCPLIB) $(C64PROGLIB) +#gopher_browser.prg: gopher_browser.o $(IP65TCPLIB) $(C64PROGLIB) $(INCFILES) ../cfg/c64prg.cfg ../inc/gopher.i +# $(LD) -m gopher_browser.map -vm -C ../cfg/c64prg.cfg -o gopher_browser.prg $(AFLAGS) $< $(IP65TCPLIB) $(C64PROGLIB) %.pg2: %.o $(IP65LIB) $(APPLE2PROGLIB) $(INCFILES) ../cfg/a2bin.cfg diff --git a/doc/nb65_api_technical_reference.doc b/doc/nb65_api_technical_reference.doc index fb757ed..ec91eb9 100644 Binary files a/doc/nb65_api_technical_reference.doc and b/doc/nb65_api_technical_reference.doc differ