It would be even easier to bypass the HLL and simply purchase a program to do this. I understand MicroSoft sells 'em.
However, I got the impression that Great Cat wanted to do this at a low level, specifically in Nasm. Perhaps this is an "English" problem, but I don't think so.
There is only one system call to deal with sockets. HLLs - and asm macros - treat it as if there were several - "socket", "connect", "bind", "listen", "accept", "send", recv", etc. etc. etc. These are subfunctions, "commands" - small integers which go in ebx. They use the same sys_socketcall, 102. Remaining arguments - they differ with the subfunction - are pointed to by ecx. Typically, they're on the stack, but don't have to be.
The "port" we ask to connect to determines whether we get an http server, or a mail server, or an nntp server, etc. This is just a 16-bit number (word) - big endian. No relation to the "port" we get with the "in" and "out" instructions!
I have only gotten as far as a simple "echo" server and client, on "port" 2002, and on the "loopback" connection - it doesn't actually talk to a second computer - just from one console to another. For "testing" purposes, it's easier if you don't have to be on two computers at once.
I don't really remember just what I did here, and they're not too well commented, but let me just throw 'em out here and see if you can get any help at all from them...
; echo server
; echos lines until "quit"
; "kill" unloads server
; runs on loopback, 127.0.0.1, and port 2002,
; no options on this model!
;
; nasm -f elf echosrv.asm
; ld -o echosrv echosrv.o
global _start
;-------------------
; should probably be in an .inc file
struc sockaddr_in
.sin_family resw 1
.sin_port resw 1
.sin_addr resd 1
.sin_zero resb 8
endstruc
; Convert numbers (constants!) to network byte order
%define hton(x) ((x & 0xFF000000) >> 24) | ((x & 0x00FF0000) >> 8) | ((x & 0x0000FF00) << 8) | ((x & 0x000000FF) << 24)
%define htons(x) ((x >> 8) & 0xFF) | ((x & 0xFF) << 8)
AF_INET equ 2
SOCK_STREAM equ 1
INADDR_ANY equ 0 ; /usr/include/linux/in.h
STDIN equ 0
STDOUT equ 1
LF equ 10
EINTR equ 4
__NR_exit equ 1
__NR_read equ 3
__NR_write equ 4
__NR_close equ 6
__NR_socketcall equ 102
; commands for sys_socketcall
; /usr/include/linux/in.h
SYS_SOCKET equ 1
SYS_BIND equ 2
SYS_CONNECT equ 3
SYS_LISTEN equ 4
SYS_ACCEPT equ 5
SYS_SEND equ 9
SYS_RECV equ 10
;------------------------
;_ip equ 0x7F000001 ; loopback - 127.0.0.1
_ip equ 0xC0A8012F ; loopback - 127.0.0.1
_port equ 2002
; Convert 'em to network byte order
IP equ hton(_ip)
PORT equ htons(_port)
BACKLOG equ 128 ; for "listen"
BUFLEN equ 1000
section .data
my_sa istruc sockaddr_in
at sockaddr_in.sin_family, dw AF_INET
at sockaddr_in.sin_port, dw PORT
at sockaddr_in.sin_addr, dd INADDR_ANY
at sockaddr_in.sin_zero, dd 0, 0
iend
socket_args dd AF_INET, SOCK_STREAM, 0
; first of these wants to be socket descriptor
; we fill it in later...
bind_args dd 0, my_sa, sockaddr_in_size
listen_args dd 0, BACKLOG
accept_args dd 0, 0, 0
section .bss
my_buf resb BUFLEN
fd_socket resd 1
fd_conn resd 1
section .text
_start:
; socket(AF_INET, SOCK_STREAM, 0)
mov ecx, socket_args ; address of args structure
mov ebx, SYS_SOCKET ; subfunction or "command"
mov eax, __NR_socketcall ;c.f. /usr/src/linux/net/socket.c
int 80h
cmp eax, -4096
ja exit
mov [fd_socket], eax
; and fill in bind_args, etc.
mov [bind_args], eax
mov [listen_args], eax
mov [accept_args], eax
mov ecx, bind_args
mov ebx, SYS_BIND ; subfunction or "command"
mov eax, __NR_socketcall
int 80h
cmp eax, -4096
ja exit
mov ecx, listen_args
mov ebx, SYS_LISTEN ; subfunction or "command"
mov eax, __NR_socketcall
int 80h
cmp eax, -4096
ja exit
again:
mov ecx, accept_args
mov ebx, SYS_ACCEPT ; subfunction or "command"
mov eax, __NR_socketcall
int 80h
cmp eax, -4096
ja exit
mov [fd_conn], eax
readagain:
; read(sock, buf, len)
push BUFLEN ; arg 3: max count
push my_buf ; arg 2: buffer
push dword [fd_conn] ; arg 1: fd
call readline
add esp, 12
test eax, eax
js closeconn
push eax ; length read is length to write
push my_buf
push dword [fd_conn]
call writeNbytes
add esp, 12
cmp dword [my_buf], 'quit'
jz closeconn
cmp dword [my_buf], 'kill'
jz killserver
jmp readagain
closeconn:
mov eax, __NR_close
mov ebx, [fd_conn]
int 80h
cmp eax, -4096
ja exit
jmp again
killserver:
mov eax, __NR_close
mov ebx, [fd_conn]
int 80h
mov eax, __NR_close
mov ebx, [fd_socket]
int 80h
goodexit:
xor eax, eax ; success
exit:
mov ebx, eax ; exitcode
neg ebx
mov eax, __NR_exit
int 80h
;-----------------------
readline:
push ebp
mov ebp, esp
sub esp, 4
pusha
%define fd ebp + 8
%define buf ebp + 12
%define max ebp + 16
%define result ebp - 4
mov dword [result], 0
mov ebx, [fd]
mov ecx, [buf]
mov edx, [max]
.reread:
mov eax, __NR_read
int 80h
cmp eax, -EINTR
jz .reread
cmp eax, -4096
ja .err
add [result], eax
cmp byte [eax + ecx - 1], LF
jz .done
add ecx, eax
sub edx, eax
jna .done
jmp .reread
.done:
popa
mov eax, [result]
mov esp, ebp
pop ebp
ret
.err:
mov [result], eax
jmp .done
%undef fd
%undef buf
%undef max
%undef result
;--------------
writeNbytes:
push ebp
mov ebp, esp
sub esp, 4
pusha
%define fd ebp + 8
%define buf ebp + 12
%define Nbytes ebp + 16
%define bytesleft ebp - 4
mov ebx, [fd]
mov ecx, [buf]
mov edx, [Nbytes]
mov [bytesleft], edx
.rewrite:
mov eax, __NR_write
int 80h
cmp eax, -EINTR
jz .rewrite
cmp eax, -4096
ja exit
sub [bytesleft], eax
jz .done
add ecx, eax
sub edx, eax
jna .done
jmp .rewrite
.done:
popa
mov eax, [Nbytes]
%undef fd
%undef buf
%undef Nbytes
%undef bytesleft
mov esp, ebp
pop ebp
ret
... and a client...
;-----------------------------
;
; nasm -f elf32 echocli.asm
; ld -o echocli echocli.o
global _start
struc sockaddr_in
.sin_family resw 1
.sin_port resw 1
.sin_addr resd 1
.sin_zero resb 8
endstruc
_ip equ 0x7F000001 ; loopback - 127.0.0.1
;_ip equ 0x48400C6B ; loopback - 127.0.0.1
_port equ 2002
; Convert numbers to network byte order
IP equ ((_ip & 0xFF000000) >> 24) | ((_ip & 0x00FF0000) >> 8) | ((_ip & 0x0000FF00) << 8) | ((_ip & 0x000000FF) << 24)
PORT equ ((_port >> 8) & 0xFF) | ((_port & 0xFF) << 8)
AF_INET equ 2
SOCK_STREAM equ 1
BUFLEN equ 0x80
STDIN equ 0
STDOUT equ 1
LF equ 10
EINTR equ 4
__NR_exit equ 1
__NR_read equ 3
__NR_write equ 4
__NR_socketcall equ 102
SYS_SOCKET equ 1
SYS_CONNECT equ 3
section .data
my_sa istruc sockaddr_in
at sockaddr_in.sin_family, dw AF_INET
at sockaddr_in.sin_port, dw PORT
at sockaddr_in.sin_addr, dd IP
at sockaddr_in.sin_zero, dd 0, 0
iend
socket_args dd AF_INET, SOCK_STREAM, 0
; first of these wants to be socket descriptor
; we fill it in later...
connect_args dd 0, my_sa, sockaddr_in_size
section .bss
my_buf resb BUFLEN
sock_desc resd 1
section .text
_start:
; socket(AF_INET, SOCK_STREAM, 0)
mov ecx, socket_args ; address of args structure
mov ebx, SYS_SOCKET ; subfunction or "command"
mov eax, __NR_socketcall ;c.f. /usr/src/linux/net/socket.c
int 80h
cmp eax, -4096
ja exit
mov [sock_desc], eax
; and fill in connect_args
mov [connect_args], eax
; connect(sock, (struct sockaddr *)&sa, sizeof(struct sockaddr))
mov ecx, connect_args
mov ebx, SYS_CONNECT ; subfunction or "command"
mov eax, __NR_socketcall
int 80h
cmp eax, -4096
ja exit
again:
push BUFLEN
push my_buf
push STDIN
call readline
add esp, 12
push eax
push my_buf
push dword [sock_desc]
call writeNbytes
add esp, 12
cmp dword [my_buf], 'quit'
jz goodexit
push BUFLEN
push my_buf
push dword [sock_desc]
call readline
add esp, 12
push eax
push my_buf
push STDOUT
call writeNbytes
add esp, 12
jmp again
goodexit:
xor eax, eax ; success
exit:
mov ebx, eax ; exitcode
neg ebx
mov eax, __NR_exit
int 80h
readline:
push ebp
mov ebp, esp
sub esp, 4
pusha
%define fd ebp + 8
%define buf ebp + 12
%define max ebp + 16
%define result ebp - 4
mov dword [result], 0
mov ebx, [fd]
mov ecx, [buf]
mov edx, [max]
.reread:
mov eax, __NR_read
int 80h
cmp eax, -EINTR
jz .reread
cmp eax, -4096
ja exit
add [result], eax
cmp byte [eax + ecx - 1], LF
jz .done
add ecx, eax
sub edx, eax
jna .done
jmp .reread
.done:
popa
mov eax, [result]
%undef fd
%undef buf
%undef max
%undef result
mov esp, ebp
pop ebp
ret
writeNbytes:
push ebp
mov ebp, esp
sub esp, 4
pusha
%define fd ebp + 8
%define buf ebp + 12
%define Nbytes ebp + 16
%define bytesleft ebp - 4
mov ebx, [fd]
mov ecx, [buf]
mov edx, [Nbytes]
mov [bytesleft], edx
.rewrite:
mov eax, __NR_write
int 80h
cmp eax, -EINTR
jz .rewrite
cmp eax, -4096
ja exit
sub [bytesleft], eax
jz .done
add ecx, eax
sub edx, eax
jna .done
jmp .rewrite
.done:
popa
mov eax, [Nbytes]
%undef fd
%undef buf
%undef Nbytes
%undef bytesleft
mov esp, ebp
pop ebp
ret
I don't know too much about this stuff, and don't remember all of the little I learned, but I'll try to answer questions if I can.
You should also read Beej's Guide, of course!
Best,
Frank