Ciro Santilli OurBigBook.com  Sponsor 中国独裁统治 China Dictatorship 新疆改造中心、六四事件、法轮功、郝海东、709大抓捕、2015巴拿马文件 邓家贵、低端人口、西藏骚乱
sqlite/ip.c
/* https://cirosantilli.com/sqlite-c-extension
 *
 * Adapted from: https://www.sqlite.org/src/file/ext/misc/rot13.c
 */

#include "sqlite3ext.h"
SQLITE_EXTENSION_INIT1
#include <assert.h>
#include <string.h>
#include <stdint.h>

#include <arpa/inet.h> /* pton, ntop */

/** ipv4 String to Integer */
static void ips2i(
  sqlite3_context *context,
  int argc,
  sqlite3_value **argv
){
  const unsigned char *zIn;
  struct in_addr addr;
  int s;

  assert( argc==1 );
  if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return;
  zIn = (const unsigned char*)sqlite3_value_text(argv[0]);
  s = inet_pton(AF_INET, (const char * restrict)zIn, &addr);
  if (s <= 0) {
    /* TODO report error nicely. */
  }
  /* Need int64 otherwise overflows int32_t. There is no unsigned version apparently. */
  sqlite3_result_int64(context, ntohl(addr.s_addr));
}

/** ipv4 Integer to String */
static void ipi2s(
  sqlite3_context *context,
  int argc,
  sqlite3_value **argv
){
  struct in_addr addr;
  char zOut[INET_ADDRSTRLEN];

  assert( argc==1 );
  if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return;
  addr.s_addr = ntohl(sqlite3_value_int64(argv[0]));
  inet_ntop(AF_INET, &addr, zOut, INET_ADDRSTRLEN);
  /* TODO any way to avoid the strlen here? inet_ntop does not seem to return it. */
  sqlite3_result_text(context, (char*)zOut, strlen(zOut), SQLITE_TRANSIENT);
}

int sqlite3_ip_init(
  sqlite3 *db,
  char **pzErrMsg,
  const sqlite3_api_routines *pApi
){
  int rc = SQLITE_OK;
  SQLITE_EXTENSION_INIT2(pApi);
  (void)pzErrMsg;
  rc = sqlite3_create_function(db, "ips2i", 1,
                   SQLITE_UTF8|SQLITE_INNOCUOUS|SQLITE_DETERMINISTIC,
                   0, ips2i, 0, 0);
  if (rc == 0) {
    rc = sqlite3_create_function(db, "ipi2s", 1,
                    SQLITE_UTF8|SQLITE_INNOCUOUS|SQLITE_DETERMINISTIC,
                    0, ipi2s, 0, 0);
  }
  return rc;
}