Diff for /parser3/src/classes/inet.C between versions 1.4 and 1.22

version 1.4, 2010/10/21 15:06:27 version 1.22, 2026/07/19 14:25:42
Line 1 Line 1
 /** @file  /** @file
         Parser: @b inet parser class.          Parser: @b inet parser class.
   
         Copyright(c) 2001-2009 ArtLebedev Group(http://www.artlebedev.com)          Copyright (c) 2001-2026 Art. Lebedev Studio (https://www.artlebedev.com)
         Author: Alexandr Petrosian <paf@design.ru>(http://paf.design.ru)          Authors: Konstantin Morshnev <moko@design.ru>, Alexandr Petrosian <paf@design.ru>
 */  */
   
 static const char * const IDENT_INET_C="$Date$";  
   
 #include "pa_vmethod_frame.h"  #include "pa_vmethod_frame.h"
 #include "pa_request.h"  #include "pa_request.h"
   #include "pa_vtable.h"
   
   #ifdef _MSC_VER
   #include "winsock2.h"
   #include "ws2tcpip.h"
   #endif
   
   volatile const char * IDENT_INET_C="$Id$";
   
 class MInet: public Methoded {  class MInet: public Methoded {
 public:  public:
Line 17  public: Line 23  public:
   
 // global variables  // global variables
   
 DECLARE_CLASS_VAR(inet, new MInet, 0);  DECLARE_CLASS_VAR(inet, new MInet);
   
   
 static void _ntoa(Request& r, MethodParams& params){  static void _ntoa(Request& r, MethodParams& params){
         unsigned long l=(unsigned long)trunc(params.as_double(0, "parameter must be expression", r));          unsigned long l=(unsigned long)trunc(params.as_double(0, "parameter must be expression", r));
         static const int ip_cstr_bufsize=3*4+3+1+1;          static const int ip_cstr_bufsize=3*4+3+1/*zero-teminator*/+1/*for faulty snprintfs*/;
         char* ip_cstr=new(PointerFreeGC) char[ip_cstr_bufsize];          char* ip_cstr=new(PointerFreeGC) char[ip_cstr_bufsize];
           snprintf(ip_cstr, ip_cstr_bufsize, "%u.%u.%u.%u", (l>>24) & 0xFF, (l>>16) & 0xFF, (l>>8) & 0xFF, l & 0xFF);
         snprintf(ip_cstr, ip_cstr_bufsize, "%u.%u.%u.%u",          r.write(*new String(ip_cstr));
                                 (l>>24) & 0xFF,  
                                 (l>>16) & 0xFF,  
                                 (l>>8) & 0xFF,  
                                 l & 0xFF);  
   
         r.write_no_lang(*new String(ip_cstr));  
 }  }
   
 static void _aton(Request& r, MethodParams& params){  static void _aton(Request& r, MethodParams& params){
         const String ip=params.as_string(0, PARAMETER_MUST_BE_STRING);          const String ip=params.as_string(0, PARAMETER_MUST_BE_STRING);
         if(ip.is_empty())          if(ip.is_empty())
                 throw Exception(PARSER_RUNTIME,                  throw Exception(PARSER_RUNTIME, 0, "IP address must not be empty.");
                         0,  
                         "IP address must not be empty.");  
   
         const char* ip_cstr=ip.cstr();          const char* ip_cstr=ip.cstr();
         ulong result=0;          ulong result=0;
Line 49  static void _aton(Request& r, MethodPara Line 47  static void _aton(Request& r, MethodPara
         bool err=false;          bool err=false;
         const char* p=ip_cstr;          const char* p=ip_cstr;
         while(char c=*p++){          while(char c=*p++){
                 uint digit=(uint)(c-'0');       // assume ascii                  int digit=(int)(c-'0'); // assume ascii
                 if(digit>=0 && digit<=9){                  if(digit>=0 && digit<=9){
                         byte_start=false;                          byte_start=false;
                         if((byte_value=byte_value*10+digit) > 255){                          if((byte_value=byte_value*10+(uint)digit) > 255){
                                 err=true;                                  err=true;
                                 break;                                  break;
                         }                          }
Line 73  static void _aton(Request& r, MethodPara Line 71  static void _aton(Request& r, MethodPara
         }          }
   
         if(err || dot_cnt!=3 || byte_start){          if(err || dot_cnt!=3 || byte_start){
                 throw Exception(PARSER_RUNTIME,                  throw Exception(PARSER_RUNTIME, 0, "Invalid IP address '%s' specified.", ip_cstr);
                         0,  
                         "Invalid IP address '%s' specified.", ip_cstr);  
         } else {          } else {
                 result=(result << 8)+(ulong)byte_value;                  result=(result << 8)+(ulong)byte_value;
                 r.write_no_lang(*new VDouble(result));                  r.write(*new VDouble(result));
           }
   }
   
   int ipv_format(const String &value){
           if(value == "4") return AF_INET;
           if(value == "6") return AF_INET6;
           if(value == "any") return AF_UNSPEC;
           throw Exception(PARSER_RUNTIME, &value, "ipv option value must be 4 or 6 or any");
   }
   
   static void _ip2name(Request& r, MethodParams& params){
           const String sip=params.as_string(0, PARAMETER_MUST_BE_STRING);
           if(sip.is_empty())
                   throw Exception(PARSER_RUNTIME, 0, "IP address must not be empty.");
   
           const char* ip_cstr=sip.cstr();
   
           struct addrinfo hints, *info=0;
           memset(&hints, 0, sizeof(hints));
           hints.ai_family=AF_INET;
           hints.ai_socktype=SOCK_STREAM;
           hints.ai_flags=AI_NUMERICHOST; // to disable DNS lookup
   
           if(params.count() == 2)
                   if(HashStringValue* options=params.as_hash(1)){
                           int valid_options=0;
                           if(Value* value=options->get("ipv")){
                                   hints.ai_family=ipv_format(r.process(*value).as_string());
                                   valid_options++;
                           }
                           if(valid_options!=options->count())
                                   throw Exception(PARSER_RUNTIME, 0, CALLED_WITH_INVALID_OPTION);
                   }
   
           int error=getaddrinfo(ip_cstr, 0, &hints, &info);
           if(error==EAI_NONAME)
                   throw Exception(PARSER_RUNTIME, 0, "Invalid IP address '%s' specified", ip_cstr);
           if(error)
                   throw Exception(PARSER_RUNTIME, 0, "Invalid IP address '%s': %s", ip_cstr, gai_strerror(error));
   
           char hbuf[NI_MAXHOST];
           error=getnameinfo(info->ai_addr, info->ai_addrlen, hbuf, sizeof(hbuf), NULL, 0, NI_NAMEREQD);
   
           freeaddrinfo(info);
   
           if(!error){
                   r.write(*new String(pa_idna_decode(pa_strdup(hbuf), r.charsets.source()), String::L_TAINTED));
           } else if(error!=EAI_NONAME){
                   throw Exception(PARSER_RUNTIME, 0, "Can't resolve IP address '%s': %s", ip_cstr, gai_strerror(error));
         }          }
 }  }
   
   // also used in curl.C, returns first address or fills the table if not null
   const char *pa_name2ip(const char *name, int family, Table *table, const char *exception_type){
           struct addrinfo hints, *info;
           memset(&hints, 0, sizeof(hints));
           hints.ai_family=family;
           hints.ai_socktype=SOCK_STREAM;
   
           int error=getaddrinfo(name, NULL, &hints, &info);
   
           if(error)
                   throw Exception(exception_type, 0, "Can't resolve domain name '%s': %s", name, gai_strerror(error));
   
           const char *result=0;
           char hbuf[INET6_ADDRSTRLEN];
   
           for(struct addrinfo *cur=info; cur; cur=cur->ai_next) {
                   if(error=getnameinfo(cur->ai_addr, cur->ai_addrlen, hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST))
                           throw Exception(exception_type, 0, "Can't translate address: %s", gai_strerror(error));
                   if(table){
                           Table::element_type row(new ArrayString());
                           static const String sv4("4"), sv6("6"), sunknown("unknown");
                           *row+=new String(pa_strdup(hbuf), String::L_TAINTED);
                           *row+=cur->ai_family == AF_INET ? &sv4 : cur->ai_family == AF_INET6 ? &sv6 : &sunknown;
                           *table+=row;
                   } else {
                           result=pa_strdup(hbuf);
                           break;
                   }
           }
   
           freeaddrinfo(info);
           return result;
   }
   
   static void _name2ip(Request& r, MethodParams& params){
           const String sname=params.as_string(0, PARAMETER_MUST_BE_STRING);
           if(sname.is_empty())
                   throw Exception(PARSER_RUNTIME, 0, "Domain name must not be empty.");
   
           const char* name_cstr=pa_idna_encode(sname.cstr(), r.charsets.source());
   
           int family=AF_INET;
           Table *table=NULL;
   
           if(params.count() == 2)
                   if(HashStringValue* options=params.as_hash(1)){
                           int valid_options=0;
                           if(Value* value=options->get("ipv")){
                                   family=ipv_format(r.process(*value).as_string());
                                   valid_options++;
                           }
                           if(Value* value=options->get("table")){
                                   if(r.process(*value).as_bool()){
                                           Table::columns_type columns(new ArrayString);
                                           static const String sip("ip"), sversion("version");
                                           *columns+=&sip; *columns+=&sversion;
                                           table=new Table(columns);
                                   }
                                   valid_options++;
                           }
                           if(valid_options!=options->count())
                                   throw Exception(PARSER_RUNTIME, 0, CALLED_WITH_INVALID_OPTION);
                   }
   
           if(const char *ip=pa_name2ip(name_cstr, family, table, PARSER_RUNTIME))
                   r.write(*new String(ip, String::L_TAINTED));
   
           if(table)
                   r.write(*new VTable(table));
   }
   
   static void _hostname(Request& r, MethodParams&){
           char buf[MAX_STRING];
   
           if(gethostname(buf, MAX_STRING))
                   throw Exception(PARSER_RUNTIME, 0, "Cant't get hostname");
   
           r.write(*new String(pa_strdup(buf), String::L_TAINTED));
   }
   
 // constructor  // constructor
 MInet::MInet(): Methoded("inet") {  MInet::MInet(): Methoded("inet") {
         add_native_method("ntoa", Method::CT_STATIC, _ntoa, 1, 1);          add_native_method("ntoa", Method::CT_STATIC, _ntoa, 1, 1);
         add_native_method("aton", Method::CT_STATIC, _aton, 1, 1);          add_native_method("aton", Method::CT_STATIC, _aton, 1, 1);
           // ^inet:ip2name[ip; $.ipv[4|6|any] ]
         // @todo: gethostbyname, gethostbyaddr          add_native_method("ip2name", Method::CT_STATIC, _ip2name, 1, 2);
           // ^inet:name2ip[name; $.ipv[4|6|any] $.table(true) ]
           add_native_method("name2ip", Method::CT_STATIC, _name2ip, 1, 2);
           // ^inet:hostname[]
           add_native_method("hostname", Method::CT_STATIC, _hostname, 0, 0);
 }  }

Removed from v.1.4  
changed lines
  Added in v.1.22


E-mail: