1 ;;;; Lysiane Bouchard - Vincent St-Amour
4 ;; TODO what really is in there
5 ;;; - connection structure and related operations
6 ;;; - operations on the current connection
7 ;;; - external operations on a connection
9 ;;; Note : connections are used only with tcp
10 ;; TODO merge all this with tcp ? it's only used with tcp. would result in a huge file, though
12 ;; connection structures are represented as vectors :
14 ;; -0: informations (u8vector)
16 ;; - which of the stack's IP addresses uses the connection
17 ;; - peer's IP address
18 ;; - peer's source port number
19 ;; - peer's MAC address
20 ;; - whether the connection is active or not
21 ;; - the acknoledgement number at which the stack is for this connection
22 ;; - number of self-ack units TODO what's that ?
23 ;; - the acknoledgement number at which our peer is
24 ;; - number of attemps so far TODO make sure it's so far
25 ;; Note : storing our port number in the connection structure is unecessary
26 ;; -1: timestamp (integer) TODO which unit ?
27 ;; -2: input buffer (u8vector)
28 ;; -3: output buffer (u8vector)
29 ;; -4: state function (function)
30 ;; defines the connection's behaviour at a given time.
32 (define conn-timestamp 1)
34 (define conn-output 3)
35 (define conn-state-function 4)
38 (define conn-self-ip 0)
39 (define conn-peer-ip 4) ;; TODO see if it's necessary or if a simple swap can do the job
40 (define conn-peer-portnum 8) ;; TODO same here
41 (define conn-peer-mac 10) ;; TODO same here
42 (define conn-active? 16) ; boolean ;: TODO find a way to do without
43 (define tcp-self-seqnum 17)
44 (define tcp-self-ack-units 21) ;; TODO what's that ?
45 (define tcp-peer-seqnum 22) ;; TODO add conn- before ?
46 (define tcp-attempts-count 26)
47 (define tcp-infos-size 27)
51 ;; TODO have conn-ref and offsets, just like pkt, so we save the getters / setters
52 (define (conn-info-ref conn i) (u8vector-ref (vector-ref conn conn-info) i)) ;; TODO get rid ?
53 (define (conn-info-set! conn i val) (u8vector-set! (vector-ref conn conn-info) i val))
54 (define (set-timestamp!) (vector-set! curr-conn conn-timestamp (get-current-time))) ;; TODO add curr to name ?
55 (define (get-curr-elapsed-time) (get-elapsed-time (vector-ref curr-conn conn-timestamp)))
57 (define (=conn-info-pkt? pkt-idx c c-idx n)
58 (u8vector-equal-field? pkt pkt-idx (vector-ref c conn-info) c-idx n))
61 ;; creates a new connection with the info in the incoming packet
62 ;; it becomes the current connection
63 (define (new-conn) ;; TODO used only once
64 ;; TODO clean this up a bit, are some operations redundant ? are all necessary ?
65 (set! curr-conn (vector (make-u8vector tcp-infos-size 0)
67 (vector 0 0 (make-u8vector tcp-input-size 0))
68 (vector 0 0 (make-u8vector tcp-output-size 0))
70 (add-conn-to-curr-port curr-conn) ;; TODO is it always the curr-conn ? if so, simplify
71 (copy-pkt->curr-conn-info ip-destination-ip conn-self-ip 4) ;; TODO useful ?
72 (copy-pkt->curr-conn-info tcp-source-portnum conn-peer-portnum 2)
73 (copy-pkt->curr-conn-info ip-source-ip conn-peer-ip 4) ;; TODO why these 2 ? we can probably just swap when we create the response, no ?
74 (copy-pkt->curr-conn-info ethernet-source-mac conn-peer-mac 6) ;; TODO do we need this ? we can simply answer to the sender
76 (u8vector-copy! (tcp-isn) 0 pkt tcp-self-seqnum 4)
77 (copy-pkt->curr-conn-info tcp-seqnum tcp-peer-seqnum 4))
80 ;; an input/output buffers is represented as a vector
81 ;; -0: amount of bytes stored in the buffer (integer)
82 ;; -1: pointer to the next free space in the buffer (integer)
83 ;; -2: the buffer itself (u8vector)
84 ;; the length is found in conf.scm and can be different for input and
85 ;; output buffers, with a maximum of 256 bytes
86 ;; TODO this is all broken, we'd need 2 pointers.
87 ;; for output buffer, one to show where to add the next data, and another to show the 1st unsent (or not acked)
88 ;; for input, one for the stack to see where it can add, and the other that shows where the app reads
89 ;; FIX THIS NOTHING CAN WORK WITHOUT (perhaps it does by subtrating amount, but it's disgusting)
90 ;; TODO for efficiency reasons, maybe keep the free space along with the amount, so we don't calculate it every time
92 (define (buf-size buf) (u8vector-length (vector-ref 2 buf)))
93 ;; TODO would be faster to look at the conf for a user, we can't since we don't know if it's an input or output buffer, maybe store a flag for this ? would not really be faster than getting the length, since picobit stores it with the vector
94 ;; TODO maybe we can see which of the connection buffers is used
96 (define (curr-buf-get-amount) (vector-ref (vector-ref curr-conn conn-output) 0))
97 ;; TODO change name so we see it's for an output buffer
98 ;; TODO only used once, and in a debatable way
99 (define (buf-inc-amount buf n) (vector-set! buf 0 (+ (vector-ref buf 0) n)))
100 ;; TODO not really inc/dec since it's not 1 but n
101 (define (buf-dec-amount buf n) (vector-set! buf 0 (- (vector-ref buf 0) n)))
102 (define (buf-inc-pointer buf n)
103 (vector-set! buf 1 (modulo (+ (vector-ref buf 1) n) (buf-size buf))))
105 (define (buf-free-space buf) (- (buf-size buf) (vector-ref buf 0)))
106 ;; TODO this might be used for redundant checks, if so, fix
108 ;; consumes n bytes of data from the buffer, so it can be overwritten
109 (define (buf-consume buf n) ;; TODO name ? and used only once, maybe will be more in the future
110 (if (>= n (vector-ref buf 0))
111 (begin (vector-set! buf 0 0) ; set amount and pointer to 0
112 (vector-set! buf 1 0))
113 (begin (buf-dec-amount buf n)
114 (buf-inc-pointer buf n))))
116 ;; TODO move with other info functions
117 (define (copy-pkt->curr-conn-info pkt-idx conn-idx n) ;; TODO standardise name
118 (u8vector-copy! pkt pkt-idx (vector-ref curr-conn conn-info) conn-idx n))
119 (define (copy-curr-conn-info->pkt pkt-idx conn-idx n) ;; TODO standardise name
120 (u8vector-copy! (vector-ref curr-conn conn-info) conn-idx pkt pkt-idx n))
123 ;; TODO we're still doomed if offset if more than 24 bits
124 ;; add offset to the field of n bytes that begins at idx
125 ;; TODO is this used often enough to be worth it ?
126 ;; TODO not really an increment
127 (define (increment-curr-conn-info! idx n offset)
128 (u8vector-increment! (vector-ref curr-conn conn-info) idx n offset))
130 ;; Links the current connection with the corresponding application
131 ;; sends the connection to the application, which can then access it at
133 (define (link-to-app) ((conf-ref curr-port conf-reception) curr-conn)) ;; TODO used only once, in tcp INLINE
136 ;; detach the current connection from the current port
137 (define (detach-curr-conn) ;; TODO put with ports ?
138 (detach-curr-conn-loop curr-port))
139 (define (detach-curr-conn-loop lst) ;; TODO have a ! in the name
140 (if (pair? (cdr lst)) ;; TODO have an accessor for conf and conns ? but this is not really a conn
141 (if (eq? (cadr lst) curr-conn)
142 (set-cdr! lst (cddr lst))
143 (detach-curr-conn-loop (cdr lst)))))
146 ;; copy n bytes from a circular buffer to a byte vector
147 ;; this consumes the data from the buffer, it cannot be read again
148 ;; we are guaranteed that n cannot be greater than the number of bytes that can
150 (define (copy-buffer->u8vector! buf vec i-vec n)
151 ;; the copy starts at the current location in the buffer
152 (let ((i-buf (vector-ref buf 1))
153 (size (buf-size buf))
154 (buf-data (vector-ref buf 2)))
155 (if (<= (+ i-buf n) size) ; wraparound
156 (let ((n1 (- size i-buf 1)))
157 (u8vector-copy! buf-data i-buf vec i-vec n1)
158 (u8vector-copy! buf-data 0 vec (+ i-vec n1) (- n n1)))
159 (u8vector-copy! buf-data i-buf vec i-vec n))
160 (buf-inc-pointer buf n)))
161 ;; TODO put with other buffer functions
163 ;; TODO does this obsolete other functions ?
164 ;; copy n bytes of data from a vector to a circular buffer
165 ;; once again, we are guaranteed that the copy is valid, that the buffer has
166 ;; enough room for the new data
167 ;; TODO a lot in common with the previous, find a way to merge ?
168 ;; returns the offset of the next empty space in the buffer. TODO really ?
169 ;; if the buffer is full, returns #f
170 (define (copy-u8vector->buffer! vec i-vec buf n)
171 (let ((i-buf (vector-ref buf 1))
172 (size (buf-size buf))
173 (buf-data (vector-ref buf 2)))
174 (if (<= (+ i-buf n) size) ; wraparound
175 (let ((n1 (- size i-buf 1))) ;; TODO off-by-one ?
176 (u8vector-copy! vec i-vec buf-data i-buf n1)
177 (u8vector-copy! vec (+ i-vec n1) buf-data 0 (- n n1)))
178 (u8vector-copy! vec i-vec buf i-buf n))
179 (buf-inc-amount buf n)))
185 ;; read n input bytes from the connection c, if n is omitted, read all
186 ;; TODO the changes were not tested
187 (define (tcp-read c . n) ;; TODO quite ugly
189 ;; TODO visit the connection ? maybe not needed, we have received data, and there is nothing to de really
190 (let* ((buf (vector-ref c conn-input))
191 (available (vector-ref buf 0)) ; amount of data in the buffer
192 (amount (if (null? n)
194 (min available (car n)))))
196 (let ((data (make-u8vector amount 0)) (i 0))
197 (copy-buffer->u8vector! buf data 0 amount)
198 data)) ; TODO change one of the 2 pointers
199 ((not (conn-info-ref c conn-active?)) 'end-of-input)
202 ;; write bytes (in a u8vector) to c, returns the number of bytes written
203 (define (tcp-write c data)
205 (if (conn-info-ref c conn-active?)
206 (let* ((buf (vector-ref c conn-output))
207 (amount (min (buf-free-space buf) (u8vector-length data))))
209 (begin ;; TODO change one of the 2 pointers, once we have them
210 (copy-u8vector->buffer! data 0 buf amount)
213 'connection-closed)) ; error, we try to write to a closed connection
214 ;; TODO after that, visit the connection
217 ;; API function to terminate a connection
218 (define (tcp-close conn . abort?)
219 (set! curr-conn conn)
220 (conn-info-set! conn conn-active? #f)
221 (if abort? (tcp-abort) (detach-curr-conn)))