added SocketAddress>>family
added Socket>>readBytes:offset:length: started writing Http.moo
This commit is contained in:
		
							
								
								
									
										190
									
								
								moo/kernel/Http.moo
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										190
									
								
								moo/kernel/Http.moo
									
									
									
									
									
										Normal 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.
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@ -216,9 +216,9 @@ class(#byte(16)) IP6Address(IP4Address)
 | 
			
		||||
 | 
			
		||||
class(#byte) SocketAddress(Object) from 'sck.addr'
 | 
			
		||||
{
 | 
			
		||||
	##method(#primitive) family.
 | 
			
		||||
	method(#primitive) family.
 | 
			
		||||
	method(#primitive) fromString: str.
 | 
			
		||||
	
 | 
			
		||||
 | 
			
		||||
	method(#class) 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 internal representation used by various modules. (e.g. sck)
 | 
			
		||||
	var(#get) handle := -1.
 | 
			
		||||
	var(#get) closedEventAction := nil.
 | 
			
		||||
 | 
			
		||||
	##method initialize
 | 
			
		||||
	##{
 | 
			
		||||
@ -242,9 +243,25 @@ class AsyncHandle(Object)
 | 
			
		||||
		{
 | 
			
		||||
			self _close.
 | 
			
		||||
			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
 | 
			
		||||
	{
 | 
			
		||||
		^self writeBytes: bytes offset: offset length: length.
 | 
			
		||||
@ -264,7 +281,7 @@ class Socket(AsyncHandle) from 'sck'
 | 
			
		||||
	var pending_bytes, pending_offset, pending_length.
 | 
			
		||||
	var outreadysem, outdonesem, inreadysem.
 | 
			
		||||
 | 
			
		||||
	method(#primitive) open(domain, type, proto).
 | 
			
		||||
	method(#primitive) open(family, type, proto).
 | 
			
		||||
	method(#primitive) _close.
 | 
			
		||||
	method(#primitive) bind: addr.
 | 
			
		||||
	method(#primitive) _listen: backlog.
 | 
			
		||||
@ -273,12 +290,13 @@ class Socket(AsyncHandle) from 'sck'
 | 
			
		||||
	method(#primitive) _socketError.
 | 
			
		||||
 | 
			
		||||
	method(#primitive) readBytes: bytes.
 | 
			
		||||
	method(#primitive) readBytes: bytes offset: offset length: length.
 | 
			
		||||
	method(#primitive) _writeBytes: bytes.
 | 
			
		||||
	method(#primitive) _writeBytes: bytes offset: offset length: length.
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
(* TODO: generate these domain and type from the C header *)
 | 
			
		||||
pooldic Socket.Domain
 | 
			
		||||
(* TODO: generate these family and type from the C header *)
 | 
			
		||||
pooldic Socket.Family
 | 
			
		||||
{
 | 
			
		||||
	INET := 2.
 | 
			
		||||
	INET6 := 10.
 | 
			
		||||
@ -295,9 +313,9 @@ extend Socket
 | 
			
		||||
	method(#class) new { 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
 | 
			
		||||
@ -351,8 +369,6 @@ extend Socket
 | 
			
		||||
	
 | 
			
		||||
	method close
 | 
			
		||||
	{
 | 
			
		||||
'Socket close' dump.
 | 
			
		||||
 | 
			
		||||
		if (self.outdonesem notNil)
 | 
			
		||||
		{
 | 
			
		||||
			System unsignal: self.outdonesem.
 | 
			
		||||
@ -390,7 +406,7 @@ extend Socket
 | 
			
		||||
		}
 | 
			
		||||
		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.
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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.
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -55,36 +55,9 @@
 | 
			
		||||
 | 
			
		||||
#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
 | 
			
		||||
{
 | 
			
		||||
	struct sockaddr    sa;
 | 
			
		||||
#if (MOO_SIZEOF_STRUCT_SOCKADDR_IN > 0)
 | 
			
		||||
	struct sockaddr_in in4;
 | 
			
		||||
#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;
 | 
			
		||||
	int dots = 0, digits = 0;
 | 
			
		||||
	moo_uint32_t acc = 0, addr = 0;	
 | 
			
		||||
	moo_uint32_t acc = 0, addr = 0;
 | 
			
		||||
	moo_ooch_t c;
 | 
			
		||||
 | 
			
		||||
	end = str + len;
 | 
			
		||||
@ -482,6 +455,21 @@ no_rbrack:
 | 
			
		||||
	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)
 | 
			
		||||
{
 | 
			
		||||
@ -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[] =
 | 
			
		||||
{
 | 
			
		||||
	{ 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)
 | 
			
		||||
{
 | 
			
		||||
	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);
 | 
			
		||||
	if (!MOO_CLASS_SPEC_IS_INDEXED(spec) || MOO_CLASS_SPEC_INDEXED_TYPE(spec) != MOO_OBJ_TYPE_BYTE || MOO_CLASS_SPEC_NAMED_INSTVARS(spec) != 0)
 | 
			
		||||
 | 
			
		||||
@ -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;
 | 
			
		||||
	moo_oop_byte_t buf;
 | 
			
		||||
	moo_oow_t offset, length, maxlen;
 | 
			
		||||
	int fd;
 | 
			
		||||
	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;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	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)
 | 
			
		||||
	{
 | 
			
		||||
		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, { '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',':','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, { '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  }  }
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user