/*********************************************
  netpuyo(client)
  network.c --- protocol operating subroutine
  (C) Sep 17, 1997 ROYALPANDA
**********************************************/

#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<netinet/tcp.h>
#include<netdb.h>
#include<sys/errno.h>

#include"protocol.h"
#include"netpuyo.h"

unsigned char Send_buf[8];  /* 送信バッファ */
unsigned char *Send_write;  /* メッセージ作成用 */

unsigned char Recv_buf[128]; /* 受信バッファ */
int Recv_len;  /* 読み込んだ長さ */
int Recv_read; /* 処理した長さ */
int Recv_msg;  /* 次に読むメッセージのデータの位置 */

#define TCP_PROTO 6   /* TCPのプロトコルナンバー */

/* システムコールのエラー */

static int syserr( char *msg )
{
  fprintf( stderr,"%s: ",Myname );
  perror( msg );
}


/* サーバーに接続 */

int init_network( char *host,int port )
{
  struct hostent *hp;
  struct sockaddr_in sin;

  static int on = 1;
  
  if( (hp = gethostbyname(host)) == NULL ){
    fprintf( stderr,"%s: unknown host: %s\n",Myname,host );
    return -1;
  }

  if( (Sock = socket(AF_INET,SOCK_STREAM,0)) < 0 ){
    syserr( "socket" );
    return -1;
  }

  memset( &sin,0,sizeof(struct sockaddr_in) );
  sin.sin_family = AF_INET;
  sin.sin_port = htons( port );
  memmove( &sin.sin_addr,hp->h_addr,hp->h_length );

  if( connect( Sock,&sin,sizeof(sin)) < 0 ){
    syserr( "connect" );
    return -1;
  }
  if( setsockopt( Sock,TCP_PROTO,TCP_NODELAY,(char*)&on,sizeof(on) ) < 0 ){
    syserr( "setsockopt" );
    return -1;
  }

  Recv_len = 0;
  Recv_read = 0;
  return 0;

}


/* 受信バッファに読み込む */

void fill_buf( void )
{
  int l;

  if( Recv_len == sizeof(Recv_buf) )
    return;

  if( (l = read(Sock,Recv_buf+Recv_len,sizeof(Recv_buf)-Recv_len )) < 0 ){
    syserr("read");
    close( Sock );
    exit(1);
  }

  if( l == 0 ){
    close(Sock);
    exit(0);
  }

  Recv_len += l;
}


/* メッセージを1つ読み込む */

int recv_msg( void )
{
  int l;
  fd_set fds;

  l = Recv_len - Recv_read;

  if( l < 16 ){
    if( l > 0 )
      memmove( Recv_buf,Recv_buf+Recv_read,l );
    Recv_read = 0;
    Recv_len = l;
    return 0;
  }

  Recv_msg = Recv_read;
  Recv_read += 16;

  return Recv_buf[Recv_msg++];
}


/* 小さい整数を獲得 */

int recv_snum( void )
{
  return Recv_buf[Recv_msg++]-32;
}


/* IDを獲得(自分なら0に修正する) */
int recv_id( void )
{
  int p;

  p = Recv_buf[Recv_msg++]-32;
  if( My_id )
    p = 1-p;
  return p;
}


/* 大きい整数を獲得 */

int recv_lnum( void )
{
  int i;

  i = Recv_buf[Recv_msg] - 32 + (Recv_buf[Recv_msg+1]-32) * 64;
  Recv_msg += 2;
  return i;
}


/* メッセージ送信準備 */

void send_init( int msg )
{
  Send_buf[0] = msg;
  Send_write = Send_buf+1;
}


/* 小さい整数を送る */
void send_snum( int i )
{
  *Send_write++ = i+32;
}


/* IDを送る( 0を自分のIDに修正 ) */

void send_id( int p )
{
  if( My_id )
    p = 1-p;
  *Send_write++ = p+32;
}


/* メッセージを実際に送信 */

void send_msg( void )
{
  int l;

  write( Sock,Send_buf,8 );
}
