/**********************************************************************
 
	Copyright (C) 2003 Hirohisa MORI <joshua@nichibun.ac.jp>
 
	This program is free software; you can redistribute it 
	and/or modify it under the terms of the GLOBALBASE 
	Library General Public License (G-LGPL) as published by 

	http://www.globalbase.org/
 
	This program is distributed in the hope that it will be 
	useful, but WITHOUT ANY WARRANTY; without even the 
	implied warranty of MERCHANTABILITY or FITNESS FOR A 
	PARTICULAR PURPOSE.

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

#include <winsock2.h>
#include	<stdlib.h>
#include	<stdarg.h>
#include	<stdio.h>
#include	<io.h>

#include	"memory_debug.h"
#include	"stream.h"
#include	"task.h"

extern SEM stream_lock;
#ifndef _SOCKLEN_T
typedef size_t socklen_t;
#endif

int s_close_socket();
int s_write_socket();
int s_read_socket();
int s_vprintf_socket();
int s_vprintf_cr_socket();
int s_flush_socket();
int s_vscanf_socket();
int s_proc_send_socket();
STREAM * s_proc_recv_socket();

int s_get_socketip_socket(STREAM * s);

S_TABLE s_socket_table = {
	's',
	0,
	{0,0},
	0,
	0,
	s_close_socket,
	s_write_socket,
	s_read_socket,
	s_flush_socket,
	s_proc_send_socket,
	s_proc_recv_socket,
	s_get_socketip_socket
};

int
s_close_socket(STREAM * s)
{
	shutdown(s->socket.sock, SD_BOTH);
	closesocket(s->socket.sock);
	s->socket.sock = INVALID_SOCKET;
	return 0;
}

int
s_write_socket(STREAM * s, void * data, int len)
{
	int nResult;
	long timeout = 12;
	
	do{
		FD_SET fd = {{1}, {s->socket.sock}};
		TIMEVAL tv = {timeout, 0};
		nResult = select(0, NULL, &fd, NULL, &tv);
	}while(nResult == 0);
	
	if(nResult == SOCKET_ERROR){
		er_panic("socket error");
		return -1;
	}

	nResult = send(s->socket.sock, data, len, 0);
	
	return nResult;
}

int
s_read_socket(STREAM * s, void * data, int len)
{
	int nResult;
	long timeout = 12;
	
	do{
		FD_SET fd = {{1}, {s->socket.sock}};
		TIMEVAL tv = {timeout, 0};
		nResult = select(0, &fd, NULL, NULL, &tv);
	}while(nResult==0);
	if(nResult == SOCKET_ERROR) {
		return -1;
	}
	return recv(s->socket.sock, data, len, 0);
}

int
s_flush_socket(STREAM * s)
{

	return 0;
}

int
s_get_socketip_socket(STREAM * s)
{
int ret;
int er;
socklen_t size;
struct sockaddr_in ss;
	if ( s->h.tbl != &s_file_table )
		return 0;
	size = sizeof(ss);
	er = getpeername(s->socket.sock,(struct sockaddr*)&ss,&size);
	if ( er < 0 )
		return 0;
	ret = ntohl(ss.sin_addr.s_addr);
	return ret;
}



int
s_proc_send_socket(STREAM * s, PROC_SEND_CHUNK** chunk, BOOL close_flag)
{
	int flags;
	
	PROC_SEND_SOCKET *ps = (PROC_SEND_SOCKET *)d_alloc(sizeof(PROC_SEND_SOCKET));

	ps->header.size = sizeof(PROC_SEND_SOCKET);
	ps->header.type = s->h.tbl->type;
	ps->open_mode = s->h.mode;
	
	flags = DUPLICATE_SAME_ACCESS;
	if(close_flag)
		flags |= DUPLICATE_CLOSE_SOURCE;
	
	if(!DuplicateHandle(
		GetCurrentProcess(), 
		(HANDLE)(s->socket.sock),
		GetCurrentProcess(), 
		(HANDLE*)&(ps->sock),
		0,
		TRUE,
		flags)){
		er_panic("dup_handler error");
	}
	*chunk = (PROC_SEND_CHUNK*)ps;
	/* WIN_SERVER_DEBUG */
	printf("s_proc_send_socket. sock=%ld\n", ps->sock);
	
	return 0;
}


STREAM *
s_proc_recv_socket(S_TABLE *table, PROC_SEND_CHUNK* chunk)
{
	STREAM *ret;
	PROC_SEND_SOCKET *ps;
	
	ps = (PROC_SEND_SOCKET *)chunk;
	
	ret = d_alloc(sizeof(S_SOCKET));
	ret->h.tbl = table;
	ret->h.thread = 0;
	ret->socket.sock = ps->sock;
	
	_s_open(ret,ps->open_mode);
	/* WIN_SERVER_DEBUG */
	printf("socket received. sock=%ld\n", ps->sock);
	return ret;
}

void
init_socket_stream()
{
	insert_s_table(&s_socket_table);
}