Random cleanup.
[small-scheme-stack.git] / conn.scm
blob39367e2e5d12614dfe81e39b7be448db45c39d13
1 ;;;; Lysiane Bouchard - Vincent St-Amour
2 ;;;; conn.scm
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 :
13 ;; FORMAT: 6 fields:
14 ;; -0: informations (u8vector)
15 ;;     contains:
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.
31 (define conn-info           0)
32 (define conn-timestamp      1)
33 (define conn-input          2)
34 (define conn-output         3)
35 (define conn-state-function 4)
37 ;; informations
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)
50 ;; general operations
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)
66                           #f
67                           (vector 0 0 (make-u8vector tcp-input-size 0))
68                           (vector 0 0 (make-u8vector tcp-output-size 0))
69                           tcp-syn-recv))
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
75   (set-timestamp!)
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
132 ;; any time
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
149 ;; actually be read
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)))
183 ;;; TCP API
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
188   (set! curr-conn c)
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)
193                      available
194                      (min available (car n)))))
195     (cond ((> amount 0)
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)
200           (else #f))))
202 ;; write bytes (in a u8vector) to c, returns the number of bytes written
203 (define (tcp-write c data)
204   (set! curr-conn c)
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))))
208         (if (> amount 0)
209             (begin ;; TODO change one of the 2 pointers, once we have them
210               (copy-u8vector->buffer! data 0 buf amount)
211               amount)
212             #f))
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)))