From 76ae659e456525358cd562755f6a3d63876dcf93 Mon Sep 17 00:00:00 2001 From: jonnosan Date: Sat, 18 Jul 2009 13:24:52 +0000 Subject: [PATCH] git-svn-id: http://svn.code.sf.net/p/netboot65/code@161 93682198-c243-4bdb-bd91-e943c89aac3b --- client/examples/dumb_telnet.asm | 386 --------------------------- client/examples/httpd.asm | 208 +++++++++++++++ client/inc/gopher.i | 60 ++++- client/inc/telnet.i | 13 +- client/ip65/function_dispatcher.s | 14 +- client/ip65/tcp.s | 96 ++++++- client/test/Makefile | 4 +- doc/nb65_api_technical_reference.doc | Bin 131072 -> 131584 bytes 8 files changed, 373 insertions(+), 408 deletions(-) delete mode 100644 client/examples/dumb_telnet.asm create mode 100644 client/examples/httpd.asm 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 fb757edad4708b5cf7d33fcfda04468bc4cbc208..ec91eb9ffa110dd0ed5de84689f0160b54fc6173 100644 GIT binary patch delta 9385 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 Xm^W_fbbZ>KRYUzH_thHRpw9mSu>84u