added SocketAddress>>family

added Socket>>readBytes:offset:length:
started writing Http.moo
This commit is contained in:
hyunghwan.chung 2018-05-09 10:37:07 +00:00
parent 82160e03dd
commit bc93856b35
4 changed files with 267 additions and 148 deletions

190
moo/kernel/Http.moo Normal file
View File

@ -0,0 +1,190 @@
###include 'Moo.moo'.
#include 'Socket.moo'.
class HttpServerSocket(ServerSocket)
{
}
class HttpServer(Object)
{
var server_sockets.
method initialize
{
server_sockets := LinkedList new.
}
method start: laddr
{
| sck |
if (laddr class == Array)
{
laddr do: [:addr |
sck := ServerSocket family: (addr family) type: Socket.Type.STREAM.
self.server_sockets addLast: sck.
sck bind: addr.
].
}
else
{
sck := ServerSocket family: (laddr family) type: Socket.Type.STREAM.
self.server_sockets addLast: sck.
sck bind: laddr.
}.
self.server_sockets do: [:ssck |
ssck listen: 128.
].
}
method close
{
self.server_sockets do: [:sck |
sck close.
].
while (self.server_sockets size > 0)
{
self.server_sockets removeLastLink.
}.
}
}
class MyObject(Object)
{
method(#class) start_server_socket
{
| s2 buf |
s2 := ServerSocket family: Socket.Family.INET type: Socket.Type.STREAM.
buf := ByteArray new: 128.
s2 onEvent: #accepted do: [ :sck :clisck :cliaddr |
'SERVER ACCEPTED new client' dump.
clisck onEvent: #data_in do: [ :csck |
| nbytes |
while (true)
{
nbytes := csck readBytes: buf.
if (nbytes <= 0)
{
if (nbytes == 0) { csck close }.
('Got ' & (nbytes asString)) dump.
break.
}.
buf dump.
csck writeBytes: buf offset: 0 length: nbytes.
}.
].
clisck onEvent: #data_out do: [ :csck |
##csck writeBytes: #[ $a, $b, C'\n' ].
].
clisck onEvent: #closed do: [ :csck |
'Socket CLOSED....' dump.
].
].
s2 bind: (SocketAddress fromString: '0.0.0.0:7777').
s2 listen: 10.
^s2.
}
method(#class) start_client_socket
{
| s buf count |
s := ClientSocket family: Socket.Family.INET type: Socket.Type.STREAM.
buf := ByteArray new: 128.
count := 0.
s onEvent: #connected do: [ :sck :state |
if (state)
{
s writeBytes: #[ $a, $b, $c ].
s writeBytes: #[ $d, $e, $f ].
}
else
{
'FAILED TO CONNECT' dump.
}.
].
s onEvent: #data_in do: [ :sck |
| nbytes |
while (true)
{
nbytes := sck readBytes: buf.
if (nbytes <= 0)
{
if (nbytes == 0) { sck close }.
break.
}.
('Got ' & (nbytes asString)) dump.
buf dump.
}.
].
s onEvent: #data_out do: [ :sck |
if (count < 10) { sck writeBytes: #[ $a, $b, C'\n' ]. count := count + 1. }.
].
s connect: (SocketAddress fromString: '127.0.0.1:9999').
}
method(#class) mainxx
{
[
| s s2 ss |
[
s := self start_client_socket.
s2 := self start_server_socket.
while (true)
{
ss := System handleAsyncEvent.
if (ss isError) { break }.
###if (ss == st) { System removeAsyncSemaphore: st }.
}.
]
ensure:
[
if (s notNil) { s close }.
if (s2 notNil) { s2 close }.
]
] on: Exception do: [:ex | ('Exception - ' & ex messageText) dump ].
'----- END OF MAIN ------' dump.
}
method(#class) main
{
| httpd |
[
httpd := HttpServer new.
[
| ss |
httpd start: %(
SocketAddress fromString: '[::]:7777',
SocketAddress fromString: '0.0.0.0:7776'
).
while (true) {
ss := System handleAsyncEvent.
if (ss isError) { break }.
}.
] ensure: [
if (httpd notNil) { httpd close }
]
] on: Exception do: [:ex | ('Exception - ' & ex messageText) dump].
'----- END OF MAIN ------' dump.
}
}

View File

@ -216,9 +216,9 @@ class(#byte(16)) IP6Address(IP4Address)
class(#byte) SocketAddress(Object) from 'sck.addr' class(#byte) SocketAddress(Object) from 'sck.addr'
{ {
##method(#primitive) family. method(#primitive) family.
method(#primitive) fromString: str. method(#primitive) fromString: str.
method(#class) fromString: str method(#class) fromString: str
{ {
^self new fromString: str ^self new fromString: str
@ -230,6 +230,7 @@ class AsyncHandle(Object)
## the handle must be the first field in this object to match ## the handle must be the first field in this object to match
## the internal representation used by various modules. (e.g. sck) ## the internal representation used by various modules. (e.g. sck)
var(#get) handle := -1. var(#get) handle := -1.
var(#get) closedEventAction := nil.
##method initialize ##method initialize
##{ ##{
@ -242,9 +243,25 @@ class AsyncHandle(Object)
{ {
self _close. self _close.
self.handle := -1. self.handle := -1.
if (self.closedEventAction notNil)
{
self.closedEventAction value: self.
}.
} }
} }
method onEvent: event_type do: action_block
{
if (event_type == #closed)
{
self.closedEventAction := action_block.
^self.
}.
Exception signal: 'unknown event type ' & event_type asString.
}
method writeBytes: bytes offset: offset length: length method writeBytes: bytes offset: offset length: length
{ {
^self writeBytes: bytes offset: offset length: length. ^self writeBytes: bytes offset: offset length: length.
@ -264,7 +281,7 @@ class Socket(AsyncHandle) from 'sck'
var pending_bytes, pending_offset, pending_length. var pending_bytes, pending_offset, pending_length.
var outreadysem, outdonesem, inreadysem. var outreadysem, outdonesem, inreadysem.
method(#primitive) open(domain, type, proto). method(#primitive) open(family, type, proto).
method(#primitive) _close. method(#primitive) _close.
method(#primitive) bind: addr. method(#primitive) bind: addr.
method(#primitive) _listen: backlog. method(#primitive) _listen: backlog.
@ -273,12 +290,13 @@ class Socket(AsyncHandle) from 'sck'
method(#primitive) _socketError. method(#primitive) _socketError.
method(#primitive) readBytes: bytes. method(#primitive) readBytes: bytes.
method(#primitive) readBytes: bytes offset: offset length: length.
method(#primitive) _writeBytes: bytes. method(#primitive) _writeBytes: bytes.
method(#primitive) _writeBytes: bytes offset: offset length: length. method(#primitive) _writeBytes: bytes offset: offset length: length.
} }
(* TODO: generate these domain and type from the C header *) (* TODO: generate these family and type from the C header *)
pooldic Socket.Domain pooldic Socket.Family
{ {
INET := 2. INET := 2.
INET6 := 10. INET6 := 10.
@ -295,9 +313,9 @@ extend Socket
method(#class) new { self messageProhibited: #new } method(#class) new { self messageProhibited: #new }
method(#class) new: size { self messageProhibited: #new: } method(#class) new: size { self messageProhibited: #new: }
method(#class) domain: domain type: type method(#class) family: family type: type
{ {
^(super new) open(domain, type, 0) ^(super new) open(family, type, 0)
} }
method initialize method initialize
@ -351,8 +369,6 @@ extend Socket
method close method close
{ {
'Socket close' dump.
if (self.outdonesem notNil) if (self.outdonesem notNil)
{ {
System unsignal: self.outdonesem. System unsignal: self.outdonesem.
@ -390,7 +406,7 @@ extend Socket
} }
else else
{ {
Exception signal: 'unknown event type ' & event_type asString. ^super onEvent: event_type do: action_block.
} }
} }
@ -569,109 +585,3 @@ class ServerSocket(Socket)
^self _listen: backlog. ^self _listen: backlog.
} }
} }
class MyObject(Object)
{
method(#class) start_server_socket
{
| s2 buf |
s2 := ServerSocket domain: Socket.Domain.INET type: Socket.Type.STREAM.
buf := ByteArray new: 128.
s2 onEvent: #accepted do: [ :sck :clisck :cliaddr |
'SERVER ACCEPTED new client' dump.
clisck onEvent: #data_in do: [ :csck |
| nbytes |
while (true)
{
nbytes := csck readBytes: buf.
if (nbytes <= 0)
{
if (nbytes == 0) { csck close }.
('Got ' & (nbytes asString)) dump.
break.
}.
buf dump.
csck writeBytes: buf offset: 0 length: nbytes.
}.
].
clisck onEvent: #data_out do: [ :csck |
##csck writeBytes: #[ $a, $b, C'\n' ].
].
].
s2 bind: (SocketAddress fromString: '0.0.0.0:7777').
s2 listen: 10.
^s2.
}
method(#class) start_client_socket
{
| s buf count |
s := ClientSocket domain: Socket.Domain.INET type: Socket.Type.STREAM.
buf := ByteArray new: 128.
count := 0.
s onEvent: #connected do: [ :sck :state |
if (state)
{
s writeBytes: #[ $a, $b, $c ].
s writeBytes: #[ $d, $e, $f ].
}
else
{
'FAILED TO CONNECT' dump.
}.
].
s onEvent: #data_in do: [ :sck |
| nbytes |
while (true)
{
nbytes := sck readBytes: buf.
if (nbytes <= 0)
{
if (nbytes == 0) { sck close }.
break.
}.
('Got ' & (nbytes asString)) dump.
buf dump.
}.
].
s onEvent: #data_out do: [ :sck |
if (count < 10) { sck writeBytes: #[ $a, $b, C'\n' ]. count := count + 1. }.
].
s connect: (SocketAddress fromString: '127.0.0.1:9999').
}
method(#class) main
{
[
| s s2 ss |
[
s := self start_client_socket.
s2 := self start_server_socket.
while (true)
{
ss := System handleAsyncEvent.
if (ss isError) { break }.
###if (ss == st) { System removeAsyncSemaphore: st }.
}.
]
ensure:
[
if (s notNil) { s close }.
if (s2 notNil) { s2 close }.
]
] on: Exception do: [:ex | ('Exception - ' & ex messageText) dump ].
'----- END OF MAIN ------' dump.
}
}

View File

@ -55,36 +55,9 @@
#define MA MOO_TYPE_MAX(moo_oow_t) #define MA MOO_TYPE_MAX(moo_oow_t)
typedef struct sck_addr_trailer_t sck_addr_trailer_t;
struct sck_addr_trailer_t
{
int family;
union
{
struct
{
moo_uint16_t port;
moo_uint32_t addr;
} in4;
struct
{
moo_uint16_t port;
moo_uint8_t addr[16];
moo_uint32_t scope;
} in6;
/*
struct
{
moo_ooch_t path[100];
} local; */
} u;
};
union sockaddr_t union sockaddr_t
{ {
struct sockaddr sa;
#if (MOO_SIZEOF_STRUCT_SOCKADDR_IN > 0) #if (MOO_SIZEOF_STRUCT_SOCKADDR_IN > 0)
struct sockaddr_in in4; struct sockaddr_in in4;
#endif #endif
@ -104,7 +77,7 @@ static int str_to_ipv4 (const moo_ooch_t* str, moo_oow_t len, struct in_addr* in
{ {
const moo_ooch_t* end; const moo_ooch_t* end;
int dots = 0, digits = 0; int dots = 0, digits = 0;
moo_uint32_t acc = 0, addr = 0; moo_uint32_t acc = 0, addr = 0;
moo_ooch_t c; moo_ooch_t c;
end = str + len; end = str + len;
@ -482,6 +455,21 @@ no_rbrack:
return -1; return -1;
} }
static moo_pfrc_t pf_get_family (moo_t* moo, moo_mod_t* mod, moo_ooi_t nargs)
{
moo_oop_t rcv;
moo_oop_t v;
struct sockaddr* sa;
rcv = (moo_oop_t)MOO_STACK_GETRCV(moo, nargs);
MOO_PF_CHECK_RCV (moo, MOO_OBJ_IS_BYTE_POINTER(rcv) && MOO_OBJ_GET_SIZE(rcv) >= MOO_SIZEOF(sockaddr_t));
sa = (struct sockaddr*)MOO_OBJ_GET_BYTE_SLOT(rcv);
v = MOO_SMOOI_TO_OOP(sa->sa_family);
MOO_STACK_SETRET (moo, nargs, v);
return MOO_PF_SUCCESS;
}
static moo_pfrc_t pf_from_string (moo_t* moo, moo_mod_t* mod, moo_ooi_t nargs) static moo_pfrc_t pf_from_string (moo_t* moo, moo_mod_t* mod, moo_ooi_t nargs)
{ {
@ -506,7 +494,8 @@ static moo_pfrc_t pf_from_string (moo_t* moo, moo_mod_t* mod, moo_ooi_t nargs)
static moo_pfinfo_t pfinfos[] = static moo_pfinfo_t pfinfos[] =
{ {
{ I, { 'f','r','o','m','S','t','r','i','n','g',':','\0' }, 0, { pf_from_string, 1, 1 } }, { I, { 'f','a','m','i','l','y' }, 0, { pf_get_family, 0, 0 } },
{ I, { 'f','r','o','m','S','t','r','i','n','g',':','\0' }, 0, { pf_from_string, 1, 1 } }
}; };
/* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */
@ -514,7 +503,6 @@ static moo_pfinfo_t pfinfos[] =
static int import (moo_t* moo, moo_mod_t* mod, moo_oop_class_t _class) static int import (moo_t* moo, moo_mod_t* mod, moo_oop_class_t _class)
{ {
moo_ooi_t spec; moo_ooi_t spec;
/*if (moo_setclasstrsize (moo, _class, MOO_SIZEOF(sck_addr_trailer_t), MOO_NULL) <= -1) return -1;*/
spec = MOO_OOP_TO_SMOOI(_class->spec); spec = MOO_OOP_TO_SMOOI(_class->spec);
if (!MOO_CLASS_SPEC_IS_INDEXED(spec) || MOO_CLASS_SPEC_INDEXED_TYPE(spec) != MOO_OBJ_TYPE_BYTE || MOO_CLASS_SPEC_NAMED_INSTVARS(spec) != 0) if (!MOO_CLASS_SPEC_IS_INDEXED(spec) || MOO_CLASS_SPEC_INDEXED_TYPE(spec) != MOO_OBJ_TYPE_BYTE || MOO_CLASS_SPEC_NAMED_INSTVARS(spec) != 0)

View File

@ -404,6 +404,7 @@ static moo_pfrc_t pf_read_socket (moo_t* moo, moo_mod_t* mod, moo_ooi_t nargs)
{ {
oop_sck_t sck; oop_sck_t sck;
moo_oop_byte_t buf; moo_oop_byte_t buf;
moo_oow_t offset, length, maxlen;
int fd; int fd;
ssize_t n; ssize_t n;
@ -428,7 +429,36 @@ static moo_pfrc_t pf_read_socket (moo_t* moo, moo_mod_t* mod, moo_ooi_t nargs)
return MOO_PF_FAILURE; return MOO_PF_FAILURE;
} }
n = recv(fd, MOO_OBJ_GET_BYTE_SLOT(buf), MOO_OBJ_GET_SIZE(buf), 0); offset = 0;
maxlen = MOO_OBJ_GET_SIZE(buf);
length = maxlen;
if (nargs >= 2)
{
moo_oop_t tmp;
tmp = MOO_STACK_GETARG(moo, nargs, 1);
if (moo_inttooow (moo, tmp, &offset) <= 0)
{
moo_seterrbfmt (moo, MOO_EINVAL, "invalid offset - %O", tmp);
return MOO_PF_FAILURE;
}
if (nargs >= 3)
{
tmp = MOO_STACK_GETARG(moo, nargs, 2);
if (moo_inttooow(moo, tmp, &length) <= 0)
{
moo_seterrbfmt (moo, MOO_EINVAL, "invalid length - %O", tmp);
return MOO_PF_FAILURE;
}
}
if (offset >= maxlen) offset = maxlen - 1;
if (length > maxlen - offset) length = maxlen - offset;
}
n = recv(fd, &MOO_OBJ_GET_BYTE_SLOT(buf)[offset], length, 0);
if (n <= -1 && errno != EWOULDBLOCK && errno != EAGAIN) if (n <= -1 && errno != EWOULDBLOCK && errno != EAGAIN)
{ {
moo_seterrwithsyserr (moo, errno); moo_seterrwithsyserr (moo, errno);
@ -540,6 +570,7 @@ static moo_pfinfo_t pfinfos[] =
{ I, { 'l','i','s','t','e','n',':','\0' }, 0, { pf_listen_socket, 1, 1 } }, { I, { 'l','i','s','t','e','n',':','\0' }, 0, { pf_listen_socket, 1, 1 } },
{ I, { 'o','p','e','n','\0' }, 0, { pf_open_socket, 3, 3 } }, { I, { 'o','p','e','n','\0' }, 0, { pf_open_socket, 3, 3 } },
{ I, { 'r','e','a','d','B','y','t','e','s',':','\0' }, 0, { pf_read_socket, 1, 1 } }, { I, { 'r','e','a','d','B','y','t','e','s',':','\0' }, 0, { pf_read_socket, 1, 1 } },
{ I, { 'r','e','a','d','B','y','t','e','s',':','o','f','f','s','e','t',':','l','e','n','g','t','h',':','\0' }, 0, { pf_read_socket, 3, 3 } },
{ I, { 's','o','c','k','e','t','E','r','r','o','r','\0' }, 0, { pf_get_socket_error, 0, 0 } }, { I, { 's','o','c','k','e','t','E','r','r','o','r','\0' }, 0, { pf_get_socket_error, 0, 0 } },
{ I, { 'w','r','i','t','e','B','y','t','e','s',':','\0' }, 0, { pf_write_socket, 1, 1 } }, { I, { 'w','r','i','t','e','B','y','t','e','s',':','\0' }, 0, { pf_write_socket, 1, 1 } },
{ I, { 'w','r','i','t','e','B','y','t','e','s',':','o','f','f','s','e','t',':','l','e','n','g','t','h',':','\0' }, 0, { pf_write_socket, 3, 3 } } { I, { 'w','r','i','t','e','B','y','t','e','s',':','o','f','f','s','e','t',':','l','e','n','g','t','h',':','\0' }, 0, { pf_write_socket, 3, 3 } }