//get the index static ngx_http_dclass_kvdata_str *ngx_http_dclass_index(ngx_http_request_t *r) { ngx_uint_t i; u_char *hfield=NULL; ngx_uint_t key; ngx_str_t str; ngx_http_variable_value_t *val; const dclass_keyvalue *kvd; ngx_list_part_t *part; ngx_table_elt_t *header; ngx_http_dclass_conf_t *cf; ngx_http_dclass_kvdata_str *kvs; cf = ngx_http_get_module_loc_conf(r,ngx_http_dclass_module); if(!cf->enable || !cf->head[0]) return NULL; ngx_str_set(&str,"dclass_ptr"); key=ngx_hash_key(str.data,str.len); val=ngx_http_get_variable(r, &str, key); if(val && val->valid && val->data && !ngx_rstrncmp((u_char*)"ptr",val->data,3)) { kvs=(ngx_http_dclass_kvdata_str*)val->data; ngx_log_error(NGX_HTTP_DCLASS_LOGLEVEL,r->connection->log,0,"dClass: classify cache: '%s'",kvs->kvd[0]->id); return kvs; } if(!*cf->hfield.data) { if(r->headers_in.user_agent) hfield = r->headers_in.user_agent->value.data; } else { part=&r->headers_in.headers.part; header=part->elts; for (i=0;;i++) { if(i>=part->nelts) { if(part->next==NULL) break; part=part->next; header=part->elts; i=0; } if(!ngx_strcasecmp(cf->hfield.data,header[i].key.data)) { hfield=header[i].value.data; break; } } } if(hfield==NULL) return NULL; kvs=(ngx_http_dclass_kvdata_str*)ngx_pcalloc(r->pool,sizeof(ngx_http_dclass_kvdata_str)); if(kvs==NULL) return NULL; for(i=0;i<NGX_HTTP_DCLASS_INDEXES && cf->head[i];i++) { kvd=dclass_classify(cf->head[i],(char*)hfield); kvs->kvd[i]=kvd; ngx_cpystrn(kvs->data,(u_char*)"ptr",4); ngx_log_error(NGX_HTTP_DCLASS_LOGLEVEL,r->connection->log,0,"dClass: classify %d: '%s' => '%s'",i,hfield,kvd->id); } return kvs; }
int main(int argc,char **args) { int ret,i; int openddr=0; long count,ttime; char buf[1024]; char *loadFile="../dtrees/openddr.dtree"; char *outFile=""; char *parameter=NULL; struct timespec startn,endn,diffn,total; dclass_index di; dtree_dt_index *h=&di.dti; const dclass_keyvalue *kvd; for(i=1;i<argc;i++) { //-l [dtree file] if(!strcmp(args[i],"-l") && argc>(++i)) loadFile=args[i]; //-o [output dtree file] else if(!strcmp(args[i],"-o") && argc>(++i)) outFile=args[i]; //-m [open ddr resource dir] else if(!strcmp(args[i],"-d") && argc>(++i)) { openddr=1; loadFile=args[i]; } else if(!strncmp(args[i],"-h",2) || !strncmp(args[i],"--h",3)) { printf("Usage: dclass_client [OPTIONS] [FILE|STRING]\n\n"); printf(" -l <path> load dtree from file\n"); printf(" -o <path> store dtree to file\n"); printf(" -d <folder path> load OpenDDR resources xmls\n"); printf(" FILE STRING text file\n"); printf(" STRING test string\n"); return 0; } //[test string] | [test file] else parameter=args[i]; } printf("dClass - Device classification (version %s)\n",dclass_get_version()); printf("Loading %s: '%s'\n",openddr?"openddr":"dtree",loadFile); clock_gettime(CLOCK_REALTIME,&startn); if(openddr) ret=openddr_load_resources(&di,loadFile); else ret=dclass_load_file(&di,loadFile); clock_gettime(CLOCK_REALTIME,&endn); dtree_timersubn(&endn,&startn,&diffn); printf("load dtree tokens: %d time: %lds %ldms %ldus %ldns\n", ret,diffn.tv_sec,diffn.tv_nsec/1000000,diffn.tv_nsec/1000%1000,diffn.tv_nsec%1000); printf("dtree stats: nodes: %zu slabs: %zu mem: %zu bytes strings: %zu(%zu,%zu)\n", h->node_count,h->slab_count,h->size,h->dc_count,h->dc_slab_count,h->dc_slab_pos); clock_gettime(CLOCK_REALTIME,&startn); count=dtree_print(h,&dclass_get_id); clock_gettime(CLOCK_REALTIME,&endn); dtree_timersubn(&endn,&startn,&diffn); printf("walk tree: %ld tokens %zu nodes time: %lds %ldms %ldus %ldns\n", count,h->node_count,diffn.tv_sec,diffn.tv_nsec/1000000,diffn.tv_nsec/1000%1000,diffn.tv_nsec%1000); if(*outFile) { printf("Dumping dtree: '%s'\n",outFile); ret=dclass_write_file(&di,outFile); printf("Wrote %d entries\n",ret); } clock_gettime(CLOCK_REALTIME,&startn); kvd=dclass_classify(&di,"Mozilla/5.0 (Linux; U; Android 2.2; en; HTC Aria A6380 Build/ERE27) AppleWebKit/540.13+ (KHTML, like Gecko) Version/3.1 Mobile Safari/524.15.0"); clock_gettime(CLOCK_REALTIME,&endn); dtree_timersubn(&endn,&startn,&diffn); printf("HTC Aria UA lookup: '%s' time: %lds %ldms %ldus %ldns\n", kvd->id,diffn.tv_sec,diffn.tv_nsec/1000000,diffn.tv_nsec/1000%1000,diffn.tv_nsec%1000); if(parameter) { FILE *f; if((f=fopen(parameter,"r"))) { printf("UA file: '%s'\n",parameter); count=0; memset(&total,0,sizeof(total)); while(fgets(buf,sizeof(buf),f)) { #if DTREE_TEST_UALOOKUP int slen=strlen(buf)-1; if(buf[slen]=='\n') buf[slen]='\0'; printf("UA: '%s'\n",buf); fflush(stdout); #endif clock_gettime(CLOCK_REALTIME,&startn); kvd=dclass_classify(&di,buf); clock_gettime(CLOCK_REALTIME,&endn); dtree_timersubn(&endn,&startn,&diffn); total.tv_sec+=diffn.tv_sec; total.tv_nsec+=diffn.tv_nsec; count++; #if DTREE_TEST_UALOOKUP printf("UA lookup %ld: '%s' time: %lds %ldms %ldus %ldns\n", count,kvd->id,diffn.tv_sec,diffn.tv_nsec/1000000,diffn.tv_nsec/1000%1000,diffn.tv_nsec%1000); #endif } fclose(f); if(!count) count=1; ttime=(total.tv_sec*1000*1000*1000)+total.tv_nsec; ttime/=count; printf("TOTAL average time: %ld lookups, %lds %ldms %ldus %ldns\n", count,ttime/1000000000,ttime/1000000%1000000,ttime/1000%1000,ttime%1000); } else { printf("UA: '%s'\n",parameter); clock_gettime(CLOCK_REALTIME,&startn); kvd=dclass_classify(&di,parameter); clock_gettime(CLOCK_REALTIME,&endn); dtree_timersubn(&endn,&startn,&diffn); printf("Param UA lookup: '%s' time: %lds %ldms %ldus %ldns\n", kvd->id,diffn.tv_sec,diffn.tv_nsec/1000000,diffn.tv_nsec/1000%1000,diffn.tv_nsec%1000); if(kvd && kvd->size) { printf("OpenDDR attributes => "); for(i=0;i<kvd->size;i++) printf("%s: '%s' ",kvd->keys[i],kvd->values[i]); printf("\n"); } } } dclass_free(&di); return 0; }
//populated the dclass variable static ngx_int_t ngx_http_dclass_class_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data) { ngx_http_dclass_conf_t *cf; u_char *hfield=NULL; ngx_list_part_t *part; ngx_table_elt_t *header; ngx_uint_t i; dclass_keyvalue *kvd; cf = ngx_http_get_module_loc_conf(r, ngx_http_dclass_module); v->valid=1; v->escape=0; v->no_cacheable=0; v->not_found=0; if(!cf->enable || !cf->head) { v->data=(u_char*)"error"; v->len=5; return NGX_OK; } if(!*cf->hfield.data) { if(r->headers_in.user_agent) hfield = r->headers_in.user_agent->value.data; } else { part = &r->headers_in.headers.part; header = part->elts; for (i=0;;i++) { if (i >= part->nelts) { if (part->next == NULL) break; part = part->next; header = part->elts; i = 0; } if(!ngx_strcasecmp(cf->hfield.data,header[i].key.data)) { hfield=header[i].value.data; break; } } } if(hfield == NULL) { v->data=(u_char*)"unknown"; v->len=7; return NGX_OK; } kvd=(dclass_keyvalue*)dclass_classify(cf->head,(char*)hfield); if(!kvd) { v->data=(u_char*)"null"; v->len=4; return NGX_OK; } v->data=(u_char*)kvd->id; v->len=ngx_strlen(kvd->id); return NGX_OK; }