/*

CLASS {NATIVE_Socket|_Gcc},
UNTESTED, NATIVE, BYTES:

IMPORT: {Socket}, {String_functions} .

NATIVE: "///COPY NATIVE_Socket.*" .

FUN Create_socket(
{address_family} Address|_family,
{socket_type} Type|_of_socket,
{protocol} Protocol,
BOOL Is_server) ==> INT, NATIVE: @
	"RESULT = NATIVE_socket::Create_socket("
	"	X_Address, X_Type, X_Protocol, X_Is_server);" .
	
*/

#ifdef SEPARATE_UNITS
    #include "NATIVE_Socket.h"
#endif

int NATIVE_socket::Create_socket(
		byte X_Address,
		byte X_Type,
		byte X_Protocol,
		bool X_Is_server)
{
#ifdef MSWINDOWS
	static WSAData wsaData;
	static bool WinSocks_initialized = false;
#endif

	int s;
	int prot;
#ifdef MSWINDOWS
	if (!WinSocks_initialized)
	{
		WSAStartup(MAKEWORD(2,0), &wsaData);
		WinSocks_initialized = true;
	}
#endif

	if (X_Address != 15 //InterNetwork
		&& X_Address != 16 //InterNetworkV6
	   ) return 0;
	
	if (X_Type != 1 //Dgram
	   && X_Type != 5 //Stream
	   ) return 0;

	if (X_Protocol != 22 //TCP
	   && X_Protocol != 23 //UDP
	   ) return 0;
    
    if (X_Protocol == 23) prot = IPPROTO_UDP;
    else prot = IPPROTO_TCP;
    
    s = socket(AF_INET, SOCK_STREAM, prot);
	if (s == -1) return 0;
	
	return s;
}

/*

---------------------------------- 'SERVER'

FUN Listen_socket(
{Socket} SO|bject_socket,
STR Host|_address,
INT Port|_number_or_0,
INT Max_queue) ==> BOOL, NATIVE:
	CASE SO.Handle == 0 || !SO.Is_server || SO.Type != 'STREAM' ? NONE
	ELSE INT handle|_of_socket = SO.Handle ;
	NATIVE @
"	int s = X_handle;"
"	if (s == 0) return false;"
"	struct sockaddr_in a;"
"	a.sin_family = AF_INET;"
"	a.sin_port = htons(X_Port);"
"	a.sin_addr.s_addr = INADDR_ANY;"
"	//a.sin_addr.s_addr = inet_addr(&X_Host[0]);"
"	if (X_Max_queue <= 0) X_Max_queue = SOMAXCONN;"
"	if (bind(s, (sockaddr *)&a, sizeof(a)) != 0) return false;"
"	if (listen(s, X_Max_queue) != 0) return false;"
"	RESULT = true;" .

FUN Socket_accept({Socket} SO|bject_socket) ==> INT, NATIVE:
	INT handle|_of_server_socket = SO.Handle
	NATIVE @
"	struct sockaddr a;"
"	int a_len = sizeof(struct sockaddr);"
"	int s = X_handle;"
"	try {"
"#ifdef MSWINDOWS"
"		int c = accept(s, &a, &a_len);"
"#else"
"		int c = accept(s, &a, (socklen_t*)&a_len);"
"#endif"
"		return c;"
"	}"
"	catch (std::exception& ex) {"
"		return 0;"
"	}" .

FUN Socket_shutdown(
{Socket} SO|bject_socket|DUMMY, 
INT H|andler_connection_to_close), NATIVE : @
"	int c = X_H;"
"	shutdown(c, 2);"
"#ifdef MSWINDOWS"
"	closesocket(c);"
"#else"
"	close(c);"
"#endif" 
.

------------------------- 'CLIENT'

FUN Socket_connect(
{Socket} SO|bject_socket,
STR Host|_address,
INT Port|_number) ==> BOOL, NATIVE:
	INT handle|_of_client_socket = SO.Handle
	NATIVE @
"	int c = X_handle;"
"	struct sockaddr_in a;"
"	a.sin_family = AF_INET;"
"	a.sin_port = htons(X_Port);"
"	a.sin_addr.s_addr = inet_addr(&X_Host[0]);"
"  	try"
"	{"
"		int r = connect(c, (sockaddr*)&a, sizeof(a));"
"		return r == 0;"
"	}"
"  	catch (std::exception& ex) { return false; }" .

------------------------- 'SEND / RECEIVE'

FUN Socket_receive(
{Socket} SO|bject_socket|DUMMY,
INT Handler|_socket_used_to_receive,
BYTE Data|_array_to_fill[]), NATIVE : @
"	char buf[256];"
"	int s = X_Handler;"
"	int len;"
"	do"
"	{"
"		len = recv(s, &buf[0], sizeof(buf), 0);"
"		if (len == 0) break;"
"		for (int i = 0; i < len; i++)"
"			X_Data->Add(buf[i]);"
"	}"
"	while (len >= sizeof(buf));" .

FUN Socket_send(
{Socket} SO|bject_socket|DUMMY,
INT Handler|_socket_used_to_send,
BYTE Data|_array_to_send[*]), NATIVE : @
"	char *buf = (char*)malloc(X_Data->Count());"
"	int s = X_Handler;"
"	for (int i = 0; i < X_Data->Count(); i++)"
"		buf[i] = X_Data->get(i);"
"	send(s, &buf[0], X_Data->Count(), 0);"
"	free(buf);" .

-------------------------- 'CLOSE'

FUN Socket_close({Socket} SO|bject_socket), NATIVE:
	INT handle|_to_close = SO.Handle
	NATIVE @
"	int s = X_handle;"
"	shutdown(s, 2);"
"#ifdef MSWINDOWS"
"	closesocket(s);"
"#else"
"	close(s);"
"#endif" 
.

------------------------------ 'Utility'

//FUN Get_host_name ==> STR, NATIVE : @
//"var buf: array[0..255] of Char;"
//"	buf[0] := #0;"
//"	if gethostname(buf, Sizeof(buf)) > 0 then"
//"		RESULT := buf;" .

FUN Get_host_ip ==> STR, NATIVE : @
"	char ac[80];"
"	if (gethostname(ac, sizeof(ac)) != 0) return RESULT;"
"	struct hostent *He = gethostbyname(ac);"
"	if (He == 0) return RESULT;"
"	for (int i = 0; He->h_addr_list[i] != 0; i++)"
"	{"
"		struct in_addr Ia;"
"		memcpy(&Ia, He->h_addr_list[i], sizeof(Ia));"
"		RESULT = inet_ntoa(Ia);"
"		break;"
"	}" .

END
*/
