;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; ;; Copyright (C) KolibriOS team 2004-2009. All rights reserved. ;; ;; Distributed under terms of the GNU General Public License ;; ;; ;; ;; SOCKET.INC ;; ;; ;; ;; Written by hidnplayr@kolibrios.org ;; ;; based on code by mike.dld ;; ;; ;; ;; GNU GENERAL PUBLIC LICENSE ;; ;; Version 2, June 1991 ;; ;; ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; $Revision$ struct SOCKET_head .PrevPtr dd ? ; pointer to previous socket in list .NextPtr dd ? ; pointer to next socket in list .Number dd ? ; socket number (unique within single process) .PID dd ? ; application process id .Domain dd ? ; INET/UNIX/.. .Type dd ? ; RAW/UDP/TCP/... .Protocol dd ? ; ICMP/IPv4/ARP/ .lock dd ? ; lock mutex .end: ends struct IPv4_SOCKET .LocalIP dd ? .RemoteIP dd ? .SequenceNumber dd ? ; todo: add options (for func 8 and 9) .end: ends struct TCP_SOCKET .LocalPort dw ? ; In INET byte order .RemotePort dw ? ; In INET byte order .backlog dw ? ; Backlog .OrigRemoteIP dd ? ; original remote IP address (used to reset to LISTEN state) .OrigRemotePort dw ? ; original remote port (used to reset to LISTEN state) .TCBState dd ? ; TCB state .TCBTimer dd ? ; TCB timer (seconds) .ISS dd ? ; initial send sequence .IRS dd ? ; initial receive sequence .SND_UNA dd ? ; sequence number of unack'ed sent Packets .SND_NXT dd ? ; next send sequence number to use .SND_WND dd ? ; send window .RCV_NXT dd ? ; next receive sequence number to use .RCV_WND dd ? ; receive window .SEG_LEN dd ? ; segment length .SEG_WND dd ? ; segment window .wndsizeTimer dd ? ; window size timer .flags db ? ; packet flags .end: ends struct UDP_SOCKET .LocalPort dw ? ; In INET byte order .RemotePort dw ? ; In INET byte order .end: ends struct ICMP_SOCKET .Identifier dw ? ; .end: ends struct IPC_SOCKET .ConnectedTo dd ? ; Socket number of other socket this one is connected to .end: ends MAX_backlog equ 20 ; backlog for stream sockets SOCKETBUFFSIZE equ 4096 ; in bytes SOCKET_QUEUE_SIZE equ 10 ; maximum number ofincoming packets queued for 1 socket uglobal net_sockets rd 2 last_UDP_port dw ? ; These values give the number of the last used ephemeral port last_TCP_port dw ? ; endg ;----------------------------------------------- ; ; SOCKET_init ; ; - ; ; IN: / ; OUT: / ; ;----------------------------------------------- align 4 socket_init: mov [net_sockets], 0 mov [net_sockets + 4], 0 mov [last_UDP_port], MIN_EPHEMERAL_PORT mov [last_TCP_port], MIN_EPHEMERAL_PORT ret ;----------------------------------------------------------------------------- ; ; Socket API (function 74) ; ;----------------------------------------------------------------------------- align 4 sys_socket: test bl, bl jz socket_open ; 0 dec bl jz socket_close ; 1 dec bl jz socket_bind ; 2 dec bl jz socket_listen ; 3 dec bl jz socket_connect ; 4 dec bl jz socket_accept ; 5 dec bl jz socket_send ; 6 dec bl jz socket_recv ; 7 dec bl ; jz socket_get_opt ; 8 dec bl ; jz socket_set_opt ; 9 s_error: mov dword [esp+32],-1 ret ;----------------------------------------------- ; ; SOCKET_open ; ; ; IN: domain in ecx ; type in edx ; protocol in esi ; OUT: eax is socket num, -1 on error ; ;----------------------------------------------- align 4 socket_open: DEBUGF 1,"socket_open: domain: %u, type: %u",ecx, edx call net_socket_alloc or eax, eax jz s_error mov [eax + SOCKET_head.Domain], ecx mov [eax + SOCKET_head.Type], edx mov [eax + SOCKET_head.Protocol], esi stdcall net_socket_addr_to_num, eax DEBUGF 1,", socketnumber: %u\n", eax mov [esp+32], eax ret ;----------------------------------------------- ; ; SOCKET_bind ; ; IN: socket number in ecx ; pointer to sockaddr struct in edx ; length of that struct in esi ; OUT: 0 on success ; ;----------------------------------------------- align 4 socket_bind: DEBUGF 1,"Socket_bind: socknum: %u sockaddr: %x, length: %u, ",ecx,edx,esi stdcall net_socket_num_to_addr, ecx cmp eax, -1 jz s_error cmp esi, 2 jl s_error cmp word [edx], AF_INET4 je .af_inet4 cmp word [edx], AF_UNIX je .af_unix jmp s_error .af_unix: ; TODO: write code here mov dword [esp+32],0 ret .af_inet4: cmp esi, 6 jl s_error mov ecx, [eax + SOCKET_head.Type] mov bx, word [edx + 2] DEBUGF 1,"local port: %x ",bx test bx, bx jz .find_free call socket_check_port test bx, bx je s_error jmp .got_port .find_free: call socket_find_port test bx, bx je s_error .got_port: DEBUGF 1,"using port: %x ",bx mov word [eax + SOCKET_head.end + IPv4_SOCKET.end + UDP_SOCKET.LocalPort], bx mov ebx, dword [edx + 4] mov dword [eax + SOCKET_head.end + IPv4_SOCKET.LocalIP], ebx DEBUGF 1,"local ip: %u.%u.%u.%u\n",\ [eax + SOCKET_head.end + IPv4_SOCKET.LocalIP + 0]:1,[eax + SOCKET_head.end + IPv4_SOCKET.LocalIP + 1]:1,\ [eax + SOCKET_head.end + IPv4_SOCKET.LocalIP + 2]:1,[eax + SOCKET_head.end + IPv4_SOCKET.LocalIP + 3]:1 mov dword [esp+32],0 ret ;----------------------------------------------- ; ; SOCKET_connect ; ; ; IN: socket number in ecx ; pointer to sockaddr struct in edx ; length of that struct in esi ; OUT: 0 on success ; ;----------------------------------------------- align 4 socket_connect: DEBUGF 1,"Socket_connect: socknum: %u sockaddr: %x, length: %u,",ecx,edx,esi stdcall net_socket_num_to_addr, ecx cmp eax, -1 jz s_error cmp esi, 2 jl s_error cmp word [edx], AF_INET4 je .af_inet4 jmp s_error .af_inet4: cmp esi, 8 jl s_error cmp [eax + SOCKET_head.Type], IP_PROTO_UDP je .udp cmp [eax + SOCKET_head.Type], IP_PROTO_ICMP je .icmp cmp [eax + SOCKET_head.Type], IP_PROTO_TCP je .tcp jmp s_error .udp: mov bx , word [edx + 2] mov word [eax + SOCKET_head.end + IPv4_SOCKET.end + UDP_SOCKET.RemotePort], bx DEBUGF 1,"remote port: %x ",bx mov ebx, dword [edx + 4] mov dword [eax + SOCKET_head.end + IPv4_SOCKET.RemoteIP], ebx DEBUGF 1,"remote ip: %u.%u.%u.%u\n",[edx+4]:1,[edx+5]:1,[edx+6]:1,[edx+7]:1 mov dword [esp+32],0 ret .icmp: ; TODO: write code here ret .tcp: ;local sockAddr dd ? ; cmp esi, SOCKET_PASSIVE ; jne .skip_port_check ; ; push ebx ; mov eax, ebx ; xchg al, ah ; mov ebx, net_sockets ; ; .next_socket: ; mov ebx, [ebx + SOCKET.NextPtr] ; or ebx, ebx ; jz .last_socket ; cmp [ebx + SOCKET.TCBState], TCB_LISTEN ; jne .next_socket ; cmp [ebx + SOCKET.LocalPort], ax ; jne .next_socket ; ; xchg al, ah ; DEBUGF 1, "K : error: port %u is listened by 0x%x\n", ax, ebx ; pop ebx ; jmp .error ; ; .last_socket: ; pop ebx ; ; .skip_port_check: ; mov [eax + SOCKET.wndsizeTimer], 0 ; Reset the window timer. ; ; xchg bh, bl ; mov [eax + SOCKET.LocalPort], bx ; xchg ch, cl ; mov [eax + SOCKET.RemotePort], cx ; mov [eax + SOCKET.OrigRemotePort], cx ; mov ebx, [IP_LIST] ; mov [eax + SOCKET.LocalIP], ebx ; mov [eax + SOCKET.RemoteIP], edx ; mov [eax + SOCKET.OrigRemoteIP], edx ; mov ebx, TCB_LISTEN ; cmp esi, SOCKET_PASSIVE ; je @f ; mov ebx, TCB_SYN_SENT ; @@: mov [eax + SOCKET.TCBState], ebx ; Indicate the state of the TCB ; cmp ebx, TCB_LISTEN ; je .exit ; Now, if we are in active mode, then we have to send a SYN to the specified remote port ; mov eax, EMPTY_QUEUE ; call dequeue ; cmp ax, NO_BUFFER ; je .exit ; push eax ; mov bl, TH_SYN ; xor ecx, ecx ; stdcall build_tcp_Packet, [sockAddr] ; mov eax, NET1OUT_QUEUE ; mov edx, [IP_LIST] ; mov ecx, [sockAddr] ; cmp edx, [ecx + SOCKET.RemoteIP] ; jne .not_local ; mov eax, IPIN_QUEUE ; .not_local: ; Send it. ; pop ebx ; call queue .exit: xor eax, eax ret ;----------------------------------------------- ; ; SOCKET_listen ; ; ; IN: socket number in ecx ; backlog in edx ; OUT: eax is socket num, -1 on error ; ;----------------------------------------------- align 4 socket_listen: DEBUGF 1,"Socket_listen: socknum: %u backlog: %u\n",ecx,edx stdcall net_socket_num_to_addr, ecx cmp eax, -1 jz s_error cmp edx, MAX_backlog jl .ok mov dx , 20 .ok: mov [eax + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.backlog], dx ; TODO: insert code for active connections like TCP mov dword [esp+32], 0 ret ;----------------------------------------------- ; ; SOCKET_accept ; ; ; IN: socket number in ecx ; addr in edx ; addrlen in esi ; OUT: eax is socket num, -1 on error ; ;----------------------------------------------- align 4 socket_accept: DEBUGF 1,"Socket_accept: socknum: %u sockaddr: %x, length: %u\n",ecx,edx,esi stdcall net_socket_num_to_addr, ecx or eax, eax jz s_error mov esi, eax cmp word [esi + SOCKET_head.Domain], AF_INET4 je .af_inet4 jmp s_error .af_inet4: cmp [esi + SOCKET_head.Type], IP_PROTO_TCP je .tcp jmp s_error .tcp: cmp [esi + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.backlog], 0 jz s_error call net_socket_alloc or eax, eax jz s_error mov edi, eax dec [esi + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.backlog] mov ecx, (SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.end+3)/4 push esi edi rep movsd pop edi esi mov [edi + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.backlog], 0 ; TODO: fill in structure in ecx mov [esi + SOCKET_head.end + IPv4_SOCKET.RemoteIP], 0 mov [esi + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RemotePort], 0 stdcall net_socket_addr_to_num, edi mov [esp+32], eax ret ;----------------------------------------------- ; ; SOCKET_close ; ; ; IN: socket number in ecx ; OUT: eax is socket num, -1 on error ; ;----------------------------------------------- align 4 socket_close: DEBUGF 1,"Socket_close: socknum: %u\n",ecx stdcall net_socket_num_to_addr, ecx or eax, eax jz s_error cmp [eax + SOCKET_head.Domain], AF_INET4 jne s_error cmp [eax + SOCKET_head.Type], IP_PROTO_UDP je .udp cmp [eax + SOCKET_head.Type], IP_PROTO_ICMP je .icmp cmp [eax + SOCKET_head.Type], IP_PROTO_TCP je .tcp jmp s_error .udp: stdcall net_socket_free, eax mov dword [esp+32],0 ret .icmp: ret .tcp: if 1 = 0 ;local sockAddr dd ? ; DEBUGF 1, "K : socket_close_tcp (0x%x)\n", ebx ; first, remove any resend entries pusha mov esi, resendQ mov ecx, 0 .next_resendq: cmp ecx, NUMRESENDENTRIES je .last_resendq ; None left cmp [esi + 4], ebx je @f ; found one inc ecx add esi, 8 jmp .next_resendq @@: mov dword[esi + 4], 0 inc ecx add esi, 8 jmp .next_resendq .last_resendq: popa mov ebx, eax ; mov [sockAddr], eax cmp [eax + SOCKET.TCBState], TCB_LISTEN je .destroy_tcb cmp [eax + SOCKET.TCBState], TCB_SYN_SENT je .destroy_tcb ; Now construct the response, and queue for sending by IP mov eax, EMPTY_QUEUE call dequeue cmp ax, NO_BUFFER je .error push eax mov bl, TH_FIN xor ecx, ecx xor esi, esi stdcall build_tcp_Packet, [sockAddr] mov ebx, [sockAddr] ; increament SND.NXT in socket lea esi, [ebx + SOCKET.SND_NXT] call inc_inet_esi ; Get the socket state mov eax, [ebx + SOCKET.TCBState] cmp eax, TCB_SYN_RECEIVED je .fin_wait_1 cmp eax, TCB_ESTABLISHED je .fin_wait_1 ; assume CLOSE WAIT ; Send a fin, then enter last-ack state mov [ebx + SOCKET.TCBState], TCB_LAST_ACK jmp .send .fin_wait_1: ; Send a fin, then enter finwait2 state mov [ebx + SOCKET.TCBState], TCB_FIN_WAIT_1 .send: mov eax, NET1OUT_QUEUE mov edx, [IP_LIST] ; mov ecx, [sockAddr] cmp edx, [ecx + SOCKET.RemoteIP] jne .not_local mov eax, IPIN_QUEUE .not_local: ; Send it. pop ebx call queue jmp .exit .destroy_tcb: stdcall net_socket_free, eax end if .exit: mov dword [esp+32],0 ret ;----------------------------------------------- ; ; SOCKET_receive ; ; ; IN: socket number in ecx ; addr to buffer in edx ; length of buffer in esi ; flags in edi ; OUT: eax is number of bytes copied, -1 on error ; ;----------------------------------------------- align 4 socket_recv: DEBUGF 1,"Socket_receive: socknum: %u bufferaddress: %x, length: %u, flags: %x\n",ecx,edx,esi,edi stdcall net_socket_num_to_addr, ecx ; get real socket address or eax, eax jz s_error DEBUGF 1,"Socket pointer: %x\n", eax get_from_queue (eax + 2048), SOCKET_QUEUE_SIZE, 4*3, s_error mov edi, edx mov ecx, [esi + socket_queue_entry.data_size] DEBUGF 1,"Got %u bytes of data\n", ecx cmp ecx, edx jle .large_enough DEBUGF 1,"Buffer too small...\n" jmp s_error .large_enough: push [esi + socket_queue_entry.data_ptr] mov esi, [esi + socket_queue_entry.offset] add esi, [esp] DEBUGF 1,"Source buffer: %x, real addr: %x\n", [esp], esi mov dword[esp+32+4], ecx ; return number of bytes copied shr ecx, 1 jnc .nb movsb .nb: shr ecx, 1 jnc .nw movsw .nw: rep movsd call kernel_free ret ;----------------------------------------------- ; ; SOCKET_send ; ; ; IN: socket number in ecx ; pointer to data in edx ; datalength in esi ; flags in edi ; OUT: -1 on error ; ;----------------------------------------------- align 4 socket_send: DEBUGF 1,"Socket_send: socknum: %u sockaddr: %x, length: %u, flags: %x, ",ecx,edx,esi,edi stdcall net_socket_num_to_addr, ecx ; get real socket address or eax, eax jz s_error cmp word [eax + SOCKET_head.Domain], AF_INET4 je .af_inet4 jmp s_error ;--------- .af_inet4: DEBUGF 1,"Socket type:%u\n", [eax + SOCKET_head.Type]:4 cmp [eax + SOCKET_head.Type], IP_PROTO_TCP je .tcp cmp [eax + SOCKET_head.Type], IP_PROTO_UDP je .udp cmp [eax + SOCKET_head.Type], SOCK_RAW je .raw jmp s_error ;-------- .udp: DEBUGF 1,"type: UDP, " cmp [eax + SOCKET_head.end + IPv4_SOCKET.end + UDP_SOCKET.LocalPort],0 jne @f push esi mov ecx, [eax + SOCKET_head.Type] call socket_find_port test bx, bx pop esi je s_error mov [eax + SOCKET_head.end + IPv4_SOCKET.end + UDP_SOCKET.LocalPort], bx @@: mov ecx, esi mov esi, edx call UDP_socket_send mov [esp+32], eax ret .tcp: mov [esp+32], eax ret ;-------- .raw: cmp [eax + SOCKET_head.Protocol], IP_PROTO_IP je .raw_ip cmp [eax + SOCKET_head.Protocol], IP_PROTO_ICMP je .raw_icmp jmp s_error ;-------- .raw_ip: mov [esp+32], eax ret .raw_icmp: ; sub ecx, ICMP_Packet.Data ; mov esi, edx ; push ax ; call IPv4_get_frgmnt_num ; mov dx, ax ; pop ax ; shl edx, 16 ; mov dh , [esi + ICMP_Packet.Type] ; mov dl , [esi + ICMP_Packet.Code] ; mov di , [esi + ICMP_Packet.Identifier] ; mov [eax + SOCKET.LocalPort], di ; Set localport to the identifier number, so we can receive reply's ; shl edi, 16 ; mov di , [esi + ICMP_Packet.SequenceNumber] ; add esi, ICMP_Packet.Data ; mov ebx, [eax + SOCKET.LocalIP] ; mov eax, [eax + SOCKET.RemoteIP] ; call ICMP_create_packet mov [esp+32], eax ret ;----------------------------------------------- ; ; SOCKET_find_free_port (local port) ; ; works with INET byte order ; ; IN: type in ecx (TCP/UDP) ; OUT: bx = 0 on error, portnumber otherwise ; ;----------------------------------------------- align 4 socket_find_port: DEBUGF 1,"Socket_find_free_port\n" cmp ecx, IP_PROTO_UDP je .udp cmp ecx, IP_PROTO_TCP je .tcp .udp: mov bx, [last_UDP_port] je .continue .tcp: mov bx, [last_TCP_port] .continue: inc bx .check_only: mov esi, net_sockets .next_socket: mov esi, [esi + SOCKET_head.NextPtr] or esi, esi jz .port_ok cmp [esi + SOCKET_head.Type], ecx jne .next_socket rol bx, 8 cmp [esi + SOCKET_head.end + IPv4_SOCKET.end + UDP_SOCKET.LocalPort], bx rol bx, 8 ; this doesnt change the zero flag, does it ? jne .next_socket cmp bx, MAX_EPHEMERAL_PORT jle .continue ; todo: WRAP! ; mov [last_UDP_port], MIN_EPHEMERAL_PORT .exit: xor ebx, ebx .port_ok: rol bx, 8 ret ;----------------------------------------------- ; ; SOCKET_check_port (local port) ; ; works with INET byte order ; ; IN: type in ecx (TCP/UDP) ; port to check in bx ; OUT: bx = 0 on error, unchanged otherwise ; ;----------------------------------------------- align 4 socket_check_port: mov esi, net_sockets .next_socket: mov esi, [esi + SOCKET_head.NextPtr] or esi, esi jz .port_ok cmp [esi + SOCKET_head.Type], ecx jne .next_socket cmp [esi + SOCKET_head.end + IPv4_SOCKET.end + UDP_SOCKET.LocalPort], bx jne .next_socket xor ebx, ebx .port_ok: ret ;----------------------------------------------- ; ; SOCKET_internal_receiver ; ; Updates a socket with received data ; ; Note: the mutex must already be set ! ; ; IN: eax = socket ptr ; ecx = size ; esi = pointer to buffer ; edi = offset ; ; OUT: xxx ; ;----------------------------------------------- align 4 socket_internal_receiver: DEBUGF 1,"Internal socket receiver: buffer %x, offset: %x\n", esi, edi push edi ; offset push ecx ; size push esi ; data_ptr mov esi, esp add_to_queue (eax + 2048), SOCKET_QUEUE_SIZE, 3*4, .full DEBUGF 1,"Queued packet successfully\n" add esp, 4*3 mov [eax + SOCKET_head.lock], 0 ; flag an event to the application mov edx, [eax + SOCKET_head.PID] ; get socket owner PID mov ecx, 1 mov esi, TASK_DATA + TASKDATA.pid .next_pid: cmp [esi], edx je .found_pid inc ecx add esi, 0x20 cmp ecx, [TASK_COUNT] jbe .next_pid ret .found_pid: shl ecx, 8 or [ecx + SLOT_BASE + APPDATA.event_mask], EVENT_NETWORK ; stack event mov [check_idle_semaphore], 200 ret .full: DEBUGF 1,"Socket %x is full!\n",eax mov [eax + SOCKET_head.lock], 0 call kernel_free add esp, 8 ret ; Allocate memory for socket data and put new socket into the list ; Newly created socket is initialized with calling PID and number and ; put into beginning of list (which is a fastest way). ; ; @return socket structure address in EAX ; proc net_socket_alloc stdcall uses ebx ecx edx edi stdcall kernel_alloc, SOCKETBUFFSIZE DEBUGF 1, "K : net_socket_alloc (0x%x)\n", eax ; check if we can allocate needed amount of memory or eax, eax jz .exit ; zero-initialize allocated memory push eax mov edi, eax mov ecx, SOCKETBUFFSIZE / 4 ; cld xor eax, eax rep stosd pop eax init_queue (eax + 2048) ; add socket to the list by changing pointers mov ebx, net_sockets push [ebx + SOCKET_head.NextPtr] mov [ebx + SOCKET_head.NextPtr], eax mov [eax + SOCKET_head.PrevPtr], ebx pop ebx mov [eax + SOCKET_head.NextPtr], ebx or ebx, ebx jz @f mov [ebx + SOCKET_head.PrevPtr], eax @@: ; set socket owner PID to the one of calling process mov ebx, [TASK_BASE] mov ebx, [ebx + TASKDATA.pid] mov [eax + SOCKET_head.PID], ebx ; find first free socket number and use it ;mov edx, ebx mov ebx, net_sockets xor ecx, ecx .next_socket_number: inc ecx .next_socket: mov ebx, [ebx + SOCKET_head.NextPtr] or ebx, ebx jz .last_socket_number cmp [ebx + SOCKET_head.Number], ecx jne .next_socket ;cmp [ebx + SOCKET.PID], edx ;jne .next_socket mov ebx, net_sockets jmp .next_socket_number .last_socket_number: mov [eax + SOCKET_head.Number], ecx .exit: ret endp ; Free socket data memory and pop socket off the list ; ; @param sockAddr is a socket structure address ; proc net_socket_free stdcall uses ebx ecx edx, sockAddr:DWORD mov eax, [sockAddr] DEBUGF 1, "K : net_socket_free (0x%x)\n", eax ; check if we got something similar to socket structure address or eax, eax jz .error ; make sure sockAddr is one of the socket addresses in the list mov ebx, net_sockets ;mov ecx, [TASK_BASE] ;mov ecx, [ecx + TASKDATA.pid] .next_socket: mov ebx, [ebx + SOCKET_head.NextPtr] or ebx, ebx jz .error cmp ebx, eax jne .next_socket ;cmp [ebx + SOCKET.PID], ecx ;jne .next_socket ; okay, we found the correct one ; remove it from the list first, changing pointers mov ebx, [eax + SOCKET_head.NextPtr] mov eax, [eax + SOCKET_head.PrevPtr] mov [eax + SOCKET_head.NextPtr], ebx or ebx, ebx jz @f mov [ebx + SOCKET_head.PrevPtr], eax lea ebx, [eax + SOCKET_head.lock] call wait_mutex @@: ; and finally free the memory structure used stdcall kernel_free, [sockAddr] ret .error: DEBUGF 1, "K : failed\n" ret endp ; Get socket structure address by its number ; Scan through sockets list to find the socket with specified number. ; This proc uses SOCKET.PID indirectly to check if socket is owned by ; calling process. ; ; @param sockNum is a socket number ; @return socket structure address or 0 (not found) in EAX ; proc net_socket_num_to_addr stdcall uses ebx ecx, sockNum:DWORD mov eax, [sockNum] ; check if we got something similar to socket number or eax, eax jz .error ; scan through sockets list mov ebx, net_sockets ;mov ecx, [TASK_BASE] ;mov ecx, [ecx + TASKDATA.pid] .next_socket: mov ebx, [ebx + SOCKET_head.NextPtr] or ebx, ebx jz .error cmp [ebx + SOCKET_head.Number], eax jne .next_socket ;cmp [ebx + SOCKET.PID], ecx ;jne .next_socket ; okay, we found the correct one mov eax, ebx ret .error: xor eax, eax ret endp ; Get socket number by its structure address ; Scan through sockets list to find the socket with specified address. ; This proc uses SOCKET.PID indirectly to check if socket is owned by ; calling process. ; ; @param sockAddr is a socket structure address ; @return socket number (SOCKET.Number) or 0 (not found) in EAX ; proc net_socket_addr_to_num stdcall uses ebx ecx, sockAddr:DWORD mov eax, [sockAddr] ; check if we got something similar to socket structure address or eax, eax jz .error ; scan through sockets list mov ebx, net_sockets ;mov ecx, [TASK_BASE] ;mov ecx, [ecx + TASKDATA.pid] .next_socket: mov ebx, [ebx + SOCKET_head.NextPtr] or ebx, ebx jz .error cmp ebx, eax jne .next_socket ;cmp [ebx + SOCKET.PID], ecx ;jne .next_socket ; okay, we found the correct one mov eax, [ebx + SOCKET_head.Number] ret .error: xor eax, eax ret endp