1,6 → 1,6 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2010. All rights reserved. ;; |
;; Copyright (C) KolibriOS team 2004-2009. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;; SOCKET.INC ;; |
15,177 → 15,102 |
|
$Revision$ |
|
virtual at 0 |
|
SOCKET: |
struct SOCKET_head |
.NextPtr dd ? ; pointer to next socket in list |
.PrevPtr dd ? ; pointer to previous socket in list |
.Number dd ? ; socket number |
|
.lock dd ? ; lock mutex |
|
.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 |
.errorcode dd ? |
|
.options dd ? |
.SO_SND.SB_CC dd ? ;;;;; socket options: number of bytes in socket |
.SO_RCV.SB_CC dd ? |
.state dd ? ;;;;;;;;; |
|
.end: |
end virtual |
ends |
|
virtual at SOCKET.end |
|
IP_SOCKET: |
|
struct IPv4_SOCKET |
.LocalIP dd ? |
rd 3 ; for IPv6 addresses |
|
.RemoteIP dd ? |
rd 3 ; for IPv6 addresses |
.SequenceNumber dd ? |
|
.end: |
end virtual |
; todo: add options (for func 8 and 9) |
|
virtual at SOCKET.end |
|
SOCKET_virtual: |
|
.ConnectedTo dd ? ; Socket number of other socket this one is connected to |
|
.end: |
end virtual |
ends |
|
virtual at IP_SOCKET.end |
struct TCP_SOCKET |
|
TCP_SOCKET: |
|
.LocalPort dw ? ; In INET byte order |
.RemotePort dw ? ; In INET byte order |
|
.backlog dw ? ; Backlog |
.backlog_cur dw ? ; current size of queue for un-accept-ed connections |
|
.last_ack_number dd ? ; used only to let application know that ACK has been received |
; todo: may be use SND_UNA instead |
; todo: may be use events which allow additional information instead |
; todo: may be count acknowledged bytes (at least it has obvious sense) |
.OrigRemoteIP dd ? ; original remote IP address (used to reset to LISTEN state) |
.OrigRemotePort dw ? ; original remote port (used to reset to LISTEN state) |
.wndsizeTimer dd ? ; window size timer |
|
.t_state dd ? ; TCB state |
.t_timer dd ? ; TCB timer (seconds) |
.t_rxtshift dd ? |
.t_rxtcur dd ? |
.t_dupacks dd ? |
.t_maxseg dd ? |
.t_force dd ? |
.t_flags dd ? |
; Transmission control block |
.state dd ? ; TCB state |
.timer dd ? ; TCB timer (seconds) |
|
;--------------- |
; RFC783 page 21 |
|
; send sequence |
.ISS dd ? ; initial send sequence number |
.IRS dd ? ; initial receive sequence number |
.SND_UNA dd ? ; sequence number of unack'ed sent Packets |
.SND_NXT dd ? ; next send sequence number to use |
.SND_UP dd ? |
.SND_WL1 dd ? ; window minus one |
.SND_WL2 dd ? ; |
.ISS dd ? ; initial send sequence number |
.SND_WND dd ? ; send window |
|
; receive sequence |
.RCV_WND dw ? ; receive window |
.RCV_NXT dd ? ; next receive sequence number to use |
.RCV_UP dd ? |
.IRS dd ? ; initial receive sequence number |
.RCV_WND dd ? ; receive window |
.SEG_LEN dd ? ; segment length |
.SEG_WND dd ? ; segment window |
|
;--------------------- |
; Additional variables |
.flags db ? ; packet flags |
|
; receive variables |
.RCV_ADV dd ? |
|
; retransmit variables |
.SND_MAX dd ? |
|
; congestion control |
.SND_CWND dd ? |
.SND_SSTHRESH dd ? |
|
;---------------------- |
; Transmit timing stuff |
|
.t_idle dd ? |
.t_rtt dd ? |
.t_rtseq dd ? |
.t_srtt dd ? |
.t_rttvar dd ? |
.t_rttmin dd ? |
.max_sndwnd dd ? |
|
;----------------- |
; Out-of-band data |
|
.t_oobflags dd ? |
.t_iobc dd ? |
.t_softerror dd ? |
|
|
;--------- |
; RFC 1323 |
|
.SND_SCALE db ? ; Scale factor |
.RCV_SCALE db ? |
.request_r_scale db ? |
.requested_s_scale dd ? |
|
.ts_recent dd ? |
.ts_recent_age dd ? |
.last_ack_sent dd ? |
|
.end: |
end virtual |
ends |
|
virtual at IP_SOCKET.end |
struct UDP_SOCKET |
|
UDP_SOCKET: |
|
.LocalPort dw ? ; In INET byte order |
.RemotePort dw ? ; In INET byte order |
.firstpacket db ? |
|
.end: |
end virtual |
ends |
|
virtual at IP_SOCKET.end |
struct ICMP_SOCKET |
|
ICMP_SOCKET: |
|
.Identifier dw ? ; |
|
.end: |
end virtual |
|
ends |
|
struct IPC_SOCKET |
|
.ConnectedTo dd ? ; Socket number of other socket this one is connected to |
|
.end: |
|
ends |
|
struct socket_queue_entry |
; .owner dd ? |
.data_ptr dd ? |
.buf_ptr dd ? |
.data_size dd ? |
.offset dd ? |
.size: |
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 |
; the incoming packet queue for sockets is placed in the socket struct itself, at this location from start |
SOCKET_QUEUE_LOCATION equ SOCKETBUFFSIZE - SOCKET_QUEUE_SIZE*socket_queue_entry.size - queue.data |
SOCKET_QUEUE_LOCATION equ 2048 ; the incoming packet queue for sockets is placed in the socket struct itself, at this location from start |
|
uglobal |
net_sockets rd 4 |
net_sockets rd 2 |
last_UDP_port dw ? ; These values give the number of the last used ephemeral port |
last_TCP_port dw ? ; |
endg |
204,10 → 129,8 |
align 4 |
socket_init: |
|
xor eax, eax |
mov edi, net_sockets |
mov ecx, 4 |
rep stosd |
mov [net_sockets], 0 |
mov [net_sockets + 4], 0 |
|
mov [last_UDP_port], MIN_EPHEMERAL_PORT |
mov [last_TCP_port], MIN_EPHEMERAL_PORT |
222,26 → 145,26 |
;----------------------------------------------------------------- |
align 4 |
sys_socket: |
cmp ebx, 8 ; highest possible number |
and ebx, 0x000000FF ; should i remove this line ? |
cmp bl , 8 ; highest possible number |
jg s_error |
lea ebx, [.table + 4*ebx] |
jmp dword [ebx] |
|
.table: |
dd SOCKET_open ; 0 |
dd SOCKET_close ; 1 |
dd SOCKET_bind ; 2 |
dd SOCKET_listen ; 3 |
dd SOCKET_connect ; 4 |
dd SOCKET_accept ; 5 |
dd SOCKET_send ; 6 |
dd SOCKET_receive ; 7 |
dd SOCKET_get_opt ; 8 |
; dd SOCKET_set_opt ; 9 |
dd socket_open ; 0 |
dd socket_close ; 1 |
dd socket_bind ; 2 |
dd socket_listen ; 3 |
dd socket_connect ; 4 |
dd socket_accept ; 5 |
dd socket_send ; 6 |
dd socket_recv ; 7 |
dd socket_get_opt ; 8 |
; dd socket_set_opt ; 9 |
|
|
s_error: |
DEBUGF 1,"socket error\n" |
mov dword [esp+32], -1 |
|
ret |
251,6 → 174,7 |
; |
; SOCKET_open |
; |
; |
; IN: domain in ecx |
; type in edx |
; protocol in esi |
258,19 → 182,45 |
; |
;----------------------------------------------------------------- |
align 4 |
SOCKET_open: |
socket_open: |
|
DEBUGF 1,"socket_open: domain: %u, type: %u protocol: %x\n", ecx, edx, esi |
DEBUGF 1,"socket_open: domain: %u, type: %u",ecx, edx |
|
call SOCKET_alloc |
call net_socket_alloc |
or eax, eax |
jz s_error |
|
mov [eax + SOCKET.Domain], ecx |
mov [eax + SOCKET.Type], edx |
mov [eax + SOCKET.Protocol], esi |
mov [eax + SOCKET_head.Domain], ecx |
mov [eax + SOCKET_head.Type], edx |
mov [eax + SOCKET_head.Protocol], esi |
|
mov [esp+32], edi |
cmp ecx, AF_INET4 |
je .af_inet4 |
|
jmp .done |
|
|
.af_inet4: |
|
cmp edx, IP_PROTO_TCP |
je .tcp |
|
jmp .done |
|
.tcp: |
|
mov [eax + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_CLOSED |
|
pseudo_random ebx |
mov [eax + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.ISS], ebx |
mov [eax + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.SND_NXT], ebx |
|
.done: |
stdcall net_socket_addr_to_num, eax |
DEBUGF 1,", socketnumber: %u\n", eax |
|
mov [esp+32], eax |
|
ret |
|
|
286,11 → 236,12 |
; |
;----------------------------------------------------------------- |
align 4 |
SOCKET_bind: |
socket_bind: |
|
DEBUGF 1,"socket_bind: socknum: %u sockaddr: %x, length: %u\n", ecx, edx, esi |
DEBUGF 1,"Socket_bind: socknum: %u sockaddr: %x, length: %u, ",ecx,edx,esi |
|
call SOCKET_num_to_ptr |
stdcall net_socket_num_to_addr, ecx |
cmp eax, -1 |
jz s_error |
|
cmp esi, 2 |
313,37 → 264,37 |
|
.af_inet4: |
|
DEBUGF 1,"af_inet4\n" |
|
cmp esi, 6 |
jl s_error |
|
mov ecx, [eax + SOCKET.Type] |
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 |
jz s_error |
call socket_check_port |
test bx, bx |
je s_error |
jmp .got_port |
|
.find_free: |
call SOCKET_find_port |
; test bx, bx |
jz s_error |
|
call socket_find_port |
test bx, bx |
je s_error |
|
.got_port: |
DEBUGF 1,"using local port: %u", bx |
mov word [eax + UDP_SOCKET.LocalPort], bx |
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 + IP_SOCKET.LocalIP], ebx |
mov dword [eax + SOCKET_head.end + IPv4_SOCKET.LocalIP], ebx |
|
DEBUGF 1,"local ip: %u.%u.%u.%u\n",\ |
[eax + IP_SOCKET.LocalIP + 0]:1,[eax + IP_SOCKET.LocalIP + 1]:1,\ |
[eax + IP_SOCKET.LocalIP + 2]:1,[eax + IP_SOCKET.LocalIP + 3]:1 |
[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 |
355,6 → 306,7 |
; |
; SOCKET_connect |
; |
; |
; IN: socket number in ecx |
; pointer to sockaddr struct in edx |
; length of that struct in esi |
362,11 → 314,12 |
; |
;----------------------------------------------------------------- |
align 4 |
SOCKET_connect: |
socket_connect: |
|
DEBUGF 1,"socket_connect: socknum: %u sockaddr: %x, length: %u\n", ecx, edx, esi |
DEBUGF 1,"Socket_connect: socknum: %u sockaddr: %x, length: %u,",ecx,edx,esi |
|
call SOCKET_num_to_ptr |
stdcall net_socket_num_to_addr, ecx |
cmp eax, -1 |
jz s_error |
|
cmp esi, 8 |
379,22 → 332,23 |
|
.af_inet4: |
|
cmp [eax + SOCKET.Type], IP_PROTO_UDP |
cmp [eax + SOCKET_head.Type], IP_PROTO_UDP |
je .udp |
|
cmp [eax + SOCKET.Type], IP_PROTO_TCP |
cmp [eax + SOCKET_head.Type], IP_PROTO_TCP |
je .tcp |
|
jmp s_error |
|
.udp: |
|
mov bx , word [edx + 2] |
mov word [eax + UDP_SOCKET.RemotePort], bx |
mov [eax + UDP_SOCKET.firstpacket], 0 |
DEBUGF 1,"remote port: %u ",bx |
mov word [eax + SOCKET_head.end + IPv4_SOCKET.end + UDP_SOCKET.RemotePort], bx |
mov [eax + SOCKET_head.end + IPv4_SOCKET.end + UDP_SOCKET.firstpacket], 0 |
DEBUGF 1,"remote port: %x ",bx |
|
mov ebx, dword [edx + 4] |
mov dword [eax + IP_SOCKET.RemoteIP], ebx |
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 |
402,45 → 356,50 |
|
|
.tcp: |
; set sequence number |
; TODO: set sequence number to random value |
|
mov ebx, [TCP_sequence_num] |
add [TCP_sequence_num], 6400 |
mov [eax + TCP_SOCKET.ISS], ebx |
|
lea ebx, [eax + SOCKET.lock] |
lea ebx, [eax + SOCKET_head.lock] |
call wait_mutex |
|
; fill in remote port and IP |
|
;;;;;; mov [eax + TCP_SOCKET.wndsizeTimer], 0 ; Reset the window timer. |
|
mov [eax + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.wndsizeTimer], 0 ; Reset the window timer. |
; TODO: figure out WTF this is |
mov bx , word [edx + 2] |
mov [eax + TCP_SOCKET.RemotePort], bx |
DEBUGF 1,"remote port: %u ",bx |
mov [eax + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RemotePort], bx |
DEBUGF 1,"remote port: %x ",bx |
|
mov ebx, dword [edx + 4] |
mov [eax + IP_SOCKET.RemoteIP], ebx |
mov [eax + SOCKET_head.end + IPv4_SOCKET.RemoteIP], ebx |
|
; check if local port and IP is ok |
|
cmp [eax + IP_SOCKET.LocalIP], 0 |
cmp [eax + SOCKET_head.end + IPv4_SOCKET.LocalIP], 0 |
jne @f |
push [IP_LIST] ;;;;; device zero = default |
pop [eax + IP_SOCKET.LocalIP] |
push [IP_LIST] ; device zero = default |
pop [eax + SOCKET_head.end + IPv4_SOCKET.LocalIP] |
@@: |
|
cmp [eax + TCP_SOCKET.LocalPort], 0 |
cmp [eax + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.LocalPort], 0 |
jne @f |
call SOCKET_find_port |
|
mov ecx, [eax + SOCKET_head.Type] |
call socket_find_port |
test bx, bx |
jz s_error |
|
mov [eax + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.LocalPort], bx |
@@: |
|
; mov [eax + TCP_SOCKET.t_state], TCB_SYN_SENT |
call TCP_output |
|
mov [eax + SOCKET.lock], 0 |
mov [eax + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_SYN_SENT |
; now say hello to the remote tcp socket |
|
mov dword [esp+32], 0 ; success! |
mov bl, TH_SYN |
xor ecx, ecx |
call TCP_send |
|
mov dword [esp+32],0 |
ret |
|
|
448,6 → 407,7 |
; |
; SOCKET_listen |
; |
; |
; IN: socket number in ecx |
; backlog in edx |
; OUT: eax is socket num, -1 on error |
454,32 → 414,29 |
; |
;----------------------------------------------------------------- |
align 4 |
SOCKET_listen: |
socket_listen: |
|
DEBUGF 1,"Socket_listen: socknum: %u backlog: %u\n", ecx, edx |
|
call SOCKET_num_to_ptr |
stdcall net_socket_num_to_addr, ecx |
cmp eax, -1 |
jz s_error |
|
cmp word [eax + SOCKET.Domain], AF_INET4 |
cmp word [eax + SOCKET_head.Domain], AF_INET4 |
jne s_error |
|
cmp [eax + SOCKET.Type], IP_PROTO_TCP |
cmp [eax + SOCKET_head.Type], IP_PROTO_TCP |
jne s_error |
|
; TODO: check local port number |
|
cmp edx, MAX_backlog |
jle .ok |
mov edx, MAX_backlog |
jb .ok |
mov dx , MAX_backlog |
.ok: |
|
mov [eax + TCP_SOCKET.backlog], dx |
mov [eax + TCP_SOCKET.t_state], TCB_LISTEN |
or [eax + SOCKET.options], SO_ACCEPTCON |
mov [eax + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.backlog], dx |
mov [eax + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_LISTEN |
|
mov dword [esp+32], 0 |
|
ret |
|
|
487,6 → 444,7 |
; |
; SOCKET_accept |
; |
; |
; IN: socket number in ecx |
; addr in edx |
; addrlen in esi |
494,14 → 452,16 |
; |
;----------------------------------------------------------------- |
align 4 |
SOCKET_accept: |
socket_accept: |
|
DEBUGF 1,"Socket_accept: socknum: %u sockaddr: %x, length: %u\n", ecx, edx, esi |
|
call SOCKET_num_to_ptr |
stdcall net_socket_num_to_addr, ecx |
or eax, eax |
jz s_error |
mov esi, eax |
|
cmp word [eax + SOCKET.Domain], AF_INET4 |
cmp word [esi + SOCKET_head.Domain], AF_INET4 |
je .af_inet4 |
|
jmp s_error |
508,7 → 468,7 |
|
.af_inet4: |
|
cmp [eax + SOCKET.Type], IP_PROTO_TCP |
cmp [esi + SOCKET_head.Type], IP_PROTO_TCP |
je .tcp |
|
jmp s_error |
515,24 → 475,19 |
|
.tcp: |
|
lea ebx, [eax + SOCKET.lock] |
lea ebx, [esi + SOCKET_head.lock] |
call wait_mutex |
|
movzx ebx, [eax + TCP_SOCKET.backlog_cur] |
test ebx, ebx |
movzx eax, [esi + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.backlog_cur] |
test eax, eax |
jz .unlock_err |
|
dec [eax + TCP_SOCKET.backlog_cur] |
mov eax, [eax + TCP_SOCKET.end + (ebx-1)*4] |
mov [eax + SOCKET.lock], 0 |
mov dword [esp+32], 0 |
|
call TCP_output ;;;;; |
|
dec [esi + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.backlog_cur] |
mov eax, [eax + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.end + (eax-1)*4] |
mov [esi + SOCKET_head.lock], 0 |
stdcall net_socket_addr_to_num, eax |
mov [esp+32], eax |
ret |
|
.unlock_err: |
mov [eax + SOCKET.lock], 0 |
mov [esi + SOCKET_head.lock], 0 |
jmp s_error |
|
|
540,55 → 495,94 |
; |
; SOCKET_close |
; |
; |
; IN: socket number in ecx |
; OUT: eax is socket num, -1 on error |
; |
;----------------------------------------------------------------- |
align 4 |
SOCKET_close: |
socket_close: |
|
DEBUGF 1,"socket_close: socknum: %u\n", ecx |
DEBUGF 1,"Socket_close: socknum: %u\n",ecx |
|
call SOCKET_num_to_ptr |
stdcall net_socket_num_to_addr, ecx |
or eax, eax |
jz s_error |
|
cmp [eax + SOCKET.Domain], AF_INET4 |
cmp [eax + SOCKET_head.Domain], AF_INET4 |
jne s_error |
|
cmp [eax + SOCKET.Type], IP_PROTO_UDP |
je .free |
cmp [eax + SOCKET_head.Type], IP_PROTO_UDP |
je .udp |
|
cmp [eax + SOCKET.Type], IP_PROTO_ICMP |
je .free |
cmp [eax + SOCKET_head.Type], IP_PROTO_ICMP |
je .icmp |
|
cmp [eax + SOCKET.Type], IP_PROTO_TCP |
cmp [eax + SOCKET_head.Type], IP_PROTO_TCP |
je .tcp |
|
jmp s_error |
|
.tcp: |
test [eax + TCP_SOCKET.t_state], TCB_SYN_RECEIVED ;;;;;; |
jz .free |
.udp: |
|
call TCP_output |
|
stdcall net_socket_free, eax |
mov dword [esp+32], 0 |
ret |
|
|
.icmp: |
|
|
|
ret |
|
; state must be LISTEN, SYN_SENT, CLOSED or maybe even invalid |
; so, we may destroy the socket |
.free: |
call SOCKET_free |
.tcp: |
mov dword [esp+32], 0 |
|
; first, remove all resend entries for this socket |
|
call TCP_remove_socket |
|
; cmp [eax + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_LISTEN |
; je .destroy_tcb |
; cmp [eax + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_SYN_SENT |
; je .destroy_tcb |
; cmp [eac + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_CLOSED |
; je .destroy_tcb |
cmp [eax + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_SYN_RECEIVED |
je .fin_wait |
cmp [eax + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_ESTABLISHED |
je .fin_wait |
cmp [eax + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_CLOSE_WAIT |
je .last_ack |
|
stdcall net_socket_free, ebx |
|
ret |
|
|
.last_ack: |
mov [eax + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_LAST_ACK |
jmp .send_fin |
|
.fin_wait: |
mov [eax + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_FIN_WAIT_1 |
|
.send_fin: |
mov bl, TH_FIN + TH_ACK |
xor ecx, ecx |
call TCP_send |
|
ret |
|
|
|
|
;----------------------------------------------------------------- |
; |
; SOCKET_receive |
; |
; |
; IN: socket number in ecx |
; addr to buffer in edx |
; length of buffer in esi |
597,23 → 591,22 |
; |
;----------------------------------------------------------------- |
align 4 |
SOCKET_receive: |
socket_recv: |
|
DEBUGF 1,"socket_receive: socknum: %u bufaddr: %x, buflength: %u, flags: %x\n", ecx, edx, esi, edi |
|
call SOCKET_num_to_ptr |
DEBUGF 1,"Socket_receive: socknum: %u bufaddr: %x, buflength: %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 |
|
mov ebx, esi |
get_from_queue (eax + SOCKET_QUEUE_LOCATION),\ |
SOCKET_QUEUE_SIZE,\ |
socket_queue_entry.size,\ |
s_error |
; destroys esi and ecx |
|
DEBUGF 1,"Socket pointer: %x\n", eax |
|
get_from_queue (eax + SOCKET_QUEUE_LOCATION), SOCKET_QUEUE_SIZE, socket_queue_entry.size, s_error ; destroys esi and ecx |
|
mov edi, edx ; addr to buffer |
mov ecx, [esi + socket_queue_entry.data_size] |
|
mov ecx, [esi + socket_queue_entry.data_size] |
DEBUGF 1,"Got %u bytes of data\n", ecx |
|
cmp ecx, ebx |
620,14 → 613,15 |
jle .large_enough |
DEBUGF 1,"Buffer too small...\n" |
jmp s_error |
.large_enough: |
|
.large_enough: |
push [esi + socket_queue_entry.buf_ptr] ; save the buffer addr so we can clear it later |
mov esi, [esi + socket_queue_entry.data_ptr] |
push [esi + socket_queue_entry.data_ptr] ; save the buffer addr so we can clear it later |
mov esi, [esi + socket_queue_entry.offset] |
add esi, [esp] ; calculate the real data offset |
DEBUGF 1,"Source buffer: %x, real addr: %x\n", [esp], esi |
mov dword[esp+32+4], ecx ; return number of bytes copied in ebx |
|
; copy the data |
mov dword[esp+32+4], ecx ; return number of bytes copied |
|
shr ecx, 1 |
jnc .nb |
movsb |
638,12 → 632,9 |
jz .nd |
rep movsd |
.nd: |
; remove the packet ;;; TODO: only if it is empty!! |
|
;;;; call TCP_output ; only if it is tcp |
call kernel_free ; todo: check if ALL applications had the chance to receive data |
|
call kernel_free |
|
ret |
|
|
660,76 → 651,130 |
; |
;----------------------------------------------------------------- |
align 4 |
SOCKET_send: |
socket_send: |
|
DEBUGF 1,"socket_send: socknum: %u sockaddr: %x, length: %u, flags: %x\n", ecx, edx, esi, edi |
DEBUGF 1,"Socket_send: socknum: %u sockaddr: %x, length: %u, flags: %x, ",ecx,edx,esi,edi |
|
call SOCKET_num_to_ptr |
stdcall net_socket_num_to_addr, ecx ; get real socket address |
or eax, eax |
jz s_error |
|
cmp word [eax + SOCKET.Domain], AF_INET4 |
cmp word [eax + SOCKET_head.Domain], AF_INET4 |
je .af_inet4 |
|
jmp s_error |
|
.af_inet4: |
DEBUGF 1,"af_inet4\n" |
DEBUGF 1,"Socket type:%u\n", [eax + SOCKET_head.Type]:4 |
|
cmp [eax + SOCKET.Type], IP_PROTO_TCP |
cmp [eax + SOCKET_head.Type], IP_PROTO_TCP |
je .tcp |
|
cmp [eax + SOCKET.Type], IP_PROTO_UDP |
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\n" |
|
; check if local port is valid |
cmp [eax + UDP_SOCKET.LocalPort], 0 |
DEBUGF 1,"type: UDP, " |
|
cmp [eax + SOCKET_head.end + IPv4_SOCKET.end + UDP_SOCKET.LocalPort],0 |
jne @f |
|
call SOCKET_find_port |
jz s_error |
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 |
|
; Now, send the packet |
@@: |
|
mov ecx, esi |
mov esi, edx |
|
call UDP_output |
call UDP_socket_send |
|
mov dword [esp+32], 0 |
and dword [esp+32], 0 |
ret |
|
.tcp: |
DEBUGF 1,"type: TCP\n" |
|
; check if local port is valid |
cmp [eax + TCP_SOCKET.LocalPort], 0 |
cmp [eax + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.LocalPort],0 |
jne @f |
|
call SOCKET_find_port |
jz s_error |
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 + TCP_SOCKET.LocalPort], bx |
|
@@: |
;;;; TODO: queue the data |
|
call TCP_output |
mov ecx, esi |
mov esi, edx |
mov bl, TH_PUSH + TH_ACK |
|
call TCP_send |
|
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_get_options |
; |
; IN: ecx = socket number |
; edx = pointer to the options: |
; |
; IN: socket number in ecx |
; edx points to the options: |
; dd level, optname, optval, optlen |
; OUT: -1 on error |
; |
739,34 → 784,29 |
; |
;----------------------------------------------------------------- |
align 4 |
SOCKET_get_opt: |
socket_get_opt: |
|
DEBUGF 1,"socket_get_opt\n" |
|
call SOCKET_num_to_ptr |
jz s_error |
|
cmp dword [edx], IP_PROTO_TCP |
jnz s_error |
jnz .unknown |
cmp dword [edx+4], -2 |
jz @f |
cmp dword [edx+4], -3 |
jnz s_error |
jnz .unknown |
@@: |
; mov eax, [edx+12] |
; test eax, eax |
; jz .fail |
; cmp dword [eax], 4 |
; mov dword [eax], 4 |
; jb .fail |
; stdcall net_socket_num_to_addr, ecx |
; test eax, eax |
; jz .fail |
; ; todo: check that eax is really TCP socket |
; mov ecx, [eax + TCP_SOCKET.last_ack_number] |
; cmp dword [edx+4], -2 |
; jz @f |
; mov ecx, [eax + TCP_SOCKET.state] |
mov eax, [edx+12] |
test eax, eax |
jz .fail |
cmp dword [eax], 4 |
mov dword [eax], 4 |
jb .fail |
stdcall net_socket_num_to_addr, ecx |
test eax, eax |
jz .fail |
; todo: check that eax is really TCP socket |
mov ecx, [eax + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.last_ack_number] |
cmp dword [edx+4], -2 |
jz @f |
mov ecx, [eax + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state] |
@@: |
mov eax, [edx+8] |
test eax, eax |
775,65 → 815,70 |
@@: |
mov dword [esp+32], 0 |
ret |
.fail: |
.unknown: |
mov dword [esp+32], -1 |
ret |
|
|
;----------------------------------------------------------------- |
; |
; SOCKET_find_port |
; SOCKET_find_free_port (local port) |
; |
; Fills in the local port number for TCP and UDP sockets |
; This procedure always works because the number of sockets is |
; limited to a smaller number then the number of possible ports |
; works with INET byte order |
; |
; IN: eax = socket pointer |
; OUT: / |
; IN: type in ecx (TCP/UDP) |
; OUT: bx = 0 on error, portnumber otherwise |
; |
;----------------------------------------------------------------- |
align 4 |
SOCKET_find_port: |
socket_find_port: |
|
DEBUGF 1,"socket_find_free_port\n" |
DEBUGF 1,"Socket_find_free_port\n" |
|
push ebx esi ecx |
|
cmp [eax + SOCKET.Type], IP_PROTO_UDP |
cmp ecx, IP_PROTO_UDP |
je .udp |
|
cmp [eax + SOCKET.Type], IP_PROTO_TCP |
cmp ecx, IP_PROTO_TCP |
je .tcp |
|
jmp .error |
|
.done: |
mov [eax + UDP_SOCKET.LocalPort], bx |
.error: |
pop ecx esi ebx |
ret |
|
.udp: |
mov bx, [last_UDP_port] |
call .findit |
mov [last_UDP_port], bx |
jmp .done |
je .continue |
|
.tcp: |
mov bx, [last_TCP_port] |
call .findit |
mov [last_TCP_port], bx |
jmp .done |
|
|
.restart: |
mov bx, MIN_EPHEMERAL_PORT |
.findit: |
.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 |
jz .restart |
jle .continue |
|
call SOCKET_check_port |
jz .findit |
; todo: WRAP! |
; mov [last_UDP_port], MIN_EPHEMERAL_PORT |
.exit: |
xor ebx, ebx |
|
.port_ok: |
rol bx, 8 |
ret |
|
|
840,43 → 885,33 |
|
;----------------------------------------------------------------- |
; |
; SOCKET_check_port |
; SOCKET_check_port (local port) |
; |
; Checks if a local port number is unused |
; If the proposed port number is unused, it is filled in in the socket structure |
; works with INET byte order |
; |
; IN: eax = socket ptr (to find out if its a TCP/UDP socket) |
; bx = proposed socket number |
; IN: type in ecx (TCP/UDP) |
; port to check in bx |
; OUT: bx = 0 on error, unchanged otherwise |
; |
; OUT: ZF = cleared on error |
; |
;----------------------------------------------------------------- |
align 4 |
SOCKET_check_port: |
|
DEBUGF 1,"socket_check_port\n" |
|
mov ecx, [eax + SOCKET.Type] |
socket_check_port: |
mov esi, net_sockets |
|
.next_socket: |
mov esi, [esi + SOCKET.NextPtr] |
mov esi, [esi + SOCKET_head.NextPtr] |
or esi, esi |
jz .port_ok |
|
cmp [esi + SOCKET.Type], ecx |
cmp [esi + SOCKET_head.Type], ecx |
jne .next_socket |
|
cmp [esi + UDP_SOCKET.LocalPort], bx |
cmp [esi + SOCKET_head.end + IPv4_SOCKET.end + UDP_SOCKET.LocalPort], bx |
jne .next_socket |
|
DEBUGF 1,"local port %u already in use\n", bx |
ret |
xor ebx, ebx |
|
.port_ok: |
mov [eax + UDP_SOCKET.LocalPort], bx |
or bx, bx ; set the zero-flag |
|
ret |
|
|
883,409 → 918,243 |
|
;----------------------------------------------------------------- |
; |
; SOCKET_input |
; SOCKET_internal_receiver |
; |
; Updates a socket with received data |
; |
; Note: the mutex should already be set ! |
; Note: the mutex must already be set ! |
; |
; IN: eax = socket ptr |
; ebx = pointer to device struct |
; ecx = data size |
; esi = ptr to data |
; [esp] = ptr to buf |
; [esp + 4] = buf size |
; ecx = size |
; esi = pointer to buffer |
; edi = offset |
; |
; OUT: / |
; OUT: xxx |
; |
;----------------------------------------------------------------- |
align 4 |
SOCKET_input: |
socket_internal_receiver: |
|
DEBUGF 1,"socket_input: socket=%x, data=%x size=%u\n", eax, esi, ecx |
DEBUGF 1,"Internal socket receiver: buffer %x, offset: %x size=%u socket: %x\n", esi, edi, ecx, eax |
|
mov dword[esp+4], ecx |
push esi |
push edi ; offset |
push ecx ; size |
push esi ; data_ptr |
mov esi, esp |
|
add_to_queue (eax + SOCKET_QUEUE_LOCATION),\ |
SOCKET_QUEUE_SIZE,\ |
socket_queue_entry.size,\ |
SOCKET_input.full |
|
add_to_queue (eax + SOCKET_QUEUE_LOCATION), SOCKET_QUEUE_SIZE, socket_queue_entry.size, notify_network_event.full |
DEBUGF 1,"Queued packet successfully\n" |
add esp, socket_queue_entry.size |
mov [eax + SOCKET.lock], 0 |
jmp SOCKET_notify_owner |
|
.full: |
DEBUGF 2,"Socket %x is full!\n", eax |
mov [eax + SOCKET.lock], 0 |
call kernel_free |
add esp, 8 |
mov [eax + SOCKET_head.lock], 0 |
|
ret |
|
;----------------------------------------------------------------- |
; |
; SOCKET_notify_owner |
; |
; notify's the owner of a socket that something happened |
; |
; IN: eax = socket ptr |
; OUT: / |
; |
;----------------------------------------------------------------- |
align 4 |
SOCKET_notify_owner: |
|
DEBUGF 1,"socket_notify_owner\n" |
|
call SOCKET_check |
jz .error |
|
push ecx eax esi |
|
; socket exists, now try to flag an event to the application |
|
mov eax, [eax + SOCKET.PID] |
notify_network_event: |
; 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], eax |
cmp [esi], edx |
je .found_pid |
inc ecx |
add esi, 0x20 |
cmp ecx, [TASK_COUNT] |
jbe .next_pid |
ret |
|
; PID not found, TODO: close socket! |
|
jmp .error2 |
|
.found_pid: |
shl ecx, 8 |
or [ecx + SLOT_BASE + APPDATA.event_mask], EVENT_NETWORK |
or [ecx + SLOT_BASE + APPDATA.event_mask], EVENT_NETWORK ; stack event |
mov [check_idle_semaphore], 200 |
ret |
|
DEBUGF 1,"owner notified\n" |
.full: |
DEBUGF 2,"Socket %x is full!\n",eax |
mov [eax + SOCKET_head.lock], 0 |
call kernel_free |
add esp, 8 |
ret |
|
.error2: |
pop esi eax ecx |
.error: |
|
ret |
|
|
;-------------------------------------------------------------------- |
; |
; SOCKET_alloc |
; |
; 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). |
; |
; IN: / |
; OUT: eax = 0 on error, socket ptr otherwise |
; edi = socket number |
; ZF = cleared on error |
; @return socket structure address in EAX |
; |
;-------------------------------------------------------------------- |
align 4 |
SOCKET_alloc: |
|
push ecx ebx |
|
proc net_socket_alloc stdcall uses ebx ecx edx edi |
stdcall kernel_alloc, SOCKETBUFFSIZE |
DEBUGF 1, "socket_alloc: %x ", eax |
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 edi |
push eax |
mov edi, eax |
|
mov ecx, SOCKETBUFFSIZE / 4 |
; cld |
xor eax, eax |
rep stosd |
pop edi eax |
pop eax |
|
init_queue (eax + SOCKET_QUEUE_LOCATION) |
|
; 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.NextPtr] |
mov ebx, [ebx + SOCKET_head.NextPtr] |
or ebx, ebx |
jz .last_socket |
cmp [ebx + SOCKET.Number], ecx |
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: |
mov [eax + SOCKET.Number], ecx |
.last_socket_number: |
mov [eax + SOCKET_head.Number], ecx |
|
DEBUGF 1, "(number: %u)\n", ecx |
|
; Fill in PID |
mov ebx, [TASK_BASE] |
mov ebx, [ebx + TASKDATA.pid] |
|
mov [eax + SOCKET.PID], ebx |
|
; add socket to the list by changing pointers |
|
mov ebx, [net_sockets + SOCKET.NextPtr] |
|
mov [eax + SOCKET.PrevPtr], net_sockets |
mov [eax + SOCKET.NextPtr], ebx |
|
or ebx, ebx |
jz @f |
add ebx, SOCKET.lock ; lock the next socket |
call wait_mutex |
sub ebx, SOCKET.lock |
mov [ebx + SOCKET.PrevPtr], eax |
mov [ebx + SOCKET.lock], 0 |
@@: |
|
mov [net_sockets + SOCKET.NextPtr], eax |
|
mov edi, ecx |
or eax, eax ; used to clear zero flag |
.exit: |
pop ebx ecx |
|
ret |
endp |
|
|
;---------------------------------------------------- |
; Free socket data memory and pop socket off the list |
; |
; SOCKET_free |
; @param sockAddr is a socket structure address |
; |
; Free socket data memory and remove socket from the list |
; |
; IN: eax = socket ptr |
; OUT: / |
; |
;---------------------------------------------------- |
align 4 |
SOCKET_free: |
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 |
|
DEBUGF 1, "socket_free: %x\n", eax |
|
call SOCKET_check |
; 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 |
|
push ebx |
lea ebx, [eax + SOCKET.lock] |
call wait_mutex |
|
DEBUGF 1, "freeing socket..\n" |
|
push eax ; this will be passed to kernel_free |
mov ebx, [eax + SOCKET.NextPtr] |
mov eax, [eax + SOCKET.PrevPtr] |
|
DEBUGF 1, "linking socket %x to socket %x\n", eax, ebx |
|
test eax, eax |
; 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 [eax + SOCKET.NextPtr], ebx |
@@: |
mov [ebx + SOCKET_head.PrevPtr], eax |
|
test ebx, ebx |
jz @f |
mov [ebx + SOCKET.PrevPtr], eax |
@@: |
lea ebx, [eax + SOCKET_head.lock] |
call wait_mutex |
|
call kernel_free |
pop ebx |
@@: ; and finally free the memory structure used |
stdcall kernel_free, [sockAddr] |
ret |
|
DEBUGF 1, "socket is gone!\n" |
|
.error: |
DEBUGF 1, "K : failed\n" |
ret |
endp |
|
|
;--------------------------------------------------- |
; |
; SOCKET_num_to_ptr |
; |
; 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. |
; |
; IN: ecx = socket number |
; OUT: ecx = 0 on error, socket ptr otherwise |
; ZF = set on error |
; @param sockNum is a socket number |
; @return socket structure address or 0 (not found) in EAX |
; |
;--------------------------------------------------- |
align 4 |
SOCKET_num_to_ptr: |
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 |
|
DEBUGF 1,"socket_num_to_ptr: %u ", ecx |
|
mov eax, net_sockets |
|
; scan through sockets list |
mov ebx, net_sockets |
;mov ecx, [TASK_BASE] |
;mov ecx, [ecx + TASKDATA.pid] |
.next_socket: |
mov eax, [eax + SOCKET.NextPtr] |
or eax, eax |
mov ebx, [ebx + SOCKET_head.NextPtr] |
or ebx, ebx |
jz .error |
cmp [eax + SOCKET.Number], ecx |
cmp [ebx + SOCKET_head.Number], eax |
jne .next_socket |
;cmp [ebx + SOCKET.PID], ecx |
;jne .next_socket |
|
test eax, eax |
; okay, we found the correct one |
mov eax, ebx |
ret |
|
DEBUGF 1,"(%x)\n", eax |
.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. |
; |
; SOCKET_ptr_to_num |
; @param sockAddr is a socket structure address |
; @return socket number (SOCKET.Number) or 0 (not found) in EAX |
; |
; Get socket number by its address |
; |
; IN: eax = socket ptr |
; OUT: eax = 0 on error, socket num otherwise |
; ZF = set on error |
; |
;--------------------------------------------------- |
align 4 |
SOCKET_ptr_to_num: |
|
DEBUGF 1,"socket_ptr_to_num: %x ", eax |
|
call SOCKET_check |
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 |
|
mov eax, [eax + SOCKET.Number] |
|
DEBUGF 1,"(%u)\n", eax |
|
.error: |
ret |
|
|
;--------------------------------------------------- |
; |
; SOCKET_check |
; |
; checks if the given value is really a socket ptr |
; |
; IN: eax = socket ptr |
; OUT: eax = 0 on error, unchanged otherwise |
; ZF = set on error |
; |
;--------------------------------------------------- |
align 4 |
SOCKET_check: |
|
DEBUGF 1,"socket_check\n" |
|
push ebx |
; scan through sockets list |
mov ebx, net_sockets |
|
;mov ecx, [TASK_BASE] |
;mov ecx, [ecx + TASKDATA.pid] |
.next_socket: |
mov ebx, [ebx + SOCKET.NextPtr] |
mov ebx, [ebx + SOCKET_head.NextPtr] |
or ebx, ebx |
jz .done |
jz .error |
cmp ebx, eax |
jnz .next_socket |
jne .next_socket |
;cmp [ebx + SOCKET.PID], ecx |
;jne .next_socket |
|
.done: |
mov eax, ebx |
test eax, eax |
pop ebx |
|
; okay, we found the correct one |
mov eax, [ebx + SOCKET_head.Number] |
ret |
|
|
|
;--------------------------------------------------- |
; |
; SOCKET_check_owner |
; |
; checks if the caller application owns the socket |
; |
; IN: eax = socket ptr |
; OUT: ZF = true/false |
; |
;--------------------------------------------------- |
align 4 |
SOCKET_check_owner: |
|
DEBUGF 1,"socket_check_owner\n" |
|
push ebx |
mov ebx, [TASK_BASE] |
mov ebx, [ecx + TASKDATA.pid] |
cmp [eax + SOCKET.PID], ebx |
pop ebx |
|
.error: |
xor eax, eax |
ret |
|
|
|
|
;--------------------------------------------------- |
; |
; SOCKET_process_end |
; |
; Kernel calls this function when a certain process ends |
; This function will check if the process had any open sockets |
; And update them accordingly |
; |
; IN: eax = pid |
; OUT: / |
; |
;------------------------------------------------------ |
align 4 |
SOCKET_process_end: |
|
DEBUGF 1,"socket_process_end: %x\n", eax |
|
push ebx |
mov ebx, net_sockets |
|
.next_socket: |
|
mov ebx, [ebx + SOCKET.NextPtr] |
.test_socket: |
test ebx, ebx |
jz .done |
|
cmp [ebx + SOCKET.PID], eax |
jne .next_socket |
|
DEBUGF 1,"closing socket %x", eax, ebx |
|
mov [ebx + SOCKET.PID], 0 |
|
cmp [ebx + SOCKET.Type], IP_PROTO_UDP |
je .udp |
|
cmp [ebx + SOCKET.Type], IP_PROTO_TCP |
je .tcp |
|
jmp .next_socket ; kill all sockets for given PID |
|
.udp: |
mov eax, ebx |
mov ebx, [ebx + SOCKET.NextPtr] |
call SOCKET_free |
jmp .test_socket |
|
.tcp: |
|
jmp .next_socket |
|
.done: |
pop ebx |
|
ret |
endp |