/*
	WinSock 2.0 ws2_32.lib, winsock2.h client 
	by N.T. Hashimoto, 2Sep2010, updated on 3Sep2010
	2012.
	Linux Socket Version Added 2013. T.Inaba

# WINDOWS
azpc -p socket.c /i /e azexe /dcurses /lib ws2_32.lib 
# LINUX
azpc -p socket.c /i /e azexe /dcurses 

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Socket send/receive sample program

%%% Server %%%
go:-server_create('65001',Acc),                                 % (1)
%   server_create('192.168.10.10','65001',Acc),                 % (2)
    repeat, 
	all_acc(1,WatchList),
	select_from_sockets(20000,[Acc|WatchList],ReceivedList),    % (10) 
	member(Sock,ReceivedList),
	rec_do(Acc,Sock,Data),
	write(Sock=Data),nl,
    fail.

rec_do(A,A,_):- !,server_accept(A,Host,S),assert('$acc$'(S)),fail.  % (3)
%rec_do(_,S,D):-socket_receive(S,D),atom_length(D,N),N>0,!.	    % (8)
rec_do(_,S,D):- socket_receive_list(S,D),length(D,N),N>0,!.	    % (9)
rec_do(_,S,_):- socket_close(S),retract('$acc$'(S)),fail.	    % (5) 

all_acc(N,[A|L]):- clause('$acc$',1,N,'$acc$'(A)),!,NN is N+1,all_acc(NN,L).
all_acc(_,[]).

%%% Client %%%
?- client_connect('127.0.0.1','65001',X),	% (4)
	socket_send(X,aho),			% (6)
	socket_close(X).			% (5)
?- client_connect('127.0.0.1','65001',X),
%	socket_send_list(X,['123',aho]).	% (7)=>[49,50,51,97,104,111]
%	socket_send_list(X,["123",aho,123]).	% (7)=>[49,50,51,97,104,111,123]
	socket_send_list(X,"12aho34").		% (7)=>[49,50,97,104,111,51,52] 

%%% socket_download %%%
?-client_connect('127.0.0.1','80',S),
  P1='GET /icon.zip HTTP/1.0',
  name(C,[10]),
  atom_concat(P1,C,P2),
  atom_concat(P2,C,Get),
  socket_send(S,Get),
  socket_download(S,'icon.zip'),
  socket_close(S).

%%% client_connect_async %%%
?-client_connect_async('127.0.0.1','65001',X),
  repeat, s_sleep(1), check_socket_sendable(X),
  socket_send(X,aho),
  socket_close(X).

%%% check_socket_receivable %%%
?-client_connect('127.0.0.1','65001',X),
  repeat, s_sleep(1), check_socket_receivable(X),
  socket_receive(X,Y),write(X),
  socket_close(X).

%%% ping %%%
?-ping('127.0.0.1',2).

%%% ping_async %%%
?-ping_async('127.0.0.1',X),s_sleep(1000),
        check_socket_receivable(X),socket_close(X).

*/

#include <azprolog.h>
#ifdef WIN32
	#include <sys/stat.h>
	#include <stdio.h>
	#include <winsock2.h>
	#include <ws2tcpip.h>
	#include <fcntl.h>
#else
	#include <stdio.h>
	#include <sys/types.h>
	#include <sys/socket.h>
	#include <sys/time.h>
	#include <sys/stat.h>
	#include <sys/ioctl.h>
	#include <sys/un.h>
	#include <netinet/in.h>
	#include <netinet/ip_icmp.h>
	#include <arpa/inet.h>
	#include <netdb.h>
	#include <unistd.h>
	#include <string.h>
	#include <stdlib.h>
	#include <fcntl.h>
	#include <errno.h>
#endif

/*  2015.2.13 Telly
extern  void yield_error();
#define ERROR(n)     yield_error(n)
*/

#define ILL_ARG      9

#define PARG(n,i)    (next_var_cell - n + i)

#define GET_INT_CAR_LIST(top,data)     \
           REALVALUE(top);             \
           if(!IS_LIST(top)) break;    \
           top=BODY(top);              \
           data = (int)Numeric_s_num_eval_int(top++)

#define MAKE_INT_CAR_LIST(top,data) \
	  SETTAG(top,  list_tag); BODY(top)=top+1;      \
	  SETTAG(top+1,int_tag);  INT_BODY(top+1)=data; \
	  top += 2

#define Rec_buff_size  0xfffff+1         /* 10240000 => 1048576 */
#define Rec_buff_size2 0xffff+1          /* 102400   => 65536   */

static	char s_buffer[Rec_buff_size];
static	char s_buffer2[Rec_buff_size2];

typedef unsigned char BYTE;


/* Prototype */
extern pred P2_server_create();            /* (1)  */
extern pred P3_server_create();            /* (2)  */
extern pred P3_server_accept();            /* (3)  */
extern pred P3_client_connect();           /* (4)  */
extern pred P1_socket_close();             /* (5)  */
extern pred P2_socket_send();              /* (6)  */
extern pred P2_socket_send_list();         /* (7)  */
extern pred P2_socket_receive();           /* (8)  */
extern pred P2_socket_receive_list();      /* (9)  */
extern pred P3_select_from_sockets();      /* (10) */
extern pred P4_host2ip();                  /* (11) */
extern pred P2_socket_download();          /* (12) */
#ifdef WIN32
#else
extern pred P2_unix_client_connect();      /* (13) */
extern pred P2_unix_server_create();       /* (14) */
extern pred P2_unix_server_close();        /* (15) */
#endif

#ifdef WIN32
#else
extern pred P3_client_connect_async();     /* (16) */ 
#endif
extern pred P1_check_socket_receivable();  /* (17) */ 
extern pred P1_check_socket_sendable();    /* (18) */ 
#ifdef WIN32
#else
extern pred P2_ping();                     /* (19) */ 
extern pred P2_ping_async();               /* (20) */ 
#endif

#ifdef WIN32
__declspec(dllexport) int initiate_socket(){
#else
extern int initiate_socket(){
#endif
  put_bltn("server_create\0", 2,P2_server_create);
  put_bltn("server_create\0", 3,P3_server_create);
  put_bltn("server_accept\0", 3,P3_server_accept);
  put_bltn("client_connect\0",3,P3_client_connect);
  put_bltn("socket_send\0",        2,P2_socket_send);
  put_bltn("socket_send_list\0",   2,P2_socket_send_list);
  put_bltn("socket_receive\0",     2,P2_socket_receive);
  put_bltn("socket_receive_list\0",2,P2_socket_receive_list);
  put_bltn("socket_close\0",       1,P1_socket_close);
  put_bltn("select_from_sockets\0",3,P3_select_from_sockets);
  put_bltn("host2ip\0",            4,P4_host2ip);
  put_bltn("socket_download\0",    2,P2_socket_download);
#ifdef WIN32
#else
  /***** Unix Socket *****/
  put_bltn("unix_client_connect\0",2,P2_unix_client_connect);
  put_bltn("unix_server_create\0", 2,P2_unix_server_create);
  put_bltn("unix_server_close\0",  2,P2_unix_server_close);
#endif

#ifdef WIN32
#else
  /***** ASync,ICMP *****/
  put_bltn("client_connect_async\0",3,P3_client_connect_async);
#endif
  put_bltn("check_socket_receivable\0",1,P1_check_socket_receivable);
  put_bltn("check_socket_sendable\0",1,P1_check_socket_sendable);
#ifdef WIN32
#else
  put_bltn("ping\0",2,P2_ping);
  put_bltn("ping_async\0",2,P2_ping_async);
#endif

  return 1;
}


/* ********************************************** */
/* connect From Client To Server                  */
/* ?-client_connect('192.168.0.0','8080',-Socket).*/
/* ********************************************** */

#ifdef WIN32
extern int S_WaitForEchoReply(int s)
{
	struct timeval Timeout;
	fd_set readfds;
	FD_ZERO(&readfds);
	FD_SET(s,&readfds);
	Timeout.tv_sec=0;
	Timeout.tv_usec=0;
	return(select(s+1,&readfds,NULL,NULL,&Timeout));
}
#else
extern int S_WaitForEchoReply(int s);  /* in source/funccall.c */
#endif

pred P3_client_connect(Frame *Env)
{
	char destination[1024];
	char port_name[1024];
	int dstSocket;
	struct sockaddr_in dstAddr;
	int port_id;
	int on=1;
	
#ifdef WIN32
	WSADATA data;
	WSAStartup(MAKEWORD(2,0), &data);
#endif	
	Atom2Asciz(GetAtom(PARG(3,0)), destination);
	if(IsAtom(PARG(3,1))) {
		Atom2Asciz(GetAtom(PARG(3,1)), port_name);
		port_id = atoi(port_name);
	}
	else {
		port_id = GetInt(PARG(3,1));
	}
	
	memset(&dstAddr, 0, sizeof(dstAddr));
	dstAddr.sin_port = htons(port_id);
	dstAddr.sin_family = AF_INET;
	dstAddr.sin_addr.s_addr = inet_addr(destination);

	dstSocket = socket(AF_INET, SOCK_STREAM, 0);
	if(setsockopt(dstSocket,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on))){
		close(dstSocket);
		AZ_ERROR(ILL_ARG);
	}

	if(connect(dstSocket, (struct sockaddr *) &dstAddr, sizeof(dstAddr))){
		close(dstSocket);
		YIELD(FAIL);
	}
	YIELD(UnifyInt(PARG(3,2), dstSocket));
}

/* ***************************************** */
/* ?-server_create(+PortAtom,-ServerSocket). */
/* ***************************************** */
pred P2_server_create(Frame *Env)
{
	unsigned short port_id;
	char port_name[1024];
	int srcSocket;
	int on =1,ret;    /* 2012.9.26 For ReUse */
	struct sockaddr_in srcAddr;

#ifdef WIN32
	WSADATA data;
	WSAStartup(MAKEWORD(2,0), &data);
#endif	
	if(IsAtom(PARG(2,0))) {
		Atom2Asciz(GetAtom(PARG(2,0)), port_name);
		port_id = atoi(port_name);
	}
	else {
		port_id = GetInt(PARG(2,0));
	}

	memset(&srcAddr, 0, sizeof(srcAddr));
	srcAddr.sin_port = htons(port_id);
	srcAddr.sin_family = AF_INET;
	srcAddr.sin_addr.s_addr = htonl(INADDR_ANY);

	srcSocket = socket(AF_INET, SOCK_STREAM, 0);
	ret = setsockopt(srcSocket,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on));
	ret = bind(srcSocket, (struct sockaddr *) &srcAddr, sizeof(srcAddr));
	if(ret == -1) AZ_ERROR(ILL_ARG); 

	listen(srcSocket, 1);

	YIELD(UnifyInt(PARG(2,1), srcSocket));
}

/* *************************************************** */
/* ?-server_create(+ServerIP,+PortAtom,-ServerSocket). */
/* *************************************************** */
pred P3_server_create(Frame *Env)
{
	unsigned short port_id;
	char my_ip[1024];
	char port_name[1024];
	int srcSocket;
	int on =1,ret;    /* 2012.9.26 For ReUse */
	struct sockaddr_in srcAddr;

#ifdef WIN32
	WSADATA data;
	WSAStartup(MAKEWORD(2,0), &data);
#endif	
	Atom2Asciz(GetAtom(PARG(3,0)), my_ip);
	if(IsAtom(PARG(3,1))) {
		Atom2Asciz(GetAtom(PARG(3,1)), port_name);
		port_id = atoi(port_name);
	}
	else {
		port_id = GetInt(PARG(3,1));
	}

	memset(&srcAddr, 0, sizeof(srcAddr));
	srcAddr.sin_port = htons(port_id);
	srcAddr.sin_family = AF_INET;
//  srcAddr.sin_addr.s_addr = htonl(INADDR_ANY);
//  srcAddr.sin_addr.s_addr = htonl(my_ip); 
	srcAddr.sin_addr.s_addr = inet_addr(my_ip);

	srcSocket = socket(AF_INET, SOCK_STREAM, 0);
	ret = setsockopt(srcSocket,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on));
	ret = bind(srcSocket, (struct sockaddr *) &srcAddr, sizeof(srcAddr));
	if(ret == -1) AZ_ERROR(ILL_ARG);   /* Illegal Argument */
	listen(srcSocket, 1);

	YIELD(UnifyInt(PARG(3,2), srcSocket));
}


/* ?-server_accept(+ServerSocket,-DstIP,-Socket). */
pred P3_server_accept(Frame *Env)
{
	int dstSocket;
	struct sockaddr_in dstAddr;
	int dstAddrSize = sizeof(dstAddr);
	int ret,on=1;    /* 2012.9.27 */

	if(!S_WaitForEchoReply(GetInt(PARG(3,0))))  YIELD(FAIL);

	dstSocket = accept(GetInt(PARG(3,0)),(struct sockaddr*)&dstAddr,(socklen_t* )&dstAddrSize);
	ret = setsockopt(dstSocket,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on));
	if(ret == -1) YIELD(FAIL);    

	if(!UnifyAtom(PARG(3,1),(BASEINT)PutAtom(Env,inet_ntoa(dstAddr.sin_addr)))) YIELD(FAIL);
	else YIELD(UnifyInt(PARG(3,2), dstSocket));
}

/* *************************** */
/* Server/Client Common Method */
/* *************************** */

/* ?- socket_receive(+Socket,-ReceivedAtom). */
pred P2_socket_receive(Frame *Env)
{
	int dstSocket;

	LINK0(Env);
	LINK1ZZ(Env);

  	if(!S_WaitForEchoReply(GetInt(PARG(2,0))))  YIELD(FAIL);

	memset(s_buffer2,'\0',Rec_buff_size2);
	dstSocket = GetInt(PARG(2,0));
	if( recv(dstSocket, s_buffer2, Rec_buff_size2, 0) == -1){
#ifdef WIN32
// 2015.2.16 Telly 
//		rec_size=0;
		memset(s_buffer2,'\0',1);
#else
		/* 2015.1.30 Telly */
		AZ_ERROR(ILL_ARG);
#endif
	}
	YIELD(unify_atom(PARG(2,1),PutAtom(Env,s_buffer2)));
}

/* *************************** */


/* ?- socket_receive_list(+Socket,-ReceivedCharList). */
pred P2_socket_receive_list(Frame *Env)
{
	int dstSocket,rec_size,gvar_size,count=0;
	TERM *List_top;

	LINK0(Env);

	if(!S_WaitForEchoReply(GetInt(PARG(2,0))))  YIELD(FAIL);

	memset(s_buffer,'\0',Rec_buff_size);
	dstSocket = GetInt(PARG(2,0));
	if( (rec_size=recv(dstSocket, s_buffer, Rec_buff_size, 0)) == -1){
#ifdef WIN32
		rec_size=0;
#else
		/* 2015.1.30 Telly */
		AZ_ERROR(ILL_ARG);
#endif
	}

	gvar_size = rec_size*2+1;
	LINK1(Env,gvar_size,gvar_size);

	List_top = Env->Global;
        while(rec_size--){
		MAKE_INT_CAR_LIST(List_top, s_buffer[count++]&0xFF);
	}
	PUTNIL(List_top);
	YIELD(unify(Env->Global,PARG(2,1)));
}

/* ?- socket_send(+Socket,+SendAtom). */
pred P2_socket_send(Frame *Env)
{
	int dstSocket;
	int size;

	dstSocket = GetInt(PARG(2,0));
	Atom2Asciz(GetAtom(PARG(2,1)), s_buffer2);
	if( (size = strlen(s_buffer2) ) == 0 )
		YIELD(FAIL);

	s_buffer2[size]= '\0';
#ifdef WIN32
	if(send(dstSocket, s_buffer2, size, 0) == SOCKET_ERROR) 
#else
	if(send(dstSocket, s_buffer2, size, 0) == -1)
#endif
		YIELD(FAIL);
	else 
		YIELD(DET_SUCC);
}

/* *************************************************** */

#if AZ_POINTER_SIZE == 64
#define MAX_SHIFT  56
#else
#define MAX_SHIFT  24 
#endif

#define SET_INT_DATA(mmy_car,msize)		    \
	{ BASEINT tmp; char ctmp; int sft;int f=0;  \
	tmp=INT_BODY(mmy_car);			    \
	for(sft=MAX_SHIFT;sft>=0;sft -= 8){	    \
	   if((ctmp=(tmp>>sft & 0xff)) != 0 || f)  \
	      {f=1;s_buffer[msize]=ctmp; msize++;} }} 

/* ********************************************* */
/* ?- socket_send_list(+Socket,+SendAtoms_list). */

pred P2_socket_send_list(Frame *Env)
{
	TERM *my_list,*my_car,*my_llist;
	int size=0;

	my_list=PARG(2,1);
	while(-1){
		REALVALUE(my_list);
		if( IS_LIST(my_list) ){
			my_list = my_car = BODY(my_list);
			REALVALUE(my_car);
			switch(TAG(my_car)){
			case atom_tag:
				Atom2Asciz(GetAtom(my_car), s_buffer+size);
				size = strlen(s_buffer);
				break;
			case int_tag:
				SET_INT_DATA(my_car,size)
				break;
			case list_tag:
			case glist_tag:
				my_llist = my_car;
				do {	my_llist = my_car = BODY(my_llist);
					REALVALUE(my_car);
					if(!IS_INT(my_car)) AZ_ERROR(ILL_ARG);
					SET_INT_DATA(my_car,size)
					my_llist++;
					REALVALUE(my_llist);
				} while(IS_LIST(my_llist));
				break;
			default:  AZ_ERROR(ILL_ARG);
			}
			my_list++;
		} else break;
	}		
	if(size == 0) YIELD(FAIL);
	s_buffer[size]= '\0';

#ifdef WIN32
	if( send(GetInt(PARG(2,0)), s_buffer, size, 0) == SOCKET_ERROR) 
#else
	if( send(GetInt(PARG(2,0)), s_buffer, size, 0) == -1 ) 
#endif
		YIELD(FAIL);
	else 
		YIELD(DET_SUCC);
}

/* ?-socket_close(+Socket). */
pred P1_socket_close(Frame *Env)
{
	int dstSocket;
	dstSocket = GetInt(PARG(1,0));
#ifdef WIN32
	closesocket(dstSocket);
//  WSACleanup();
#else
	close(dstSocket);
#endif
	YIELD(DET_SUCC);
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
?- select_from_sockets(+TimeOutMillSec,+SocketList,-ReceivedSocketList).
*/

pred P3_select_from_sockets(Env)
Frame *Env;
{
  extern BASEINT Numeric_s_num_eval_int(TERM *arg); /* source/numeric.c */

        struct timeval Timeout;
        fd_set readfds;
        TERM   *in_list,*out_list;
        int    max_fd=0,work;

	LINK0(Env);

	/* Arg1 is TimeOut MilliSeconds */
        work = (int)Numeric_s_num_eval_int(PARG(3,0));
/*
	% 2014.2.3 msec => micro second %
        Timeout.tv_sec  = work / 1000;
        Timeout.tv_usec = (work % 1000)*1000;
*/
        Timeout.tv_sec  = work / 1000000;
        Timeout.tv_usec = work % 1000000;

	/* Arg2 is Watching Socket List */
        in_list = PARG(3,1);
        FD_ZERO(&readfds);
        while(-1){
		GET_INT_CAR_LIST(in_list,work);
                FD_SET(work,&readfds);
                if(max_fd<work) max_fd=work;
        }
        if(max_fd==0) AZ_ERROR(ILL_ARG);

        work=select(max_fd+1, &readfds, NULL, NULL, &Timeout);

	/* work is selected sockets volume or error==-1 or timeout==0 */
        if(work== -1) AZ_ERROR(ILL_ARG);       /* Error Return     */
        if(!work)     YIELD(FAIL);          /* TimeOut ==> Fail */

	/* Arg3 is Data received Socket List */
	work = work*2+1;        /* List Cell Size is cdr+(car,cdr)*N */
	LINK1(Env,work,work);   /* alloc Gvar for list Cell */

        in_list =PARG(3,1);
	out_list=Env->Global;
        while(-1){
		GET_INT_CAR_LIST(in_list,work);
                if( FD_ISSET(work,&readfds) ){
			MAKE_INT_CAR_LIST(out_list,work);
		}
        }
	PUTNIL(out_list);
	YIELD(unify(PARG(3,2),Env->Global)); 
}

/* ?-host2ip(+HostName,-GeneralHostName,-AliasHostname,-IpAddress). */
pred P4_host2ip(Frame *Env)
{
	struct hostent *host; 
	char hostname[1024];
	char ghost[1024];
	char ahost[1024];
	char ip[1024];

#ifdef WIN32
    WSADATA data;
    WSAStartup(MAKEWORD(2,0), &data); 
#endif

	Atom2Asciz(GetAtom(PARG(4,0)), hostname);

	host = gethostbyname(hostname); 
	if(host == NULL) { 
		YIELD(FAIL);
	} 

	strcpy(ghost, host->h_name); 
    if(host->h_aliases[0] == NULL) { 
        strcpy(ahost,"");
    }
    else {  
        strcpy(ahost, host->h_aliases[0]);
    }
	sprintf(ip, "%d.%d.%d.%d" , 
			(BYTE)*((host->h_addr_list[0])) , 
			(BYTE)*((host->h_addr_list[0]) + 1) , 
			(BYTE)*((host->h_addr_list[0]) + 2) , 
			(BYTE)*((host->h_addr_list[0]) + 3)); 

	if(! UnifyAtom(PARG(4,1), PutAtom(Env,ghost))) YIELD(FAIL);
	if(! UnifyAtom(PARG(4,2), PutAtom(Env,ahost))) YIELD(FAIL);
	YIELD(UnifyAtom(PARG(4,3), PutAtom(Env,ip)));
}

/* ?-socket_download(+Socket,+DownloadFile). */
pred P2_socket_download(Frame *Env)
{
    int dstSocket;
    int i,j,read_size,size,fd;
    char *out_buffer;
    char download_file[1024];


    LINK0(Env);
    LINK1ZZ(Env);

    //if(!S_WaitForEchoReply(GetInt(PARG(2,0))))  YIELD(FAIL);

    /* 引数を取得 */
    dstSocket = GetInt(PARG(2,0));
    Atom2Asciz(GetAtom(PARG(2,1)),download_file);

    /* 領域を確保 */
    //out_buffer = (char *)malloc(Rec_buff_size);
	size = 1024*1024*1024;
    out_buffer = (char *)malloc(size);
    if(out_buffer == NULL) {
        YIELD(FAIL);
    }

    /* 読込み処理 */
    memset(out_buffer,'\0',Rec_buff_size);
    i = 0;
    while(1) {
        memset(s_buffer2,'\0',Rec_buff_size2);
        read_size = recv(dstSocket, s_buffer2, Rec_buff_size2, 0);
        if(read_size == -1) {
			free(out_buffer);
			AZ_ERROR(ILL_ARG);
		}
        if(read_size == 0) break;
        memcpy(&out_buffer[i],s_buffer2,read_size);
        i = i + read_size;
		if(i > size) { 
            free(out_buffer);
            AZ_ERROR(ILL_ARG);
        }
    }

    /* 読込みバッファ上のヘッダ部分を取り除く */
    for(j=0;;j++) {
        if(out_buffer[j]    == '\r' &&
            out_buffer[j+1] == '\n' &&
            out_buffer[j+2] == '\r' &&
            out_buffer[j+3] == '\n') {
            j = j+4;
            break;
        }
    }

    /* ファイル書込み処理 */
#ifdef WIN32
	if((fd = open(download_file, O_CREAT|O_WRONLY|O_BINARY, S_IREAD|S_IWRITE)) == -1) {
#else
	if((fd = open(download_file, O_CREAT|O_WRONLY, S_IREAD|S_IWRITE)) == -1) {
#endif
        YIELD(FAIL);
    }
    if(write(fd, &out_buffer[j], i-j) <= 0) YIELD(FAIL);
    close(fd);

    /* 確保した領域を開放 */
    free(out_buffer);

    YIELD(DET_SUCC);
}

#ifdef WIN32
#else
/* ***************************************************** */
/* Asynchronous connect From Client To Server            */
/* ?-client_connect_async('192.168.0.0','8080',-Socket). */
/* ***************************************************** */
pred P3_client_connect_async(Frame *Env)
{
    char destination[1024];
    char port_name[1024];
    int dstSocket;
    struct sockaddr_in dstAddr;
    int port_id;
    int on=1,val=1;
    //struct timeval timeout={0,0};

//#ifdef WIN32
//  WSADATA data;
//  WSAStartup(MAKEWORD(2,0), &data);
//#endif
    Atom2Asciz(GetAtom(PARG(3,0)), destination);
	if(IsAtom(PARG(3,1))) {
	    Atom2Asciz(GetAtom(PARG(3,1)), port_name);
		port_id = atoi(port_name);
	}
	else {
		port_id = GetInt(PARG(3,1));
	}

    memset(&dstAddr, 0, sizeof(dstAddr));
    dstAddr.sin_port = htons(port_id);
    dstAddr.sin_family = AF_INET;
    dstAddr.sin_addr.s_addr = inet_addr(destination);

    dstSocket = socket(AF_INET, SOCK_STREAM, 0);
    ioctl(dstSocket, FIONBIO, &val);
    if(setsockopt(dstSocket,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on))){
		close(dstSocket);
        AZ_ERROR(ILL_ARG);
    }

    connect(dstSocket, (struct sockaddr *) &dstAddr, sizeof(dstAddr));

    YIELD(UnifyInt(PARG(3,2), dstSocket));
}
#endif

/* *********************************** */
/* Asynchronous Received check         */
/* ?-check_socket_receivable(+Socket). */
/* *********************************** */
pred P1_check_socket_receivable(Frame *Env)
{
    int dstSocket,ret;
    fd_set fdset;
    struct timeval timeout={0,0};
    dstSocket = GetInt(PARG(1,0));
    FD_ZERO( &fdset );
    FD_SET( dstSocket , &fdset );
    ret = select( dstSocket+1 , &fdset, NULL , NULL , &timeout );
    if(ret>0 && FD_ISSET(dstSocket,&fdset)){ YIELD(DET_SUCC);}
    else {YIELD(FAIL);}
}

/* *********************************** */
/* Asynchronous connected check        */
/* ?-check_socket_sendable(+Socket).   */
/* *********************************** */
pred P1_check_socket_sendable(Frame *Env)
{
    int dstSocket,res;
    fd_set fdset;
    struct timeval timeout={0,0};
    dstSocket = GetInt(PARG(1,0));
    FD_ZERO( &fdset );
    FD_SET( dstSocket , &fdset );
    res = select( dstSocket+1 , NULL , &fdset , NULL , &timeout );
    if(res < 1){ YIELD(FAIL);}
    else { YIELD(DET_SUCC); }
}

/* *********************************** */
/* PING connect From Client To Server  */
/* ?-ping('192.168.0.0',-Timeout Sec). */
/* *********************************** */
unsigned short
checksum(unsigned short *buf, int bufsz)
{
  unsigned long sum = 0;
  while (bufsz > 1) {
    sum += *buf;
    buf++;
    bufsz -= 2;
  }
  if (bufsz == 1) {
    sum += *(unsigned char *)buf;
  }
  sum = (sum & 0xffff) + (sum >> 16);
  sum = (sum & 0xffff) + (sum >> 16);
  return ~sum;
}

#ifdef WIN32
#else
pred P2_ping(Frame *Env)
{
	char destination[1024];
    int dstSocket;
    struct sockaddr_in dstAddr;
    int on=1;
    struct icmphdr hdr;
    struct timeval Timeout = {0,0};
    fd_set readfds;

//#ifdef WIN32
//  WSADATA data;
//  WSAStartup(MAKEWORD(1,0), &data);
//#endif
    Atom2Asciz(GetAtom(PARG(2,0)), destination);
    memset(&dstAddr, 0, sizeof(dstAddr));
    dstAddr.sin_family = AF_INET;
    dstAddr.sin_addr.s_addr = inet_addr(destination);
    dstSocket = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
    if(setsockopt(dstSocket,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on))) {
		close(dstSocket);
        AZ_ERROR(ILL_ARG);
    }
    if(connect(dstSocket, (struct sockaddr *) &dstAddr, sizeof(dstAddr))) {
		close(dstSocket);
        YIELD(FAIL);
    }
    memset(&hdr, 0, sizeof(hdr));
    hdr.type = ICMP_ECHO;
    hdr.code = 0;
    hdr.checksum = 0;
    hdr.un.echo.id = 0;
    hdr.un.echo.sequence = 0;
    hdr.checksum = checksum((unsigned short *)&hdr, sizeof(hdr));

    if (sendto(dstSocket,(char *)&hdr, sizeof(hdr),0, (struct sockaddr
*)&dstAddr, sizeof(dstAddr))<1){
//#ifdef WIN32
//      closesocket(dstSocket);
//#else
        close(dstSocket);
//#endif
        perror("sendto");
        YIELD(FAIL);
    }

    FD_ZERO(&readfds);
    FD_SET(dstSocket,&readfds);
    Timeout.tv_sec = GetInt(PARG(2,1));
    if (select(dstSocket+1,&readfds,NULL,NULL,&Timeout)<1){
//#ifdef WIN32
//      closesocket(dstSocket);
//#else
        close(dstSocket);
//#endif
        YIELD(FAIL);
    }
//#ifdef WIN32
//  closesocket(dstSocket);
//#else
    close(dstSocket);
//#endif
    YIELD(DET_SUCC);
}

/* ****************************************** */
/* PING Async connect From Client To Server   */
/* ?-ping_async('192.168.0.0',-Socket).       */
/* ****************************************** */
pred P2_ping_async(Frame *Env)
{
    char destination[1024];
    int dstSocket;
    struct sockaddr_in dstAddr;
    int on=1;
    struct icmphdr hdr;
//#ifdef WIN32
//  WSADATA data;
//  WSAStartup(MAKEWORD(1,0), &data);
//#endif
    Atom2Asciz(GetAtom(PARG(2,0)), destination);
    memset(&dstAddr, 0, sizeof(dstAddr));
    dstAddr.sin_family = AF_INET;
    dstAddr.sin_addr.s_addr = inet_addr(destination);
    dstSocket = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
    if(setsockopt(dstSocket,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on))) {
		close(dstSocket);
        AZ_ERROR(ILL_ARG);
    }
    if(connect(dstSocket, (struct sockaddr *) &dstAddr, sizeof(dstAddr))) {
		close(dstSocket);
        YIELD(FAIL);
    }
    memset(&hdr, 0, sizeof(hdr));
    hdr.type = ICMP_ECHO;
    hdr.code = 0;
    hdr.checksum = 0;
    hdr.un.echo.id = 0;
    hdr.un.echo.sequence = 0;
    hdr.checksum = checksum((unsigned short *)&hdr, sizeof(hdr));

    if (sendto(dstSocket,(char *)&hdr, sizeof(hdr),0, (struct sockaddr
*)&dstAddr, sizeof(dstAddr))<1){
        perror("sendto");
//#ifdef WIN32
//      closesocket(dstSocket);
//#else
        close(dstSocket);
//#endif
        YIELD(FAIL);
    }
    YIELD(UnifyInt(PARG(2,1), dstSocket));
}
#endif

#ifdef WIN32
#else
/* *********************************************** */
/* connect from client to server                   */
/* ?-unix_client_connect('/var/hogehoge',-socket). */
/* *********************************************** */
pred P2_unix_client_connect(Frame *Env)
{
	char destination[256];
	int dstsocket;
	struct sockaddr_un dstaddr;
	//int on=1;

	Atom2Asciz(GetAtom(PARG(2,0)), destination);
	memset(&dstaddr, 0, sizeof(dstaddr));

	dstaddr.sun_family = AF_UNIX;
	strcpy(dstaddr.sun_path,destination);

	dstsocket = socket(AF_UNIX, SOCK_STREAM, 0);
//	ret = setsockopt(dstsocket,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on));

	if(connect(dstsocket, (struct sockaddr *) &dstaddr, sizeof(dstaddr))) {
		close(dstsocket);
		YIELD(FAIL);
	}

	YIELD(UnifyInt(PARG(2,1), dstsocket));
}

/* ***************************************************** */
/* ?- unix_server_create('/var/hogehoge',-serversocket). */
/* ***************************************************** */
pred P2_unix_server_create(Frame *Env)
{
  struct sockaddr_un srcaddr;
  char path_name[256];
  int srcsocket;
  int on =1,ret;

  Atom2Asciz(GetAtom(PARG(2,0)), path_name);
  memset(&srcaddr, 0, sizeof(srcaddr));
  srcaddr.sun_family = AF_UNIX;
  strcpy(srcaddr.sun_path,path_name);

  srcsocket = socket(AF_UNIX, SOCK_STREAM, 0);

  ret = setsockopt(srcsocket,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on));

Try:
  ret = bind(srcsocket, (struct sockaddr *) &srcaddr, sizeof(srcaddr));
  if(ret == -1) {
	unlink(path_name);
	goto Try;
  }

  listen(srcsocket, 1);

  YIELD(UnifyInt(PARG(2,1), srcsocket));
}

/* ********************************************* */
/* ?-unix_server_close('/var/hogehoge',+Socket). */
/* ********************************************* */
pred P2_unix_server_close(Frame *Env)
{
        int dstSocket;
  	char path_name[256];

	Atom2Asciz(GetAtom(PARG(2,0)), path_name);
        dstSocket = GetInt(PARG(2,1));

/*	if(unlink(path_name)) AZ_ERROR(2);    */
	unlink(path_name);

        close(dstSocket);
        YIELD(DET_SUCC);
}
#endif
