
#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/stat.h>
#include<errno.h>

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

// #define URL_BUG

extern global_data_t gd;

char * scan_url_connect(int port, char * url_data, char * backdata, int timeout, int * pst, char head)
{
int sk, re, stat, ret, retval, dcount, arglen, resolv_ret;
unsigned long resoip;
struct sockaddr_in my_addr;
fd_set rfds;
struct timeval tv;

char recvd[BUF_LEN];
char sendd[BUF_LEN];
char ipa[IP_LEN];
char dom[BUF_URL];
char pass[BUF_URL];
char bu[IP_LEN];

char * ip_addr = ipa;
char * url_dom = dom;
char * url_pass = pass;
char * recvdata = recvd;
char * senddata = sendd;
char * buff = bu;

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

memset(recvdata, 0x00, BUF_LEN);
memset(senddata, 0x00, BUF_LEN);
memset(ip_addr, 0x00, IP_LEN);
memset(url_dom, 0x00, BUF_URL);
memset(url_pass, 0x00, BUF_URL);
memset(buff, 0x00, IP_LEN);

// portの設定よりもURLに含まれるポートを優先する
stat = urldompass_port(url_data, url_dom, url_pass, strlen(url_data)); 
if(stat > 0){
   port = stat;
   }

#ifdef URL_BUG
printf("URL_BUG: scan_url_connect(): data %s dom %s pass %s port %d\n", url_data, url_dom, url_pass, port);
#endif


if((sk = socket(AF_INET, SOCK_STREAM, 0))==-1){
   fprintf(stderr,"scan_url URL=%s Port=%d tcp %s", url_data, port, SOCK_1);
   backdata=safe_sprintf(backdata, BUF_MAX, "URL=%s Port=%d: %s", url_data, port, SOCK_1);
   #ifdef URL_BUG
   printf("URL_BUG: scan_url_connect(1): NOT CLEATE SOCKETS %s\n", backdata);
   #endif
   * pst = -1;
   return backdata;
   }

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

resoip = 0;
resolv_ret = 0;
// backdata = resolvename_th(backdata, url_dom, timeout, &resoip);
// backdata = resolvename_sk(backdata, url_dom, timeout, &resoip, &resolv_ret);

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');
   if(resolv_ret < 0){
      backdata = resolvename_sk(backdata, url_dom, DEFAULT_TIMEOUT, &resoip, gd.di.dns_name2, &resolv_ret, '4');
      fprintf(stderr,"RESOLV ERR: DNS name resolution failure <%s> %s\n", url_dom, backdata);
      }
   }

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 %s %d\n", SOCK_2, url_dom, (int)my_addr.sin_addr.s_addr);
   backdata=safe_sprintf(backdata,BUF_MAX,"%s: %s", url_dom, SOCK_2);
   #ifdef URL_BUG
   printf("URL_BUG: scan_url_connect(2):  NOT RESOLV NAME %s\n", backdata);
   #endif
   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 URL_BUG
printf("URL_BUG: scan_url_connect(3): %s\n", ip_addr);
#endif

// 非同期通信の開始 TCP ポートにコネ串ょん
fcntl(sk, F_SETFL, O_NONBLOCK);
re = connect(sk, (struct sockaddr *)(long)&my_addr, sizeof(my_addr));

// 速攻でつながった場合の処理
if(re >= 0){
   // 非同期通信から同期通信に
   fcntl(sk, F_SETFL, 0);
   backdata=safe_sprintf(backdata,BUF_MAX, "URL=%s IP=%s Port=%d: %s", url_data, ip_addr, port, SOCK_5);
   #ifdef URL_BUG
   printf("URL_BUG: scan_url_connect(4): 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, NULL, &rfds, NULL, &tv);
      // select の異常終了
      if(retval < 0){
         backdata=safe_sprintf(backdata,BUF_MAX, "URL=%s IP=%s Port=%d: %s", url_data, ip_addr, port, SOCK_15);
         #ifdef URL_BUG
         printf("URL_BUG: scan_url_connect(4): select error BREAK- %d - %s\n", retval, backdata);
         #endif
         // 非同期通信から同期通信に
         fcntl(sk, F_SETFL, 0);
         close(sk);
         * pst = -1;
         return backdata;
         }

      // select のタイムアウト
      else if(retval == 0){
         backdata=safe_sprintf(backdata,BUF_MAX, "URL=%s IP=%s Port=%d: %s", url_data, ip_addr, port, SOCK_16);
         #ifdef URL_BUG
         printf("URL_BUG: scan_url_connect(5): select time out BREAK- %d - %s\n", retval, backdata);
         #endif
         // 非同期通信から同期通信に
         fcntl(sk, F_SETFL, 0);
         close(sk);
         * pst = -1;
         return backdata;
         }
      // 時間内に接続出来たのでLoopOUTします
      else{
         // 非同期通信から同期通信に
         fcntl(sk, F_SETFL, 0);
         backdata=safe_sprintf(backdata,BUF_MAX, "URL=%s IP=%s Port=%d: %s", url_data, ip_addr, port, SOCK_3);
         #ifdef URL_BUG
         printf("URL_BUG: scan_url_connect(6): select time succes BREAK-%d- %s\n", retval, backdata);
         #endif
         break;
         }
      }



   // select を省いた GOTO
   notselect :;

   // ソケットに関するペンディングエラーを返す
   if(getsockopt(sk, SOL_SOCKET, SO_ERROR, (void *)&retval, (void *)&arglen) < 0){
      backdata=safe_sprintf(backdata,BUF_MAX, "URL=%s IP=%s Port=%d: %s", url_data, ip_addr, port, SOCK_13);
      #ifdef URL_BUG
      printf("URL_BUG: scan_url_connect(): getsockopt(7) Errors!\n");
      #endif
      close(sk);
      * pst = -1;
      return backdata;
      }
   else{
      // エラーがある場合
      if(retval){
         backdata=safe_sprintf(backdata,BUF_MAX,
          "URL=%s IP=%s Port=%d %s: %s", url_data, ip_addr, port, (retval != 0) ? strerror(retval): "0", SOCK_5);
         #ifdef URL_BUG
         printf("URL_BUG: scan_url_connect(8): 1 SO_ERROR %d %s\n", retval, backdata);
         #endif
         close(sk);
         * pst = -1;
         return backdata;
         }






      // エラーが無い場合
      else{
         backdata=safe_sprintf(backdata,BUF_MAX, "URL=%s IP=%s Port=%d: %s", url_data, ip_addr, port, SOCK_3);

         // ヘッダーを作る
         if(head == 0){
            self_set_request(senddata, url_dom, url_pass, BUF_LEN, "HEAD");
            }
         else if(head == 1){
            self_set_request(senddata, url_dom, url_pass, BUF_LEN, "GET");
            }
         else{
            self_set_request(senddata, url_dom, url_pass, BUF_LEN, "HEAD");
            }
         
         #ifdef URL_BUG
         printf("URL_BUG: scan_url_connect(9): set_request*send-%s- %s\n", senddata, backdata);
         #endif

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

         // ヘッダーの送信
         send(sk, senddata, strlen(senddata), 0);






         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){
               backdata=safe_sprintf(backdata,BUF_MAX, "URL=%s IP=%s Port=%d: %s", url_data, ip_addr, port, URL_2);
               #ifdef URL_BUG
               printf("URL_BUG: scan_url_connect(10): select error %s\n", backdata);
               #endif 
               // 非同期通信から同期通信
               fcntl(sk, F_SETFL, 0);
               close(sk);
               * pst = -1;
               return backdata;
               }
            // select のタイムアウト
            else if(retval == 0){
               backdata=safe_sprintf(backdata,BUF_MAX, "URL=%s IP=%s Port=%d: %s", url_data, ip_addr, port, URL_3);
               #ifdef URL_BUG
               printf("URL_BUG: scan_url_connect(11): select timed out %s\n", backdata); 
               #endif 
               // 非同期通信から同期通信に
               fcntl(sk, F_SETFL, 0);
               close(sk);
               * pst = -1;
               return backdata;
               }
            else{
               // 非同期通信から同期通信
               fcntl(sk, F_SETFL, 0);
               dcount = socket_readas(sk, recvdata, BUF_LEN, timeout, 1);
               #ifdef URL_BUG
               printf("URL_BUG: scan_url_connect(12): select succes. recv data %s<%d>\n", recvdata, dcount);
               #endif
               // 受信量が異常
               if(dcount < 1){
                  backdata=safe_sprintf(backdata,BUF_MAX, "URL=%s IP=%s Port=%d: %s" , url_data, ip_addr, port, URL_2);
                  ret = -1;
                  }
               // 受信量が正常である
               else{
                  // 200 番だいであることの確認
                  ret = self_check_recvdata(recvdata, senddata);
                  swap_mem(senddata, ',', ' ');

                  if(ret < 0){
                     backdata = safe_sprintf(backdata, BUF_MAX,"%s: %s", senddata, URL_1);
                     #ifdef URL_BUG
                     printf("URL_BUG: scan_url_connect(13): url check. not 200. ret<%d><%d> %s\n",
                       ret,*pst,backdata);
                     #endif 
                     }
                  else{
                     backdata = safe_sprintf(backdata, BUF_MAX,"%s: %s", senddata, URL_4);
                     #ifdef URL_BUG
                     printf("URL_BUG: scan_url_connect(14): url check. all succesd. ret<%d><%d> %s\n",
                       ret,*pst,backdata);
                     #endif 
                     }
                  }
               // 非同期通信から同期通信に
//             fcntl(sk, F_SETFL, 0);
               close(sk);
               * pst = ret;
               return backdata;
               }
            }

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

//  HOST IP が存在すらしない
// 非同期通信
fcntl(sk, F_SETFL, 0);

backdata=safe_sprintf(backdata,BUF_MAX, "URL=%s IP=%s Port=%d: %s", url_data, ip_addr, port, SOCK_14);
#ifdef URL_BUG
printf("URL_BUG: scan_url_connect(14): not connection err. %s\n", backdata); 
#endif 

close(sk);
* pst = -1;

return backdata;

}



