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