IP-Geolocation-MMDB

 view release on metacpan or  search on metacpan

MMDB.xs  view on Meta::CPAN

  CODE:
    if ((items - 1) % 2 != 0) {
        warn("Odd-length list passed to %" SVf " constructor", SVfARG(klass));
    }

    for (i = 1; i < items; i += 2) {
        key = SvPV_nolen_const(ST(i));
        value = ST(i + 1);
        if (strEQ(key, "file")) {
            file = value;
        }
    }

    if (NULL == file) {
        croak("The \"file\" parameter is mandatory");
    }

    filename = SvPVbyte_nolen(file);

    Newxz(self, 1, struct ip_geolocation_mmdb);
    storeTHX(self->perl);
    self->file = SvREFCNT_inc(file);

    mmdb_error = MMDB_open(filename, flags, &self->mmdb);
    if (MMDB_SUCCESS != mmdb_error) {
        Safefree(self);
        error = MMDB_strerror(mmdb_error);
        croak("Error opening database file \"%" SVf "\": %s", SVfARG(file),
              error);
    }

    RETVAL = sv_bless(newRV_noinc(newSViv(PTR2IV(self))),
                      gv_stashsv(klass, GV_ADD));
    self->selfrv = SvRV(RETVAL); /* no inc */
  OUTPUT:
    RETVAL

void
DESTROY(self)
    IP::Geolocation::MMDB self
  CODE:
    MMDB_close(&self->mmdb);
    SvREFCNT_dec(self->file);
    Safefree(self);

void
get(self, ...)
    IP::Geolocation::MMDB self
  ALIAS:
    record_for_address = 1
  INIT:
    const char *ip_address;
    int gai_error, mmdb_error;
    const char *error;
    MMDB_lookup_result_s result;
    MMDB_entry_data_list_s *list;
    SV *data = &PL_sv_undef;
    int wants_prefix_length = 0;
    uint16_t prefix_length = 0;
    U8 gimme = GIMME_V;
  PPCODE:
    ip_address = NULL;
    if (items > 1) {
        ip_address = SvPVbyte_nolen(ST(1));
    }
    if (NULL == ip_address || '\0' == *ip_address) {
        croak("%s", "You must provide an IP address to look up");
    }
    result =
        MMDB_lookup_string(&self->mmdb, ip_address, &gai_error, &mmdb_error);
    if (0 != gai_error) {
        croak("The IP address you provided (%s) is not a valid IPv4 or IPv6 "
              "address", ip_address);
    }
    if (MMDB_SUCCESS != mmdb_error) {
        error = MMDB_strerror(mmdb_error);
        croak("Error looking up IP address \"%s\": %s", ip_address, error);
    }
    if (result.found_entry) {
        list = NULL;
        mmdb_error = MMDB_get_entry_data_list(&result.entry, &list);
        if (MMDB_SUCCESS == mmdb_error) {
            (void) decode_entry_data_list(self, list, &data, &mmdb_error);
        }
        MMDB_free_entry_data_list(list);
        if (MMDB_SUCCESS != mmdb_error) {
            error = MMDB_strerror(mmdb_error);
            croak("Entry data error looking up \"%s\": %s", ip_address,
                  error);
        }
        if (0 == ix && G_SCALAR != gimme) {
            wants_prefix_length = 1;
            if (instr(ip_address, ".") && is_ipv6_database(&self->mmdb)) {
                prefix_length = result.netmask - 96;
            }
            else {
                prefix_length = result.netmask;
            }
        }
    }
    XPUSHs(sv_2mortal(data));
    if (wants_prefix_length) {
        XPUSHs(sv_2mortal(newSVuv(prefix_length)));
    }

void
iterate_search_tree(self, ...)
    IP::Geolocation::MMDB self
  INIT:
    SV *data_callback;
    SV *node_callback;
    iterate_data data;
    numeric_ip ipnum;
  CODE:
    data_callback = &PL_sv_undef;
    node_callback = &PL_sv_undef;
    if (items > 1) {
        data_callback = ST(1);
        if (items > 2) {
            node_callback = ST(2);
        }



( run in 0.744 second using v1.01-cache-2.11-cpan-71847e10f99 )