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