
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<netdb.h>
#include<unistd.h>
#include<sys/socket.h>
#include<netinet/in_systm.h>
#include<netinet/in.h>
#include<netinet/ip.h>
#include<arpa/inet.h>
#include<fcntl.h>

#include <sys/select.h>
#include <signal.h>

#include<sys/stat.h>
#include<errno.h>

#include"sitar.h"
#include"sitar_scan.h"
#include"sitar_com.h"
#include<almemsys/almemsys.h>
#include"jpreturn.h"

// #define STAT_BUG


extern global_data_t gd;

/* 1-> port No' 2-> Ipsddr 3-> return data,, return status code 0=open or=close
int scan_stat_connect(int, char *, char *, int);
*/


/*----------------- SCAN STAT CONNECT --------------------*/
char * scan_stat_connect(int port, char * url_dom, char * backdata, char * stat, int stat_size, int timeout, int * pst)
{
int sk, re, ret, retval, dcount, arglen, resolv_ret;
unsigned long resoip;
char ipa[IP_LEN];
char * ip_addr = ipa;
struct sockaddr_in my_addr;
fd_set rfds;
struct timeval tv;
char recvd[BUF_LEN];
char sendd[BUF_LEN];
char bu[IP_LEN];
char * recvdata = recvd;
char * senddata = sendd;
char * buff = bu;

memset(recvdata, 0x00, BUF_LEN);
memset(senddata, 0x00, BUF_LEN);
memset(buff, 0x00, IP_LEN);

// struct buf_data bd;

ret = -1;
errno = 0;
dcount = 0;
resolv_ret = 0;
arglen = sizeof(int);


if((sk = socket(AF_INET, SOCK_STREAM, 0))==-1){
   fprintf(stderr,"scan_stat URL=%s Port=%d tcp %s", url_dom, port, SOCK_1);
   backdata=safe_sprintf(backdata, BUF_MAX, "URL=%s Port=%d: %s", url_dom, port, SOCK_1);
   * pst = -1;
   return backdata;
   }

my_addr.sin_family = AF_INET;
my_addr.sin_port = htons(port);

resoip = 0;

if(0 == self_memcmp(gd.di.dns_name, "RESOLV")){
   backdata = resolvename_th(backdata, url_dom, timeout, &resoip);
   }
else{
   backdata = resolvename_sk(backdata, url_dom, timeout, &resoip, gd.di.dns_name, &resolv_ret, '4');
   }

my_addr.sin_addr.s_addr = resoip;

if(0 == (int)my_addr.sin_addr.s_addr || resoip == (int)NULL){
   backdata=safe_sprintf(backdata,BUF_MAX,"%s %d: %s\n", url_dom, (int)my_addr.sin_addr.s_addr, SOCK_2);
   close(sk);
   * pst = -1;
   return backdata;
   }

// ip_addr = inet_ntoa(my_addr.sin_addr);
ip_addr = (char *)inet_ntop(AF_INET, &my_addr.sin_addr, buff, IP_LEN);

#ifdef STAT_BUG
printf("STAT: scan_stat_connect(0): %s %s %d\n", url_dom, ip_addr, port);
#endif

// 非同期通信に切り替え、コネクション実行
fcntl(sk, F_SETFL, O_NONBLOCK);
re = connect(sk, (struct sockaddr *)(long int)&my_addr, sizeof(my_addr));


// 速攻で繋がった場合の処理
if(re >= 0){
  // 非同期通信から同期通信に
   fcntl(sk, F_SETFL, 0);
   backdata=safe_sprintf(backdata,BUF_MAX, "STAT=%s Port=%d: %s", url_dom, port, SOCK_5);
   #ifdef STAT_BUG
   printf("STAT: scan_stat_connect(1): CONNECT SUCCESS %s\n", backdata);
   #endif
   goto notselect;
   }


// errnoが EINPROGRESS な場合
if(errno == EINPROGRESS){
   tv.tv_sec = timeout;
   tv.tv_usec = 0;
   while(1){
      FD_ZERO(&rfds);
      FD_SET(sk, &rfds);
      retval = select(sk + 1, &rfds, NULL, NULL, &tv);
      // selectのタイムアウト
      if(retval < 0){
         #ifdef STAT_BUG
         printf("STAT: scan_stat_connect(2): select error BREAK- %d -\n", retval);
         #endif
         backdata=safe_sprintf(backdata,BUF_MAX, "URL=%s Port=%d: %s", url_dom, port, SOCK_15);
         // 非同期通信から同期通信に
         fcntl(sk, F_SETFL, 0);
         close(sk);
         * pst = -1;
         return backdata;
         }
      else if(retval == 0){
         #ifdef STAT_BUG
         printf("STAT: scan_stat_connect(3): select timed out BREAK- %d -\n", retval);
         #endif
         backdata=safe_sprintf(backdata,BUF_MAX, "URL=%s Port=%d: %s", url_dom, port, SOCK_16);
         // 非同期から同期に
         fcntl(sk, F_SETFL, 0);
         close(sk);
         * pst = -1;
         return backdata;
         }
      // 時間内に接続出来たのLoopOut
      else {
         // 非同期通信から同期通信に
         fcntl(sk, F_SETFL, 0);
         #ifdef STAT_BUG
         printf("STAT: scan_stat_connect(4): select time succes BREAK- %d -\n", retval);
         #endif
         backdata=safe_sprintf(backdata,BUF_MAX, "URL=%s Port=%d: %s", url_dom, port, SOCK_3);
         break;
         }
      }


   // select を省いたGOTO
   notselect :;


   // ソケットに関するペンディングエラーを戻す
   if(getsockopt(sk, SOL_SOCKET, SO_ERROR, (void *)&retval, (void *)&arglen) < 0){
      backdata=safe_sprintf(backdata,BUF_MAX, "URL=%s Port=%d: %s", url_dom, port, SOCK_13);
      #ifdef STAT_BUG
      fprintf(stderr,"STAT: scan_stat_connect(): getsockopt(5) Errors!\n");
      #endif
      close(sk);
      * pst = -1;
      return backdata;
      }
   else{
     // エラーがある
      if(retval){
         #ifdef STAT_BUG
         printf("STAT: scan_stat_connect(6): 1 SO_ERROR %d -\n", retval);
         #endif
         backdata=safe_sprintf(backdata,BUF_MAX, "URL=%s Port=%d: Error! %s", url_dom, port, SOCK_5);
         close(sk);
         * pst = -1;
         return backdata;
         }
      // エラーが無い場合は、ステータスの確認にうつります
      else{
        // とりあえず、STATからの200番の返事をまちます

         // 再度非同期通信の開始
         fcntl(sk, F_SETFL, O_NONBLOCK);

         tv.tv_sec = timeout;
         tv.tv_usec = 0;
         while(1){
            FD_ZERO(&rfds);
            FD_SET(sk, &rfds);
            retval = select(sk + 1, &rfds, NULL, NULL, &tv);
            // select 異常終了
            if(retval < 0){
               #ifdef STAT_BUG
               printf("STAT: scan_stat_connect(7): retval 0 ERR ===\n");
               #endif 
               backdata=safe_sprintf(backdata,BUF_MAX, "URL=%s Port=%d: %s", url_dom, port, STAT_2);
               // 非同期通信から同期通信に
               fcntl(sk, F_SETFL, 0);
               close(sk);
               * pst = -1;
               return backdata;
               }
            // select のタイムアウト
            else if(retval == 0){
               #ifdef STAT_BUG
               printf("STAT: scan_stat_connect(8): retval 1 ERR\n"); 
               #endif 
               backdata=safe_sprintf(backdata,BUF_MAX, "URL=%s Port=%d: %s", url_dom, port, STAT_3);
               // 非同期通信から同期通信に
               fcntl(sk, F_SETFL, 0);
               close(sk);
               * pst = -1;
               return backdata;
               }
            else{
               // 非同期通信から同期通信に
               fcntl(sk, F_SETFL, 0);
               // fdに変化があったので読んでみたりするテスト
//             dcount = recv(sk, recvdata, BUF_LEN, 0);
               dcount = socket_readas(sk, recvdata, BUF_LEN, timeout, 1);

               #ifdef STAT_BUG
               printf("STAT: scan_stat_connect(9): recv-- %s --\n", recvdata);
               #endif
               // 受信量が異常
               if(dcount < 1){
                  backdata = safe_sprintf(backdata,BUF_MAX, "URL=%s Port=%d: %s", url_dom, port, STAT_4);
                  ret = -1;
                  fcntl(sk, F_SETFL, 0);
                  break;
                  }
               // 受信量は正常
               else{

// printf("1 dcount=<%d>  SEND=<%s> \n RECV=<%s>\n", dcount, senddata, recvdata);

                  ch_char(recvdata, senddata);

                  rm_char(senddata, '\r');
                  rm_char(senddata, '\n');
                  swap_mem(senddata, '\t', ' ');
                  swap_mem(senddata, ',', ' ');



                  // 戻り値の比較
                  if(0 == memcmp(recvdata, stat, stat_size)){
                     ret = 0;
                     }
                  else{
                     ret = -1;
                     }

                  // 戻り値が等しくない
                  if(ret < 0){
                     backdata = safe_sprintf(backdata, BUF_MAX,"%s: %s", senddata, STAT_5);
                     #ifdef STAT_BUG
                     printf("STAT: scan_stat_connect(10): ret<%d><%d> recvdata<%s> backdata<%s>\n",
                       ret,*pst, recvdata, backdata);
                     #endif
                     // 非同期通信から同期通信に
            //       fcntl(sk, F_SETFL, 0);
                     close(sk);
                     * pst = ret;
                     return backdata;
                     }
                  // 戻り値が等しい
                  else{
                     backdata = safe_sprintf(backdata, BUF_MAX,"%s: %s", senddata, STAT_6);
                     #ifdef STAT_BUG
                     printf("STAT: scan_stat_connect(11): ret<%d><%d> recvdata<%s> backdata<%s>\n",
                       ret,*pst, recvdata, backdata);
                     #endif
                     // 非同期通信から同期通信に
           //        fcntl(sk, F_SETFL, 0);
                     break;
                     }
                  }
               }  // select()
            }  // while()


         // 非同期通信から同期通信に
         fcntl(sk, F_SETFL, 0);
         close(sk);
         * pst = ret;
         return backdata;
         }
      }
   }


// 非同期通信から同期通信に
fcntl(sk, F_SETFL, 0);
backdata=safe_sprintf(backdata,BUF_MAX, "URL=%s Port=%d: %s", url_dom, port, SOCK_14);

close(sk);
* pst = -1;

return backdata;

}




