From nobody Sat Nov 23 17:07:05 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of lists.libvirt.org designates 8.43.85.245 as permitted sender) client-ip=8.43.85.245; envelope-from=devel-bounces@lists.libvirt.org; helo=lists.libvirt.org; Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of lists.libvirt.org designates 8.43.85.245 as permitted sender) smtp.mailfrom=devel-bounces@lists.libvirt.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.libvirt.org (lists.libvirt.org [8.43.85.245]) by mx.zohomail.com with SMTPS id 1723672617271325.1717833878648; Wed, 14 Aug 2024 14:56:57 -0700 (PDT) Received: by lists.libvirt.org (Postfix, from userid 996) id 2F231135F; Wed, 14 Aug 2024 17:56:56 -0400 (EDT) Received: from lists.libvirt.org (localhost [IPv6:::1]) by lists.libvirt.org (Postfix) with ESMTP id 67BC01585; Wed, 14 Aug 2024 17:43:34 -0400 (EDT) Received: by lists.libvirt.org (Postfix, from userid 996) id 2F8A91374; Wed, 14 Aug 2024 17:43:31 -0400 (EDT) Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by lists.libvirt.org (Postfix) with ESMTPS id E28CA135F for ; Wed, 14 Aug 2024 17:43:19 -0400 (EDT) Received: from mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-625-2WOcpNNCPE-KcyNpPKY0yA-1; Wed, 14 Aug 2024 17:43:18 -0400 Received: from mx-prod-int-02.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-02.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.15]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 49BFA195420C for ; Wed, 14 Aug 2024 21:43:17 +0000 (UTC) Received: from hjs.brq.redhat.com (unknown [10.43.3.187]) by mx-prod-int-02.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 990C11955E8C for ; Wed, 14 Aug 2024 21:43:16 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on lists.libvirt.org X-Spam-Level: X-Spam-Status: No, score=-0.6 required=5.0 tests=DKIM_INVALID,DKIM_SIGNED, HEADER_FROM_DIFFERENT_DOMAINS,MAILING_LIST_MULTI,RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H3,RCVD_IN_MSPIKE_WL,SPF_HELO_NONE,T_SCC_BODY_TEXT_LINE autolearn=unavailable autolearn_force=no version=3.4.4 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1723671799; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=1BMBClpTDdDrN3RLGoi6KD1k63efi+8YHYIx+5sW2z0=; b=IVNbKfoS3bj+UEPxen3JG3BBm7ToV6hrhD2BbAQNqediV2cXuIAZye5R1z2bTIdUPoAhfN x5E9DMEsS2B7KjIfPnrmgnll2i0L4milv3WzFDrWx/yaKIwYZJqGK8vvvRXVe50maJENSW lFRG2xN7Z3I8KBT7NfvhWc7BFGdnWyo= X-MC-Unique: 2WOcpNNCPE-KcyNpPKY0yA-1 From: =?UTF-8?q?J=C3=A1n=20Tomko?= To: devel@lists.libvirt.org Subject: [libvirt PATCH 10/20] nss: convert findLeases to use json-c Date: Wed, 14 Aug 2024 23:40:25 +0200 Message-ID: <90992f7c718a61f4c63f20574fec457124527378.1723671635.git.jtomko@redhat.com> In-Reply-To: References: MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.15 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: quoted-printable Message-ID-Hash: T4QXSQ5WHL4HH5KZVDZCAU7LKHEV6WXK X-Message-ID-Hash: T4QXSQ5WHL4HH5KZVDZCAU7LKHEV6WXK X-MailFrom: jtomko@redhat.com X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; header-match-config-1; header-match-config-2; header-match-config-3; header-match-devel.lists.libvirt.org-0; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; suspicious-header X-Mailman-Version: 3.2.2 Precedence: list List-Id: Development discussions about the libvirt library & tools Archived-At: List-Archive: List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZM-MESSAGEID: 1723672619014116600 Content-Type: text/plain; charset="utf-8" While the parsing is still done by 1K buffers, the results are no longer filtered during the parsing, but the whole JSON has to live in memory at once, which was also the case before the NSS plugin dropped its dependency on libvirt_util. Also, the new parser might be more forgiving of missing elements. Signed-off-by: J=C3=A1n Tomko --- tools/nss/libvirt_nss_leases.c | 339 ++++++++++----------------------- 1 file changed, 96 insertions(+), 243 deletions(-) diff --git a/tools/nss/libvirt_nss_leases.c b/tools/nss/libvirt_nss_leases.c index 770dae8625..86bf184ea5 100644 --- a/tools/nss/libvirt_nss_leases.c +++ b/tools/nss/libvirt_nss_leases.c @@ -26,39 +26,11 @@ #include #include =20 -#include -#include +#include =20 #include "libvirt_nss_leases.h" #include "libvirt_nss.h" =20 -enum { - FIND_LEASES_STATE_START, - FIND_LEASES_STATE_LIST, - FIND_LEASES_STATE_ENTRY, -}; - - -typedef struct { - const char *name; - char **macs; - size_t nmacs; - int state; - unsigned long long now; - int af; - bool *found; - leaseAddress **addrs; - size_t *naddrs; - - char *key; - struct { - unsigned long long expiry; - char *ipaddr; - char *macaddr; - char *hostname; - } entry; -} findLeasesParser; - =20 static int appendAddr(const char *name __attribute__((unused)), @@ -157,189 +129,102 @@ appendAddr(const char *name __attribute__((unused)), =20 =20 static int -findLeasesParserInteger(void *ctx, - long long val) +findLeaseInJSON(json_object *jobj, + const char *name, + char **macs, + size_t nmacs, + int af, + time_t now, + leaseAddress **addrs, + size_t *naddrs, + bool *found) { - findLeasesParser *parser =3D ctx; + size_t i, j; + int len; =20 - DEBUG("Parse int state=3D%d '%lld' (map key '%s')", - parser->state, val, NULLSTR(parser->key)); - if (!parser->key) - return 0; - - if (parser->state =3D=3D FIND_LEASES_STATE_ENTRY) { - if (strcmp(parser->key, "expiry-time")) - return 0; - - parser->entry.expiry =3D val; - } else { - return 0; + if (!json_object_is_type(jobj, json_type_array)) { + ERROR("parsed JSON does not contain the leases array"); + return -1; } - return 1; -} =20 + len =3D json_object_array_length(jobj); + for (i =3D 0; i < len; i++) { + json_object *lease =3D NULL; + json_object *expiry =3D NULL; + json_object *ipobj =3D NULL; + unsigned long long expiryTime; + const char *ipaddr; =20 -static int -findLeasesParserString(void *ctx, - const unsigned char *stringVal, - size_t stringLen) -{ - findLeasesParser *parser =3D ctx; + lease =3D json_object_array_get_idx(jobj, i); =20 - DEBUG("Parse string state=3D%d '%.*s' (map key '%s')", - parser->state, (int)stringLen, (const char *)stringVal, - NULLSTR(parser->key)); - if (!parser->key) - return 0; + if (macs) { + const char *macAddr; + bool match =3D false; + json_object *val; =20 - if (parser->state =3D=3D FIND_LEASES_STATE_ENTRY) { - if (!strcmp(parser->key, "ip-address")) { - if (!(parser->entry.ipaddr =3D strndup((char *)stringVal, stri= ngLen))) - return 0; - } else if (!strcmp(parser->key, "mac-address")) { - if (!(parser->entry.macaddr =3D strndup((char *)stringVal, str= ingLen))) - return 0; - } else if (!strcmp(parser->key, "hostname")) { - if (!(parser->entry.hostname =3D strndup((char *)stringVal, st= ringLen))) - return 0; + val =3D json_object_object_get(lease, "mac-address"); + if (!val) + continue; + + macAddr =3D json_object_get_string(val); + if (!macAddr) + continue; + + for (j =3D 0; j < nmacs; j++) { + if (!strcmp(macs[j], macAddr)) { + match =3D true; + break; + } + } + if (!match) + continue; } else { - return 1; - } - } else { - return 0; - } - return 1; -} - - -static int -findLeasesParserMapKey(void *ctx, - const unsigned char *stringVal, - size_t stringLen) -{ - findLeasesParser *parser =3D ctx; - - DEBUG("Parse map key state=3D%d '%.*s'", - parser->state, (int)stringLen, (const char *)stringVal); - - free(parser->key); - if (!(parser->key =3D strndup((char *)stringVal, stringLen))) - return 0; - - return 1; -} - - -static int -findLeasesParserStartMap(void *ctx) -{ - findLeasesParser *parser =3D ctx; - - DEBUG("Parse start map state=3D%d", parser->state); - - if (parser->state !=3D FIND_LEASES_STATE_LIST) - return 0; - - free(parser->key); - parser->key =3D NULL; - parser->state =3D FIND_LEASES_STATE_ENTRY; - - return 1; -} - - -static int -findLeasesParserEndMap(void *ctx) -{ - findLeasesParser *parser =3D ctx; - size_t i; - bool found =3D false; - - DEBUG("Parse end map state=3D%d", parser->state); + const char *leaseName; + json_object *val; =20 - if (parser->entry.macaddr =3D=3D NULL) - return 0; + val =3D json_object_object_get(lease, "hostname"); + if (!val) + continue; =20 - if (parser->state !=3D FIND_LEASES_STATE_ENTRY) - return 0; + leaseName =3D json_object_get_string(val); + if (!leaseName) + continue; =20 - if (parser->nmacs) { - DEBUG("Check %zu macs", parser->nmacs); - for (i =3D 0; i < parser->nmacs && !found; i++) { - DEBUG("Check mac '%s' vs '%s'", parser->macs[i], NULLSTR(parse= r->entry.macaddr)); - if (parser->entry.macaddr && !strcmp(parser->macs[i], parser->= entry.macaddr)) - found =3D true; + if (strcasecmp(leaseName, name)) + continue; } - } else { - DEBUG("Check name '%s' vs '%s'", parser->name, NULLSTR(parser->ent= ry.hostname)); - if (parser->entry.hostname && !strcasecmp(parser->name, parser->en= try.hostname)) - found =3D true; - } - DEBUG("Found %d", found); - if (parser->entry.expiry !=3D 0 && - parser->entry.expiry < parser->now) { - DEBUG("Entry expired at %llu vs now %llu", - parser->entry.expiry, parser->now); - found =3D false; - } - if (!parser->entry.ipaddr) - found =3D false; - - if (found) { - *parser->found =3D true; - - if (appendAddr(parser->name, - parser->addrs, parser->naddrs, - parser->entry.ipaddr, - parser->entry.expiry, - parser->af) < 0) - return 0; - } - - free(parser->entry.macaddr); - free(parser->entry.ipaddr); - free(parser->entry.hostname); - parser->entry.expiry =3D 0; - parser->entry.macaddr =3D NULL; - parser->entry.ipaddr =3D NULL; - parser->entry.hostname =3D NULL; =20 - parser->state =3D FIND_LEASES_STATE_LIST; - - return 1; -} + expiry =3D json_object_object_get(lease, "expiry-time"); + if (!expiry) { + ERROR("Missing expiry time for %s", name); + return -1; + } =20 + expiryTime =3D json_object_get_uint64(expiry); + if (expiryTime && expiryTime < now) { + DEBUG("Skipping expired lease for %s", name); + continue; + } =20 -static int -findLeasesParserStartArray(void *ctx) -{ - findLeasesParser *parser =3D ctx; + ipobj =3D json_object_object_get(lease, "ip-address"); + if (!ipobj) { + DEBUG("Missing IP address for %s", name); + continue; + } + ipaddr =3D json_object_get_string(ipobj); =20 - DEBUG("Parse start array state=3D%d", parser->state); + DEBUG("Found record for %s", name); + *found =3D true; =20 - if (parser->state =3D=3D FIND_LEASES_STATE_START) { - parser->state =3D FIND_LEASES_STATE_LIST; - } else { - return 0; + if (appendAddr(name, + addrs, naddrs, + ipaddr, + expiryTime, + af) < 0) + return -1; } =20 - return 1; -} - - -static int -findLeasesParserEndArray(void *ctx) -{ - findLeasesParser *parser =3D ctx; - - DEBUG("Parse end array state=3D%d", parser->state); - - if (parser->state =3D=3D FIND_LEASES_STATE_LIST) - parser->state =3D FIND_LEASES_STATE_START; - else - return 0; - - return 1; + return 0; } =20 =20 @@ -356,30 +241,10 @@ findLeases(const char *file, { int fd =3D -1; int ret =3D -1; - const yajl_callbacks parserCallbacks =3D { - NULL, /* null */ - NULL, /* bool */ - findLeasesParserInteger, - NULL, /* double */ - NULL, /* number */ - findLeasesParserString, - findLeasesParserStartMap, - findLeasesParserMapKey, - findLeasesParserEndMap, - findLeasesParserStartArray, - findLeasesParserEndArray, - }; - findLeasesParser parserState =3D { - .name =3D name, - .macs =3D macs, - .nmacs =3D nmacs, - .af =3D af, - .now =3D now, - .found =3D found, - .addrs =3D addrs, - .naddrs =3D naddrs, - }; - yajl_handle parser =3D NULL; + json_object *jobj =3D NULL; + json_tokener *tok =3D NULL; + enum json_tokener_error jerr =3D json_tokener_success; + int jsonflags =3D JSON_TOKENER_STRICT | JSON_TOKENER_VALIDATE_UTF8; char line[1024]; ssize_t nreadTotal =3D 0; int rv; @@ -389,51 +254,39 @@ findLeases(const char *file, goto cleanup; } =20 - parser =3D yajl_alloc(&parserCallbacks, NULL, &parserState); - if (!parser) { - ERROR("Unable to create JSON parser"); - goto cleanup; - } + tok =3D json_tokener_new(); + json_tokener_set_flags(tok, jsonflags); =20 - while (1) { - rv =3D read(fd, line, sizeof(line)); + while (jerr !=3D json_tokener_continue) { + rv =3D read(fd, line, sizeof(line) - 1); if (rv < 0) goto cleanup; if (rv =3D=3D 0) break; nreadTotal +=3D rv; =20 - if (yajl_parse(parser, (const unsigned char *)line, rv) !=3D - yajl_status_ok) { - unsigned char *err =3D yajl_get_error(parser, 1, - (const unsigned char*)line= , rv); - ERROR("Parse failed %s", (const char *) err); - yajl_free_error(parser, err); - goto cleanup; - } + line[rv] =3D 0; + + jobj =3D json_tokener_parse_ex(tok, line, rv); + jerr =3D json_tokener_get_error(tok); } =20 - if (nreadTotal > 0 && - yajl_complete_parse(parser) !=3D yajl_status_ok) { - ERROR("Parse failed %s", - yajl_get_error(parser, 1, NULL, 0)); + if (nreadTotal > 0 && jerr !=3D json_tokener_success) { + ERROR("Cannot parse %s: %s", file, json_tokener_error_desc(jerr)); goto cleanup; } =20 - ret =3D 0; + ret =3D findLeaseInJSON(jobj, name, macs, nmacs, af, now, + addrs, naddrs, found); =20 cleanup: + json_object_put(jobj); + json_tokener_free(tok); if (ret !=3D 0) { free(*addrs); *addrs =3D NULL; *naddrs =3D 0; } - if (parser) - yajl_free(parser); - free(parserState.entry.ipaddr); - free(parserState.entry.macaddr); - free(parserState.entry.hostname); - free(parserState.key); if (fd !=3D -1) close(fd); return ret; --=20 2.45.2