Rev 922 | Rev 1019 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
431 | serge | 1 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
2 | ;; ;; |
||
983 | diamond | 3 | ;; Copyright (C) KolibriOS team 2004-2008. All rights reserved. ;; |
431 | serge | 4 | ;; Distributed under terms of the GNU General Public License ;; |
5 | ;; ;; |
||
6 | ;; SOCKET.INC ;; |
||
7 | ;; ;; |
||
8 | ;; Sockets constants, structures and functions ;; |
||
9 | ;; ;; |
||
10 | ;; This file contains the following: ;; |
||
11 | ;; is_localport_unused ;; |
||
12 | ;; get_free_socket ;; |
||
13 | ;; socket_open ;; |
||
14 | ;; socket_open_tcp ;; |
||
15 | ;; socket_close ;; |
||
16 | ;; socket_close_tcp ;; |
||
17 | ;; socket_poll ;; |
||
18 | ;; socket_status ;; |
||
19 | ;; socket_read ;; |
||
20 | ;; socket_write ;; |
||
21 | ;; socket_write_tcp ;; |
||
22 | ;; ;; |
||
23 | ;; ;; |
||
24 | ;; Changes history: ;; |
||
25 | ;; 22.09.2003 - [Mike Hibbett] : mikeh@oceanfree.net ;; |
||
26 | ;; 11.11.2006 - [Johnny_B] and [smb] ;; |
||
27 | ;; ;; |
||
28 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
||
261 | hidnplayr | 29 | |
593 | mikedld | 30 | $Revision: 983 $ |
31 | |||
922 | mikedld | 32 | ; socket data structure |
33 | struct SOCKET |
||
34 | .PrevPtr dd ? ; pointer to previous socket in list |
||
35 | .NextPtr dd ? ; pointer to next socket in list |
||
36 | .Number dd ? ; socket number (unique within single process) |
||
37 | .PID dd ? ; application process id |
||
38 | .LocalIP dd ? ; local IP address |
||
39 | .LocalPort dw ? ; local port |
||
40 | .RemoteIP dd ? ; remote IP address |
||
41 | .RemotePort dw ? ; remote port |
||
42 | .OrigRemoteIP dd ? ; original remote IP address (used to reset to LISTEN state) |
||
43 | .OrigRemotePort dw ? ; original remote port (used to reset to LISTEN state) |
||
44 | .rxDataCount dd ? ; rx data count |
||
45 | .TCBState dd ? ; TCB state |
||
46 | .TCBTimer dd ? ; TCB timer (seconds) |
||
47 | .ISS dd ? ; initial send sequence |
||
48 | .IRS dd ? ; initial receive sequence |
||
49 | .SND_UNA dd ? ; sequence number of unack'ed sent packets |
||
50 | .SND_NXT dd ? ; bext send sequence number to use |
||
51 | .SND_WND dd ? ; send window |
||
52 | .RCV_NXT dd ? ; next receive sequence number to use |
||
53 | .RCV_WND dd ? ; receive window |
||
54 | .SEG_LEN dd ? ; segment length |
||
55 | .SEG_WND dd ? ; segment window |
||
56 | .wndsizeTimer dd ? ; window size timer |
||
57 | .rxData dd ? ; receive data buffer here |
||
58 | ends |
||
593 | mikedld | 59 | |
922 | mikedld | 60 | ; TCP opening modes |
61 | SOCKET_PASSIVE = 0 |
||
62 | SOCKET_ACTIVE = 1 |
||
261 | hidnplayr | 63 | |
922 | mikedld | 64 | ; socket types |
65 | SOCK_STREAM = 1 |
||
66 | SOCK_DGRAM = 2 |
||
261 | hidnplayr | 67 | |
922 | mikedld | 68 | ;; Allocate memory for socket data and put new socket into the list |
69 | ; Newly created socket is initialized with calling PID and number and |
||
70 | ; put into beginning of list (which is a fastest way). |
||
71 | ; |
||
72 | ; @return socket structure address in EAX |
||
73 | ;; |
||
907 | mikedld | 74 | proc net_socket_alloc stdcall uses ebx ecx edx edi |
75 | stdcall kernel_alloc, SOCKETBUFFSIZE |
||
76 | DEBUGF 1, "K : net_socket_alloc (0x%x)\n", eax |
||
922 | mikedld | 77 | ; check if we can allocate needed amount of memory |
907 | mikedld | 78 | or eax, eax |
79 | jz .exit |
||
80 | |||
922 | mikedld | 81 | ; zero-initialize allocated memory |
907 | mikedld | 82 | push eax |
83 | mov edi, eax |
||
84 | mov ecx, SOCKETBUFFSIZE / 4 |
||
85 | cld |
||
86 | xor eax, eax |
||
87 | rep stosd |
||
88 | pop eax |
||
89 | |||
922 | mikedld | 90 | ; add socket to the list by changing pointers |
907 | mikedld | 91 | mov ebx, net_sockets |
92 | push [ebx + SOCKET.NextPtr] |
||
93 | mov [ebx + SOCKET.NextPtr], eax |
||
94 | mov [eax + SOCKET.PrevPtr], ebx |
||
95 | pop ebx |
||
96 | mov [eax + SOCKET.NextPtr], ebx |
||
97 | or ebx, ebx |
||
98 | jz @f |
||
99 | mov [ebx + SOCKET.PrevPtr], eax |
||
100 | |||
922 | mikedld | 101 | @@: ; set socket owner PID to the one of calling process |
102 | mov ebx, [TASK_BASE] |
||
907 | mikedld | 103 | mov ebx, [ebx + TASKDATA.pid] |
104 | mov [eax + SOCKET.PID], ebx |
||
105 | |||
922 | mikedld | 106 | ; find first free socket number and use it |
107 | ;mov edx, ebx |
||
108 | mov ebx, net_sockets |
||
109 | xor ecx, ecx |
||
110 | .next_socket_number: |
||
111 | inc ecx |
||
112 | .next_socket: |
||
113 | mov ebx, [ebx + SOCKET.NextPtr] |
||
114 | or ebx, ebx |
||
115 | jz .last_socket_number |
||
116 | cmp [ebx + SOCKET.Number], ecx |
||
117 | jne .next_socket |
||
118 | ;cmp [ebx + SOCKET.PID], edx |
||
119 | ;jne .next_socket |
||
120 | mov ebx, net_sockets |
||
121 | jmp .next_socket_number |
||
122 | |||
123 | .last_socket_number: |
||
124 | mov [eax + SOCKET.Number], ecx |
||
125 | |||
907 | mikedld | 126 | .exit: |
127 | ret |
||
128 | endp |
||
129 | |||
922 | mikedld | 130 | ;; Free socket data memory and pop socket off the list |
131 | ; |
||
132 | ; @param sockAddr is a socket structure address |
||
133 | ;; |
||
134 | proc net_socket_free stdcall uses ebx ecx edx, sockAddr:DWORD |
||
135 | mov eax, [sockAddr] |
||
907 | mikedld | 136 | DEBUGF 1, "K : net_socket_free (0x%x)\n", eax |
922 | mikedld | 137 | ; check if we got something similar to socket structure address |
907 | mikedld | 138 | or eax, eax |
139 | jz .error |
||
140 | |||
922 | mikedld | 141 | ; make sure sockAddr is one of the socket addresses in the list |
907 | mikedld | 142 | mov ebx, net_sockets |
922 | mikedld | 143 | ;mov ecx, [TASK_BASE] |
144 | ;mov ecx, [ecx + TASKDATA.pid] |
||
907 | mikedld | 145 | .next_socket: |
146 | mov ebx, [ebx + SOCKET.NextPtr] |
||
147 | or ebx, ebx |
||
148 | jz .error |
||
149 | cmp ebx, eax |
||
150 | jne .next_socket |
||
151 | ;cmp [ebx + SOCKET.PID], ecx |
||
152 | ;jne .next_socket |
||
153 | |||
922 | mikedld | 154 | ; okay, we found the correct one |
155 | ; remove it from the list first, changing pointers |
||
907 | mikedld | 156 | mov ebx, [eax + SOCKET.NextPtr] |
157 | mov eax, [eax + SOCKET.PrevPtr] |
||
158 | mov [eax + SOCKET.NextPtr], ebx |
||
159 | or ebx, ebx |
||
160 | jz @f |
||
161 | mov [ebx + SOCKET.PrevPtr], eax |
||
162 | |||
922 | mikedld | 163 | @@: ; and finally free the memory structure used |
164 | stdcall kernel_free, [sockAddr] |
||
907 | mikedld | 165 | ret |
166 | |||
167 | .error: |
||
168 | DEBUGF 1, "K : failed\n" |
||
169 | ret |
||
170 | endp |
||
171 | |||
922 | mikedld | 172 | ;; Get socket structure address by its number |
173 | ; Scan through sockets list to find the socket with specified number. |
||
174 | ; This proc uses SOCKET.PID indirectly to check if socket is owned by |
||
175 | ; calling process. |
||
176 | ; |
||
177 | ; @param sockNum is a socket number |
||
178 | ; @return socket structure address or 0 (not found) in EAX |
||
179 | ;; |
||
180 | proc net_socket_num_to_addr stdcall uses ebx ecx, sockNum:DWORD |
||
181 | mov eax, [sockNum] |
||
182 | ; check if we got something similar to socket number |
||
183 | or eax, eax |
||
184 | jz .error |
||
185 | |||
186 | ; scan through sockets list |
||
907 | mikedld | 187 | mov ebx, net_sockets |
922 | mikedld | 188 | ;mov ecx, [TASK_BASE] |
189 | ;mov ecx, [ecx + TASKDATA.pid] |
||
907 | mikedld | 190 | .next_socket: |
191 | mov ebx, [ebx + SOCKET.NextPtr] |
||
192 | or ebx, ebx |
||
193 | jz .error |
||
922 | mikedld | 194 | cmp [ebx + SOCKET.Number], eax |
907 | mikedld | 195 | jne .next_socket |
196 | ;cmp [ebx + SOCKET.PID], ecx |
||
197 | ;jne .next_socket |
||
922 | mikedld | 198 | |
199 | ; okay, we found the correct one |
||
200 | mov eax, ebx |
||
907 | mikedld | 201 | ret |
202 | |||
203 | .error: |
||
204 | xor eax, eax |
||
205 | ret |
||
206 | endp |
||
207 | |||
922 | mikedld | 208 | ;; Get socket number by its structure address |
209 | ; Scan through sockets list to find the socket with specified address. |
||
210 | ; This proc uses SOCKET.PID indirectly to check if socket is owned by |
||
211 | ; calling process. |
||
212 | ; |
||
213 | ; @param sockAddr is a socket structure address |
||
214 | ; @return socket number (SOCKET.Number) or 0 (not found) in EAX |
||
215 | ;; |
||
216 | proc net_socket_addr_to_num stdcall uses ebx ecx, sockAddr:DWORD |
||
217 | mov eax, [sockAddr] |
||
218 | ; check if we got something similar to socket structure address |
||
219 | or eax, eax |
||
220 | jz .error |
||
221 | |||
222 | ; scan through sockets list |
||
907 | mikedld | 223 | mov ebx, net_sockets |
922 | mikedld | 224 | ;mov ecx, [TASK_BASE] |
225 | ;mov ecx, [ecx + TASKDATA.pid] |
||
907 | mikedld | 226 | .next_socket: |
227 | mov ebx, [ebx + SOCKET.NextPtr] |
||
228 | or ebx, ebx |
||
229 | jz .error |
||
230 | cmp ebx, eax |
||
231 | jne .next_socket |
||
232 | ;cmp [ebx + SOCKET.PID], ecx |
||
233 | ;jne .next_socket |
||
922 | mikedld | 234 | |
235 | ; okay, we found the correct one |
||
236 | mov eax, [ebx + SOCKET.Number] |
||
907 | mikedld | 237 | ret |
238 | |||
239 | .error: |
||
240 | xor eax, eax |
||
241 | ret |
||
242 | endp |
||
243 | |||
922 | mikedld | 244 | ;; [53.9] Check if local port is used by any socket in the system. |
245 | ; Scan through sockets list, checking SOCKET.LocalPort. |
||
246 | ; Useful when you want a to generate a unique local port number. |
||
247 | ; This proc doesn't guarantee that after calling it and trying to use |
||
248 | ; the port reported being free in calls to socket_open/socket_open_tcp it'll |
||
249 | ; still be free or otherwise it'll still be used if reported being in use. |
||
261 | hidnplayr | 250 | ; |
922 | mikedld | 251 | ; @param BX is a port number |
252 | ; @return 1 (port is free) or 0 (port is in use) in EAX |
||
253 | ;; |
||
907 | mikedld | 254 | proc is_localport_unused stdcall |
255 | xchg bl, bh |
||
261 | hidnplayr | 256 | |
922 | mikedld | 257 | ; assume the return value is 'free' |
258 | xor eax, eax |
||
907 | mikedld | 259 | inc al |
922 | mikedld | 260 | |
907 | mikedld | 261 | mov edx, net_sockets |
261 | hidnplayr | 262 | |
907 | mikedld | 263 | .next_socket: |
264 | mov edx, [edx + SOCKET.NextPtr] |
||
265 | or edx, edx |
||
266 | jz .exit |
||
267 | cmp [edx + SOCKET.LocalPort], bx |
||
922 | mikedld | 268 | jne .next_socket |
261 | hidnplayr | 269 | |
922 | mikedld | 270 | ; return 'in use' |
271 | dec al |
||
261 | hidnplayr | 272 | |
907 | mikedld | 273 | .exit: |
274 | ret |
||
275 | endp |
||
261 | hidnplayr | 276 | |
922 | mikedld | 277 | ;; [53.0] Open DGRAM socket (connectionless, unreliable) |
261 | hidnplayr | 278 | ; |
922 | mikedld | 279 | ; @param BX is local port number |
280 | ; @param CX is remote port number |
||
281 | ; @param EDX is remote IP address |
||
282 | ; @return socket number or -1 (error) in EAX |
||
283 | ;; |
||
907 | mikedld | 284 | proc socket_open stdcall |
285 | call net_socket_alloc |
||
286 | or eax, eax |
||
287 | jz .error |
||
261 | hidnplayr | 288 | |
907 | mikedld | 289 | DEBUGF 1, "K : socket_open (0x%x)\n", eax |
261 | hidnplayr | 290 | |
907 | mikedld | 291 | push eax |
261 | hidnplayr | 292 | |
907 | mikedld | 293 | xchg bh, bl |
294 | mov [eax + SOCKET.LocalPort], bx |
||
295 | xchg ch, cl |
||
296 | mov [eax + SOCKET.RemotePort], cx |
||
297 | mov ebx, [stack_ip] |
||
298 | mov [eax + SOCKET.LocalIP], ebx |
||
299 | mov [eax + SOCKET.RemoteIP], edx |
||
261 | hidnplayr | 300 | |
907 | mikedld | 301 | ;pop eax ; Get the socket number back, so we can return it |
302 | stdcall net_socket_addr_to_num |
||
303 | ret |
||
261 | hidnplayr | 304 | |
907 | mikedld | 305 | .error: |
306 | DEBUGF 1, "K : socket_open (fail)\n" |
||
307 | or eax, -1 |
||
308 | ret |
||
309 | endp |
||
261 | hidnplayr | 310 | |
922 | mikedld | 311 | ;; [53.5] Open STREAM socket (connection-based, sequenced, reliable, two-way) |
261 | hidnplayr | 312 | ; |
922 | mikedld | 313 | ; @param BX is local port number |
314 | ; @param CX is remote port number |
||
315 | ; @param EDX is remote IP address |
||
316 | ; @param ESI is open mode (SOCKET_ACTIVE, SOCKET_PASSIVE) |
||
317 | ; @return socket number or -1 (error) in EAX |
||
318 | ;; |
||
907 | mikedld | 319 | proc socket_open_tcp stdcall |
320 | local sockAddr dd ? |
||
261 | hidnplayr | 321 | |
907 | mikedld | 322 | cmp esi, SOCKET_PASSIVE |
323 | jne .skip_port_check |
||
261 | hidnplayr | 324 | |
907 | mikedld | 325 | push ebx |
326 | mov eax, ebx |
||
327 | xchg al, ah |
||
328 | mov ebx, net_sockets |
||
261 | hidnplayr | 329 | |
907 | mikedld | 330 | .next_socket: |
331 | mov ebx, [ebx + SOCKET.NextPtr] |
||
332 | or ebx, ebx |
||
333 | jz .last_socket |
||
334 | cmp [ebx + SOCKET.TCBState], TCB_LISTEN |
||
335 | jne .next_socket |
||
336 | cmp [ebx + SOCKET.LocalPort], ax |
||
337 | jne .next_socket |
||
261 | hidnplayr | 338 | |
907 | mikedld | 339 | xchg al, ah |
340 | DEBUGF 1, "K : error: port %u is listened by 0x%x\n", ax, ebx |
||
341 | pop ebx |
||
342 | jmp .error |
||
261 | hidnplayr | 343 | |
907 | mikedld | 344 | .last_socket: |
345 | pop ebx |
||
261 | hidnplayr | 346 | |
907 | mikedld | 347 | .skip_port_check: |
348 | call net_socket_alloc |
||
349 | or eax, eax |
||
350 | jz .error |
||
261 | hidnplayr | 351 | |
907 | mikedld | 352 | DEBUGF 1, "K : socket_open_tcp (0x%x)\n", eax |
261 | hidnplayr | 353 | |
907 | mikedld | 354 | mov [sockAddr], eax |
261 | hidnplayr | 355 | |
907 | mikedld | 356 | ; TODO - check this works! |
357 | ;mov [eax + SOCKET.wndsizeTimer], 0 ; Reset the window timer. |
||
261 | hidnplayr | 358 | |
907 | mikedld | 359 | xchg bh, bl |
360 | mov [eax + SOCKET.LocalPort], bx |
||
361 | xchg ch, cl |
||
362 | mov [eax + SOCKET.RemotePort], cx |
||
363 | mov [eax + SOCKET.OrigRemotePort], cx |
||
364 | mov ebx, [stack_ip] |
||
365 | mov [eax + SOCKET.LocalIP], ebx |
||
366 | mov [eax + SOCKET.RemoteIP], edx |
||
367 | mov [eax + SOCKET.OrigRemoteIP], edx |
||
261 | hidnplayr | 368 | |
907 | mikedld | 369 | mov ebx, TCB_LISTEN |
370 | cmp esi, SOCKET_PASSIVE |
||
371 | je @f |
||
372 | mov ebx, TCB_SYN_SENT |
||
373 | @@: mov [eax + SOCKET.TCBState], ebx ; Indicate the state of the TCB |
||
261 | hidnplayr | 374 | |
907 | mikedld | 375 | cmp ebx, TCB_LISTEN |
376 | je .exit |
||
261 | hidnplayr | 377 | |
907 | mikedld | 378 | ; Now, if we are in active mode, then we have to send a SYN to the specified remote port |
379 | mov eax, EMPTY_QUEUE |
||
380 | call dequeue |
||
381 | cmp ax, NO_BUFFER |
||
382 | je .exit |
||
261 | hidnplayr | 383 | |
907 | mikedld | 384 | push eax |
261 | hidnplayr | 385 | |
907 | mikedld | 386 | mov bl, TH_SYN |
387 | xor ecx, ecx |
||
388 | stdcall build_tcp_packet, [sockAddr] |
||
261 | hidnplayr | 389 | |
907 | mikedld | 390 | mov eax, NET1OUT_QUEUE |
391 | mov edx, [stack_ip] |
||
392 | mov ecx, [sockAddr] |
||
393 | cmp edx, [ecx + SOCKET.RemoteIP] |
||
394 | jne .not_local |
||
395 | mov eax, IPIN_QUEUE |
||
261 | hidnplayr | 396 | |
907 | mikedld | 397 | .not_local: |
398 | ; Send it. |
||
399 | pop ebx |
||
400 | call queue |
||
261 | hidnplayr | 401 | |
907 | mikedld | 402 | mov esi, [sockAddr] |
261 | hidnplayr | 403 | |
907 | mikedld | 404 | ; increment SND.NXT in socket |
405 | add esi, SOCKET.SND_NXT |
||
406 | call inc_inet_esi |
||
261 | hidnplayr | 407 | |
907 | mikedld | 408 | .exit: |
922 | mikedld | 409 | ; Get the socket number back, so we can return it |
410 | stdcall net_socket_addr_to_num, [sockAddr] |
||
907 | mikedld | 411 | ret |
261 | hidnplayr | 412 | |
907 | mikedld | 413 | .error: |
414 | DEBUGF 1, "K : socket_open_tcp (fail)\n" |
||
415 | or eax, -1 |
||
416 | ret |
||
417 | endp |
||
261 | hidnplayr | 418 | |
922 | mikedld | 419 | ;; [53.1] Close DGRAM socket |
261 | hidnplayr | 420 | ; |
922 | mikedld | 421 | ; @param EBX is socket number |
422 | ; @return 0 (closed successfully) or -1 (error) in EAX |
||
423 | ;; |
||
907 | mikedld | 424 | proc socket_close stdcall |
425 | DEBUGF 1, "K : socket_close (0x%x)\n", ebx |
||
426 | stdcall net_socket_num_to_addr, ebx |
||
427 | or eax, eax |
||
428 | jz .error |
||
261 | hidnplayr | 429 | |
907 | mikedld | 430 | stdcall net_socket_free, eax |
261 | hidnplayr | 431 | |
907 | mikedld | 432 | xor eax, eax |
433 | ret |
||
261 | hidnplayr | 434 | |
907 | mikedld | 435 | .error: |
436 | DEBUGF 1, "K : socket_close (fail)\n" |
||
437 | or eax, -1 |
||
438 | ret |
||
439 | endp |
||
261 | hidnplayr | 440 | |
922 | mikedld | 441 | ;; [53.8] Close STREAM socket |
442 | ; Closing TCP sockets takes time, so when you get successful return code |
||
443 | ; from this function doesn't always mean that socket is actually closed. |
||
261 | hidnplayr | 444 | ; |
922 | mikedld | 445 | ; @param EBX is socket number |
446 | ; @return 0 (closed successfully) or -1 (error) in EAX |
||
447 | ;; |
||
907 | mikedld | 448 | proc socket_close_tcp stdcall |
449 | local sockAddr dd ? |
||
922 | mikedld | 450 | |
907 | mikedld | 451 | DEBUGF 1, "K : socket_close_tcp (0x%x)\n", ebx |
452 | ; first, remove any resend entries |
||
453 | pusha |
||
261 | hidnplayr | 454 | |
907 | mikedld | 455 | mov esi, resendQ |
456 | mov ecx, 0 |
||
261 | hidnplayr | 457 | |
907 | mikedld | 458 | .next_resendq: |
459 | cmp ecx, NUMRESENDENTRIES |
||
460 | je .last_resendq ; None left |
||
461 | cmp [esi + 4], ebx |
||
462 | je @f ; found one |
||
463 | inc ecx |
||
464 | add esi, 8 |
||
465 | jmp .next_resendq |
||
261 | hidnplayr | 466 | |
907 | mikedld | 467 | @@: mov dword[esi + 4], 0 |
468 | inc ecx |
||
469 | add esi, 8 |
||
470 | jmp .next_resendq |
||
261 | hidnplayr | 471 | |
907 | mikedld | 472 | .last_resendq: |
473 | popa |
||
261 | hidnplayr | 474 | |
907 | mikedld | 475 | stdcall net_socket_num_to_addr, ebx |
476 | or eax, eax |
||
477 | jz .error |
||
261 | hidnplayr | 478 | |
907 | mikedld | 479 | mov ebx, eax |
480 | mov [sockAddr], eax |
||
261 | hidnplayr | 481 | |
922 | mikedld | 482 | cmp [ebx + SOCKET.TCBState], TCB_LISTEN |
483 | je .destroy_tcb |
||
484 | cmp [ebx + SOCKET.TCBState], TCB_SYN_SENT |
||
485 | je .destroy_tcb |
||
261 | hidnplayr | 486 | |
907 | mikedld | 487 | ; Now construct the response, and queue for sending by IP |
488 | mov eax, EMPTY_QUEUE |
||
489 | call dequeue |
||
490 | cmp ax, NO_BUFFER |
||
491 | je .error |
||
261 | hidnplayr | 492 | |
907 | mikedld | 493 | push eax |
261 | hidnplayr | 494 | |
922 | mikedld | 495 | mov bl, TH_FIN |
907 | mikedld | 496 | xor ecx, ecx |
497 | xor esi, esi |
||
498 | stdcall build_tcp_packet, [sockAddr] |
||
261 | hidnplayr | 499 | |
907 | mikedld | 500 | mov ebx, [sockAddr] |
501 | ; increament SND.NXT in socket |
||
502 | lea esi, [ebx + SOCKET.SND_NXT] |
||
503 | call inc_inet_esi |
||
261 | hidnplayr | 504 | |
907 | mikedld | 505 | ; Get the socket state |
506 | mov eax, [ebx + SOCKET.TCBState] |
||
507 | cmp eax, TCB_SYN_RECEIVED |
||
508 | je .fin_wait_1 |
||
509 | cmp eax, TCB_ESTABLISHED |
||
510 | je .fin_wait_1 |
||
261 | hidnplayr | 511 | |
907 | mikedld | 512 | ; assume CLOSE WAIT |
513 | ; Send a fin, then enter last-ack state |
||
514 | mov [ebx + SOCKET.TCBState], TCB_LAST_ACK |
||
515 | jmp .send |
||
261 | hidnplayr | 516 | |
907 | mikedld | 517 | .fin_wait_1: |
518 | ; Send a fin, then enter finwait2 state |
||
519 | mov [ebx + SOCKET.TCBState], TCB_FIN_WAIT_1 |
||
261 | hidnplayr | 520 | |
907 | mikedld | 521 | .send: |
522 | mov eax, NET1OUT_QUEUE |
||
523 | mov edx, [stack_ip] |
||
524 | mov ecx, [sockAddr] |
||
525 | cmp edx, [ecx + SOCKET.RemoteIP] |
||
526 | jne .not_local |
||
527 | mov eax, IPIN_QUEUE |
||
261 | hidnplayr | 528 | |
907 | mikedld | 529 | .not_local: |
530 | ; Send it. |
||
531 | pop ebx |
||
532 | call queue |
||
533 | jmp .exit |
||
261 | hidnplayr | 534 | |
907 | mikedld | 535 | .destroy_tcb: |
261 | hidnplayr | 536 | |
907 | mikedld | 537 | ; Clear the socket variables |
538 | stdcall net_socket_free, ebx |
||
261 | hidnplayr | 539 | |
907 | mikedld | 540 | .exit: |
541 | xor eax, eax |
||
542 | ret |
||
261 | hidnplayr | 543 | |
907 | mikedld | 544 | .error: |
545 | DEBUGF 1, "K : socket_close_tcp (fail)\n" |
||
546 | or eax, -1 |
||
547 | ret |
||
548 | endp |
||
261 | hidnplayr | 549 | |
922 | mikedld | 550 | ;; [53.2] Poll socket |
261 | hidnplayr | 551 | ; |
922 | mikedld | 552 | ; @param EBX is socket number |
553 | ; @return count or bytes in rx buffer or 0 (error) in EAX |
||
554 | ;; |
||
907 | mikedld | 555 | proc socket_poll stdcall |
556 | ; DEBUGF 1, "socket_poll(0x%x)\n", ebx |
||
557 | stdcall net_socket_num_to_addr, ebx |
||
558 | or eax, eax |
||
559 | jz .error |
||
261 | hidnplayr | 560 | |
907 | mikedld | 561 | mov eax, [eax + SOCKET.rxDataCount] |
562 | ret |
||
261 | hidnplayr | 563 | |
907 | mikedld | 564 | .error: |
565 | xor eax, eax |
||
566 | ret |
||
567 | endp |
||
261 | hidnplayr | 568 | |
922 | mikedld | 569 | ;; [53.6] Get socket TCB state |
261 | hidnplayr | 570 | ; |
922 | mikedld | 571 | ; @param EBX is socket number |
572 | ; @return socket TCB state or 0 (error) in EAX |
||
573 | ;; |
||
907 | mikedld | 574 | proc socket_status stdcall |
575 | ;; DEBUGF 1, "socket_status(0x%x)\n", ebx |
||
576 | stdcall net_socket_num_to_addr, ebx |
||
577 | or eax, eax |
||
578 | jz .error |
||
261 | hidnplayr | 579 | |
907 | mikedld | 580 | mov eax, [eax + SOCKET.TCBState] |
581 | ret |
||
261 | hidnplayr | 582 | |
907 | mikedld | 583 | .error: |
584 | xor eax, eax |
||
585 | ret |
||
586 | endp |
||
261 | hidnplayr | 587 | |
922 | mikedld | 588 | ;; [53.3] Get one byte from rx buffer |
589 | ; This function can return 0 in two cases: if there's one byte read and |
||
590 | ; non left, and if an error occured. Behavior should be changed and function |
||
591 | ; shouldn't be used for now. Consider using [53.11] instead. |
||
907 | mikedld | 592 | ; |
922 | mikedld | 593 | ; @param EBX is socket number |
594 | ; @return number of bytes left in rx buffer or 0 (error) in EAX |
||
595 | ; @return byte read in BL |
||
596 | ;; |
||
907 | mikedld | 597 | proc socket_read stdcall |
598 | ; DEBUGF 1, "socket_read(0x%x)\n", ebx |
||
599 | stdcall net_socket_num_to_addr, ebx |
||
600 | or eax, eax |
||
601 | jz .error |
||
261 | hidnplayr | 602 | |
907 | mikedld | 603 | mov ebx, eax |
604 | mov eax, [ebx + SOCKET.rxDataCount] ; get count of bytes |
||
605 | test eax, eax |
||
606 | jz .error |
||
261 | hidnplayr | 607 | |
907 | mikedld | 608 | dec eax |
915 | mikedld | 609 | mov esi, ebx ; esi is address of socket |
907 | mikedld | 610 | mov [ebx + SOCKET.rxDataCount], eax ; store new count |
915 | mikedld | 611 | movzx ebx, byte[ebx + SOCKET.rxData] ; get the byte |
261 | hidnplayr | 612 | |
915 | mikedld | 613 | mov ecx, SOCKETBUFFSIZE - SOCKET.rxData - 1 |
614 | lea edi, [esi + SOCKET.rxData] |
||
907 | mikedld | 615 | lea esi, [edi + 1] |
616 | cld |
||
915 | mikedld | 617 | push ecx |
618 | shr ecx, 2 |
||
907 | mikedld | 619 | rep movsd |
915 | mikedld | 620 | pop ecx |
621 | and ecx, 3 |
||
622 | rep movsb |
||
261 | hidnplayr | 623 | |
907 | mikedld | 624 | ret |
261 | hidnplayr | 625 | |
907 | mikedld | 626 | .error: |
627 | xor ebx, ebx |
||
628 | ret |
||
629 | endp |
||
261 | hidnplayr | 630 | |
922 | mikedld | 631 | ;; [53.11] Get specified number of bytes from rx buffer |
632 | ; Number of bytes in rx buffer can be less than requested size. In this case, |
||
633 | ; only available number of bytes is read. |
||
634 | ; This function can return 0 in two cases: if there's no data to read, and if |
||
635 | ; an error occured. Behavior should be changed. |
||
323 | hidnplayr | 636 | ; |
922 | mikedld | 637 | ; @param EBX is socket number |
638 | ; @param ECX is pointer to application buffer |
||
639 | ; @param EDX is application buffer size (number of bytes to read) |
||
640 | ; @return number of bytes read or 0 (error) in EAX |
||
641 | ;; |
||
907 | mikedld | 642 | proc socket_read_packet stdcall |
643 | ; DEBUGF 1, "socket_read_packet(0x%x)\n", ebx |
||
644 | stdcall net_socket_num_to_addr, ebx ; get real socket address |
||
645 | or eax, eax |
||
646 | jz .error |
||
261 | hidnplayr | 647 | |
907 | mikedld | 648 | mov ebx, eax |
649 | mov eax, [ebx + SOCKET.rxDataCount] ; get count of bytes |
||
650 | test eax, eax ; if count of bytes is zero.. |
||
651 | jz .exit ; exit function (eax will be zero) |
||
323 | hidnplayr | 652 | |
907 | mikedld | 653 | test edx, edx ; if buffer size is zero, copy all data |
654 | jz .copy_all_bytes |
||
655 | cmp edx, eax ; if buffer size is larger then the bytes of data, copy all data |
||
656 | jge .copy_all_bytes |
||
323 | hidnplayr | 657 | |
907 | mikedld | 658 | sub eax, edx ; store new count (data bytes in buffer - bytes we're about to copy) |
659 | mov [ebx + SOCKET.rxDataCount], eax ; |
||
660 | push eax |
||
661 | mov eax, edx ; number of bytes we want to copy must be in eax |
||
662 | call .start_copy ; copy to the application |
||
323 | hidnplayr | 663 | |
907 | mikedld | 664 | mov esi, ebx ; now we're going to copy the remaining bytes to the beginning |
915 | mikedld | 665 | add esi, SOCKET.rxData ; we dont need to copy the header |
907 | mikedld | 666 | mov edi, esi ; edi is where we're going to copy to |
667 | add esi, edx ; esi is from where we copy |
||
668 | pop ecx ; count of bytes we have left |
||
669 | push ecx ; push it again so we can re-use it later |
||
670 | shr ecx, 2 ; divide eax by 4 |
||
671 | cld |
||
672 | rep movsd ; copy all full dwords |
||
673 | pop ecx |
||
674 | and ecx, 3 |
||
675 | rep movsb ; copy remaining bytes |
||
323 | hidnplayr | 676 | |
907 | mikedld | 677 | .exit: |
678 | ret ; at last, exit |
||
323 | hidnplayr | 679 | |
907 | mikedld | 680 | .error: |
681 | xor eax, eax |
||
682 | ret |
||
323 | hidnplayr | 683 | |
907 | mikedld | 684 | .copy_all_bytes: |
685 | xor esi, esi |
||
686 | mov [ebx + SOCKET.rxDataCount], esi ; store new count (zero) |
||
687 | call .start_copy |
||
688 | ret |
||
323 | hidnplayr | 689 | |
907 | mikedld | 690 | .start_copy: |
691 | mov edi, ecx |
||
692 | mov esi, ebx |
||
915 | mikedld | 693 | add esi, SOCKET.rxData ; we dont need to copy the header |
907 | mikedld | 694 | mov ecx, eax ; eax is count of bytes |
695 | push ecx |
||
696 | shr ecx, 2 ; divide eax by 4 |
||
697 | cld ; copy all full dwords |
||
698 | rep movsd |
||
699 | pop ecx |
||
700 | and ecx, 3 |
||
701 | rep movsb ; copy the rest bytes |
||
702 | retn ; exit, or go back to shift remaining bytes if any |
||
703 | endp |
||
323 | hidnplayr | 704 | |
922 | mikedld | 705 | ;; [53.4] Send data through DGRAM socket |
261 | hidnplayr | 706 | ; |
922 | mikedld | 707 | ; @param EBX is socket number |
708 | ; @param ECX is application data size (number of bytes to send) |
||
709 | ; @param EDX is pointer to application data buffer |
||
710 | ; @return 0 (sent successfully) or -1 (error) in EAX |
||
711 | ;; |
||
907 | mikedld | 712 | proc socket_write stdcall |
713 | ; DEBUGF 1, "socket_write(0x%x)\n", ebx |
||
714 | stdcall net_socket_num_to_addr, ebx ; get real socket address |
||
715 | or eax, eax |
||
716 | jz .error |
||
261 | hidnplayr | 717 | |
907 | mikedld | 718 | mov ebx, eax |
261 | hidnplayr | 719 | |
907 | mikedld | 720 | mov eax, EMPTY_QUEUE |
721 | call dequeue |
||
722 | cmp ax, NO_BUFFER |
||
723 | je .error |
||
261 | hidnplayr | 724 | |
907 | mikedld | 725 | ; Save the queue entry number |
726 | push eax |
||
261 | hidnplayr | 727 | |
907 | mikedld | 728 | ; save the pointers to the data buffer & size |
729 | push edx |
||
730 | push ecx |
||
261 | hidnplayr | 731 | |
907 | mikedld | 732 | ; convert buffer pointer eax to the absolute address |
733 | mov ecx, IPBUFFSIZE |
||
734 | mul ecx |
||
735 | add eax, IPbuffs |
||
261 | hidnplayr | 736 | |
907 | mikedld | 737 | mov edx, eax |
261 | hidnplayr | 738 | |
907 | mikedld | 739 | ; So, ebx holds the socket ptr, edx holds the IPbuffer ptr |
261 | hidnplayr | 740 | |
907 | mikedld | 741 | ; Fill in the IP header (some data is in the socket descriptor) |
742 | mov eax, [ebx + SOCKET.LocalIP] |
||
743 | mov [edx + IP_PACKET.SourceAddress], eax |
||
744 | mov eax, [ebx + SOCKET.RemoteIP] |
||
745 | mov [edx + IP_PACKET.DestinationAddress], eax |
||
261 | hidnplayr | 746 | |
907 | mikedld | 747 | mov [edx + IP_PACKET.VersionAndIHL], 0x45 |
748 | mov [edx + IP_PACKET.TypeOfService], 0 |
||
261 | hidnplayr | 749 | |
907 | mikedld | 750 | pop eax ; Get the UDP data length |
751 | push eax |
||
261 | hidnplayr | 752 | |
907 | mikedld | 753 | add eax, 20 + 8 ; add IP header and UDP header lengths |
754 | xchg al, ah |
||
755 | mov [edx + IP_PACKET.TotalLength], ax |
||
756 | xor eax, eax |
||
757 | mov [edx + IP_PACKET.Identification], ax |
||
758 | mov [edx + IP_PACKET.FlagsAndFragmentOffset], 0x0040 |
||
759 | mov [edx + IP_PACKET.TimeToLive], 0x20 |
||
760 | mov [edx + IP_PACKET.Protocol], PROTOCOL_UDP |
||
261 | hidnplayr | 761 | |
907 | mikedld | 762 | ; Checksum left unfilled |
763 | mov [edx + IP_PACKET.HeaderChecksum], ax |
||
261 | hidnplayr | 764 | |
907 | mikedld | 765 | ; Fill in the UDP header (some data is in the socket descriptor) |
766 | mov ax, [ebx + SOCKET.LocalPort] |
||
767 | mov [edx + 20 + UDP_PACKET.SourcePort], ax |
||
261 | hidnplayr | 768 | |
907 | mikedld | 769 | mov ax, [ebx + SOCKET.RemotePort] |
770 | mov [edx + 20 + UDP_PACKET.DestinationPort], ax |
||
261 | hidnplayr | 771 | |
907 | mikedld | 772 | pop eax |
773 | push eax |
||
261 | hidnplayr | 774 | |
907 | mikedld | 775 | add eax, 8 |
776 | xchg al, ah |
||
777 | mov [edx + 20 + UDP_PACKET.Length], ax |
||
261 | hidnplayr | 778 | |
907 | mikedld | 779 | ; Checksum left unfilled |
780 | xor eax, eax |
||
781 | mov [edx + 20 + UDP_PACKET.Checksum], ax |
||
261 | hidnplayr | 782 | |
907 | mikedld | 783 | pop ecx ; count of bytes to send |
784 | mov ebx, ecx ; need the length later |
||
785 | pop eax ; get callers ptr to data to send |
||
261 | hidnplayr | 786 | |
907 | mikedld | 787 | ; Get the address of the callers data |
788 | mov edi, [TASK_BASE] |
||
789 | add edi, TASKDATA.mem_start |
||
790 | add eax, [edi] |
||
791 | mov esi, eax |
||
261 | hidnplayr | 792 | |
907 | mikedld | 793 | mov edi, edx |
794 | add edi, 28 |
||
795 | cld |
||
796 | rep movsb ; copy the data across |
||
261 | hidnplayr | 797 | |
907 | mikedld | 798 | ; we have edx as IPbuffer ptr. |
799 | ; Fill in the UDP checksum |
||
800 | ; First, fill in pseudoheader |
||
801 | mov eax, [edx + IP_PACKET.SourceAddress] |
||
802 | mov [pseudoHeader], eax |
||
803 | mov eax, [edx + IP_PACKET.DestinationAddress] |
||
804 | mov [pseudoHeader + 4], eax |
||
805 | mov word[pseudoHeader + 8], PROTOCOL_UDP shl 8 + 0 ; 0 + protocol |
||
806 | add ebx, 8 |
||
807 | mov eax, ebx |
||
808 | xchg al, ah |
||
809 | mov [pseudoHeader + 10], ax |
||
261 | hidnplayr | 810 | |
907 | mikedld | 811 | mov eax, pseudoHeader |
812 | mov [checkAdd1], eax |
||
813 | mov [checkSize1], word 12 |
||
814 | mov eax, edx |
||
815 | add eax, 20 |
||
816 | mov [checkAdd2], eax |
||
817 | mov eax, ebx |
||
818 | mov [checkSize2], ax ; was eax!! mjh 8/7/02 |
||
261 | hidnplayr | 819 | |
907 | mikedld | 820 | call checksum |
261 | hidnplayr | 821 | |
907 | mikedld | 822 | ; store it in the UDP checksum ( in the correct order! ) |
823 | mov ax, [checkResult] |
||
261 | hidnplayr | 824 | |
907 | mikedld | 825 | ; If the UDP checksum computes to 0, we must make it 0xffff |
826 | ; (0 is reserved for 'not used') |
||
827 | test ax, ax |
||
828 | jnz @f |
||
829 | mov ax, 0xffff |
||
261 | hidnplayr | 830 | |
907 | mikedld | 831 | @@: xchg al, ah |
832 | mov [edx + 20 + UDP_PACKET.Checksum], ax |
||
261 | hidnplayr | 833 | |
907 | mikedld | 834 | ; Fill in the IP header checksum |
835 | GET_IHL ecx,edx ; get IP-Header length |
||
836 | stdcall checksum_jb,edx,ecx ; buf_ptr, buf_size |
||
837 | xchg al, ah |
||
838 | mov [edx + IP_PACKET.HeaderChecksum], ax |
||
261 | hidnplayr | 839 | |
907 | mikedld | 840 | ; Check destination IP address. |
841 | ; If it is the local host IP, route it back to IP_RX |
||
261 | hidnplayr | 842 | |
907 | mikedld | 843 | pop ebx |
261 | hidnplayr | 844 | |
907 | mikedld | 845 | mov eax, NET1OUT_QUEUE |
846 | mov ecx, [edx + SOCKET.RemoteIP] |
||
847 | mov edx, [stack_ip] |
||
848 | cmp edx, ecx |
||
849 | jne .not_local |
||
850 | mov eax, IPIN_QUEUE |
||
261 | hidnplayr | 851 | |
907 | mikedld | 852 | .not_local: |
853 | ; Send it. |
||
854 | call queue |
||
261 | hidnplayr | 855 | |
907 | mikedld | 856 | xor eax, eax |
857 | ret |
||
261 | hidnplayr | 858 | |
907 | mikedld | 859 | .error: |
860 | or eax, -1 |
||
861 | ret |
||
862 | endp |
||
261 | hidnplayr | 863 | |
922 | mikedld | 864 | ;; [53.7] Send data through STREAM socket |
261 | hidnplayr | 865 | ; |
922 | mikedld | 866 | ; @param EBX is socket number |
867 | ; @param ECX is application data size (number of bytes to send) |
||
868 | ; @param EDX is pointer to application data buffer |
||
869 | ; @return 0 (sent successfully) or -1 (error) in EAX |
||
870 | ;; |
||
907 | mikedld | 871 | proc socket_write_tcp stdcall |
872 | local sockAddr dd ? |
||
261 | hidnplayr | 873 | |
907 | mikedld | 874 | ; DEBUGF 1, "socket_write_tcp(0x%x)\n", ebx |
875 | stdcall net_socket_num_to_addr, ebx |
||
876 | or eax, eax |
||
877 | jz .error |
||
261 | hidnplayr | 878 | |
907 | mikedld | 879 | mov ebx, eax |
880 | mov [sockAddr], ebx |
||
261 | hidnplayr | 881 | |
907 | mikedld | 882 | ; If the sockets window timer is nonzero, do not queue packet |
883 | cmp [ebx + SOCKET.wndsizeTimer], 0 |
||
884 | jne .error |
||
261 | hidnplayr | 885 | |
907 | mikedld | 886 | mov eax, EMPTY_QUEUE |
887 | call dequeue |
||
888 | cmp ax, NO_BUFFER |
||
889 | je .error |
||
261 | hidnplayr | 890 | |
907 | mikedld | 891 | push eax |
261 | hidnplayr | 892 | |
907 | mikedld | 893 | ; Get the address of the callers data |
894 | mov edi, [TASK_BASE] |
||
895 | add edi, TASKDATA.mem_start |
||
896 | add edx, [edi] |
||
897 | mov esi, edx |
||
261 | hidnplayr | 898 | |
907 | mikedld | 899 | pop eax |
900 | push eax |
||
261 | hidnplayr | 901 | |
907 | mikedld | 902 | push ecx |
903 | mov bl, TH_ACK |
||
904 | stdcall build_tcp_packet, [sockAddr] |
||
905 | pop ecx |
||
261 | hidnplayr | 906 | |
907 | mikedld | 907 | ; Check destination IP address. |
908 | ; If it is the local host IP, route it back to IP_RX |
||
261 | hidnplayr | 909 | |
907 | mikedld | 910 | pop ebx |
911 | push ecx |
||
261 | hidnplayr | 912 | |
907 | mikedld | 913 | mov eax, NET1OUT_QUEUE |
914 | mov edx, [stack_ip] |
||
915 | mov ecx, [sockAddr] |
||
916 | cmp edx, [ecx + SOCKET.RemoteIP] |
||
917 | jne .not_local |
||
918 | mov eax, IPIN_QUEUE |
||
261 | hidnplayr | 919 | |
907 | mikedld | 920 | .not_local: |
921 | pop ecx |
||
922 | push ebx ; save ipbuffer number |
||
261 | hidnplayr | 923 | |
907 | mikedld | 924 | call queue |
261 | hidnplayr | 925 | |
907 | mikedld | 926 | mov esi, [sockAddr] |
261 | hidnplayr | 927 | |
907 | mikedld | 928 | ; increament SND.NXT in socket |
929 | ; Amount to increment by is in ecx |
||
930 | add esi, SOCKET.SND_NXT |
||
931 | call add_inet_esi |
||
261 | hidnplayr | 932 | |
907 | mikedld | 933 | pop ebx |
261 | hidnplayr | 934 | |
907 | mikedld | 935 | ; Copy the IP buffer to a resend queue |
936 | ; If there isn't one, dont worry about it for now |
||
937 | mov esi, resendQ |
||
938 | mov ecx, 0 |
||
261 | hidnplayr | 939 | |
907 | mikedld | 940 | .next_resendq: |
941 | cmp ecx, NUMRESENDENTRIES |
||
942 | je .exit ; None found |
||
943 | cmp dword[esi + 4], 0 |
||
944 | je @f ; found one |
||
945 | inc ecx |
||
946 | add esi, 8 |
||
947 | jmp .next_resendq |
||
261 | hidnplayr | 948 | |
907 | mikedld | 949 | @@: push ebx |
261 | hidnplayr | 950 | |
907 | mikedld | 951 | ; OK, we have a buffer descriptor ptr in esi. |
952 | ; resend entry # in ecx |
||
953 | ; Populate it |
||
954 | ; socket # |
||
955 | ; retries count |
||
956 | ; retry time |
||
957 | ; fill IP buffer associated with this descriptor |
||
261 | hidnplayr | 958 | |
907 | mikedld | 959 | stdcall net_socket_addr_to_num, [sockAddr] |
960 | mov [esi + 4], eax |
||
961 | mov byte[esi + 1], TCP_RETRIES |
||
962 | mov word[esi + 2], TCP_TIMEOUT |
||
261 | hidnplayr | 963 | |
907 | mikedld | 964 | inc ecx |
965 | ; Now get buffer location, and copy buffer across. argh! more copying,, |
||
966 | mov edi, resendBuffer - IPBUFFSIZE |
||
261 | hidnplayr | 967 | |
907 | mikedld | 968 | @@: add edi, IPBUFFSIZE |
969 | loop @b |
||
261 | hidnplayr | 970 | |
907 | mikedld | 971 | ; we have dest buffer location in edi |
972 | pop eax |
||
973 | ; convert source buffer pointer eax to the absolute address |
||
974 | mov ecx, IPBUFFSIZE |
||
975 | mul ecx |
||
976 | add eax, IPbuffs |
||
977 | mov esi, eax |
||
261 | hidnplayr | 978 | |
907 | mikedld | 979 | ; do copy |
980 | mov ecx, IPBUFFSIZE |
||
981 | cld |
||
982 | rep movsb |
||
261 | hidnplayr | 983 | |
907 | mikedld | 984 | .exit: |
985 | xor eax, eax |
||
986 | ret |
||
261 | hidnplayr | 987 | |
907 | mikedld | 988 | .error: |
989 | or eax, -1 |
||
990 | ret |
||
991 | endp |