void MethodCreator::forward_method_to(DexMethod* meth, DexMethod* smeth) { auto code = meth->get_code(); if (code != nullptr) { meth->set_code(nullptr); delete code; } MethodCreator mc(meth); MethodBlock* block = mc.get_main_block(); std::vector<Location> args; auto proto = smeth->get_proto(); auto rtype = proto->get_rtype(); auto meth_args = proto->get_args(); if (meth_args != nullptr) { uint16_t arg_count = static_cast<uint16_t>(meth_args->get_type_list().size()); for (auto i = 0; i < arg_count; ++i) { args.push_back(mc.get_local(i)); } } block->invoke(smeth, args); if (rtype == get_void_type()) { block->ret_void(); } else { auto ret = mc.make_local(rtype); block->move_result(ret, rtype); block->ret(ret); } mc.create(); }
/** * If the caller is in the primary DEX we want to make sure there are no * references in other DEXes that may cause a verification error. * Don't inline if so. */ bool MultiMethodInliner::refs_not_in_primary(DexMethod* callee) { const auto ok_from_primary = [&](DexType* type) { if (primary.count(type) == 0 && type_class_internal(type) != nullptr) { info.not_in_primary++; return false; } return true; }; for (auto insn : callee->get_code()->get_instructions()) { if (insn->has_types()) { auto top = static_cast<DexOpcodeType*>(insn); if (!ok_from_primary(top->get_type())) { return true; } } else if (insn->has_methods()) { auto mop = static_cast<DexOpcodeMethod*>(insn); auto meth = mop->get_method(); if (!ok_from_primary(meth->get_class())) { return true; } auto proto = meth->get_proto(); if (!ok_from_primary(proto->get_rtype())) { return true; } auto args = proto->get_args(); if (args == nullptr) continue; for (const auto& arg : args->get_type_list()) { if (!ok_from_primary(arg)) { return true; } } } else if (insn->has_fields()) { auto fop = static_cast<DexOpcodeField*>(insn); auto field = fop->field(); if (!ok_from_primary(field->get_class()) || !ok_from_primary(field->get_type())) { return true; } } } return false; }
/** * Move all single impl in a single impl method signature to next pass. * We make a single optimization per pass over any given single impl so * I1, I2 and void I1.m(I2) * the first optimization (I1 or I2) moves the other interface to next pass. * That is not the case for methods on non optimizable classes, so for * I1, I2 and void C.m(I1, I2) * then m is changed in a single pass for both I1 and I2. */ void OptimizationImpl::drop_single_impl_collision(DexType* intf, SingleImplData& data, DexMethod* method) { auto check_type = [&](DexType* type) { if (type != intf && single_impls->is_single_impl(type) && !single_impls->is_escaped(type)) { single_impls->escape_interface(type, NEXT_PASS); assert(optimized.find(type) == optimized.end()); } }; auto owner = method->get_class(); if (!single_impls->is_single_impl(owner)) return; check_type(owner); auto proto = method->get_proto(); check_type(proto->get_rtype()); auto args_list = proto->get_args(); for (auto arg : args_list->get_type_list()) { check_type(arg); } }
int proc_query(js_string *raw, struct sockaddr_in *from, int sock) { q_header header; /* Header of the question */ js_string *lookfor; /* What to look for in the big hash */ js_string *origq; /* Original query asked by the user */ js_string *lc; /* Lower-case version of query asked by the user */ rr *nxstore = 0; /* A pointer to the SOA we return when we hit a NXDOMAIN */ int length, case_folded, result_code = 0, qtype; int has_recursive_authority = 0; mhash_e spot_data; int have_authority = 0; /* Do we have authority for this record? (must be 1 to return a NXDOMAIN) */ rr *point; uint32 ip; int desires_recursion = 0; /* Do they desire recursion? */ char *num_string; /* The string to put the number of thread running in */ unsigned int mem_usage; /* The amount of memory a maradns process has allocated */ /* Sanity checks */ if(js_has_sanity(raw) == JS_ERROR) return JS_SUCCESS; if(raw->unit_size != 1) return JS_SUCCESS; /* Get the header */ if(read_hdr(raw,&header) == JS_ERROR) { /* Something went wrong, return error "Format error" */ udperror(sock,raw,from,FORMAT_ERROR,"Couldn't get header"); return JS_SUCCESS; } /* We only answer questions (Thanks to Roy Arends for pointing out this security flaw) */ if(header.qr != 0) { return JS_SUCCESS; } /* We only support a qdcount of 1 */ if(header.qdcount != 1) { udperror(sock,raw,from,NOT_IMPLEMENTED,"Qdcount not 1"); return JS_SUCCESS; } /* We only support an opcode of 0 (standard query) */ if(header.opcode != 0) { /* Since TinyDNS also returns NOT_IMPLEMENTED here, no need for a fingerprint check. Note that tinydns, unlike MaraDNS, echos the question. */ udperror(sock,raw,from,NOT_IMPLEMENTED,"non-0 opcode"); return JS_SUCCESS; } /* Get the question from the stream */ if(raw->unit_count < 14) { udperror(sock,raw,from,FORMAT_ERROR,"bad question hdr"); return JS_SUCCESS; } /* Determine the length of the domain label in the question */ length = dlabel_length(raw,12); if(length < 0 || length > 255) { udperror(sock,raw,from,FORMAT_ERROR,"bad question length"); return JS_SUCCESS; } if(raw->unit_count < 16 + length) { /* 16 because 12 for the header, and 4 for the type and class */ udperror(sock,raw,from,FORMAT_ERROR,"question doesn't fit"); return JS_SUCCESS; } /* Return "not implemented" if the class is not 1 (Internet class) */ if(*(raw->string + length + 14) != 0 && *(raw->string + length + 15) != 1) { udperror(sock,raw,from,NOT_IMPLEMENTED,"Class not 1"); return JS_ERROR; } /* Create the lookfor string, returning error if appropriate */ if((lookfor = js_create(256,1)) == 0) { udperror(sock,raw,from,SERVER_FAIL,"can't create lookfor string"); return JS_ERROR; } if((origq = js_create(256,1)) == 0) { js_destroy(lookfor); udperror(sock,raw,from,SERVER_FAIL,"can't create origq string"); return JS_ERROR; } if((lc = js_create(256,1)) == 0) { js_destroy(lookfor); js_destroy(origq); udperror(sock,raw,from,SERVER_FAIL,"can't create lc string"); return JS_ERROR; } if(js_set_encode(lc,JS_US_ASCII) == JS_ERROR) { /* ASCII because we only fold the case of A-Z */ goto serv_fail; } /* Get the query we will look for from their raw query */ if(js_substr(raw,lookfor,12,length + 2) == JS_ERROR) { goto serv_fail; } /* And copy it over to the "original query" */ if(js_copy(lookfor,origq) == JS_ERROR) { goto serv_fail; } /* Get the type of query the client desires */ qtype = get_rtype(origq); if(qtype == JS_ERROR) { goto serv_fail; } if(qtype >= 250 && qtype <= 254) { /* IXFR, AXFR, and 2 more */ goto not_impl; } /* Return a timestamp */ result_code = timestamp(header.id,sock,(struct sockaddr *)from,origq); if(result_code == JS_SUCCESS) { js_destroy(lookfor); js_destroy(origq); js_destroy(lc); return JS_SUCCESS; } if(result_code == JS_ERROR) { goto serv_fail; } js_destroy(lookfor); js_destroy(origq); js_destroy(lc); return JS_SUCCESS; /* Work around C's lack of error handling and garbage collection with gotos */ serv_fail: js_destroy(lookfor); js_destroy(origq); js_destroy(lc); udperror(sock,raw,from,SERVER_FAIL,"serv_fail in proc_query"); return JS_ERROR; not_impl: js_destroy(lookfor); js_destroy(origq); js_destroy(lc); udperror(sock,raw,from,NOT_IMPLEMENTED,"not_impl in proc_query"); return JS_ERROR; }
int timestamp(int id, int sock, struct sockaddr *from, js_string *query) { unsigned char ip[4]; unsigned char length, val; int counter, critter, lenl, value; js_string *reply; q_header header; /* Sanity checks */ if(query->unit_size != 1) return JS_ERROR; if(query->unit_count >= query->max_count) return JS_ERROR; if(get_rtype(query) != RR_A && get_rtype(query) != RR_ANY) return 0; if(query->unit_count < 9) /* The minimum possible length for a ddip domain label */ return 0; if((reply = js_create(512,1)) == 0) return JS_ERROR; /* Build up the header for this reply */ if(id > 0 && id < 65535) header.id = id; else goto cleanup; header.qr = 1; /* Reply */ header.opcode = 0; /* Normal DNS */ header.aa = 0; /* DDIP to A translations are never authoritative */ header.tc = 0; /* A labels are too short to be truncated */ header.rd = 0; /* Recursion not desired */ header.ra = 0; /* Recursion not available */ header.z = 0; /* This must be 0 unless we are EDNS aware (we aren't) */ header.rcode = 0; /* Success! */ header.qdcount = 1; header.ancount = 1; header.nscount = 0; header.arcount = 0; /* Make a header of the reply */ if(make_hdr(&header,reply) == JS_ERROR) goto cleanup; /* Add the question they asked to the reply */ if(js_append(query,reply) == JS_ERROR) goto cleanup; /* Add the class (in) to the answer */ if(js_adduint16(reply,1) == JS_ERROR) goto cleanup; /* Make sure the answer is an A record type */ if(change_rtype(query,RR_A) == JS_ERROR) goto cleanup; /* We will now add out manufactured A reply */ if(js_append(query,reply) == JS_ERROR) goto cleanup; /* Append the class (in) to the answer */ if(js_adduint16(reply,1) == JS_ERROR) goto cleanup; /* Append a bogus TTL to the answer */ /*if(js_adduint32(reply,19770616) == JS_ERROR)*/ if(js_adduint32(reply,69) == JS_ERROR) goto cleanup; /* Add the rdlength to the answer */ if(js_adduint16(reply,4) == JS_ERROR) goto cleanup; /* Add the actual 4-byte reply to the answer */ time((time_t *)&ip); /* Endian dependent, but doesn't matter */ for(counter = 0; counter < 4; counter++) { if(js_addbyte(reply,ip[counter]) == JS_ERROR) goto cleanup; } /* Send the reply out */ sendto(sock,reply->string,reply->unit_count,0,from, sizeof(struct sockaddr)); /* And, we are done */ js_destroy(reply); return JS_SUCCESS; /* We use gotos to work around C's lack of error trapping */ cleanup: js_destroy(reply); return JS_ERROR; }
int udpsuccess(rr *where, int id, int sock, struct sockaddr_in *client, js_string *query, void **rotate_point, int show_cname_a, int rd_val, conn *ect, int force_authoritative,int ra_value) { js_string *most = 0; /* Most of the data */ js_string *ar = 0; /* Then the additional records */ uint16 first_rr_type; int in_ns = 0; int ns_delegation = 0; int length_save; int len_inet = sizeof(struct sockaddr); rr *ipwhere = 0; /* The following are used for round robin rotation */ rr *rotate_1st = 0, *rotate_2nd = 0, *rotate_last = 0; /* Counters in ensure that we don't give out more than the maximum number of A, AN (A), chain, or total records */ int a_count = 0, an_count = 0; fila *zap_point; /* These two variables are added to handle PTR records */ int seen_ptr_record = 0; rr *top = where; int is_auth = 0; int compress_error_happened = 0; q_header header; /* Initialize the total count */ total_count = 0; /* Initialize the js_string objects */ if((most = js_create(1024,1)) == 0) return JS_ERROR; #ifdef AUTHONLY if((ar = js_create(5000,1)) == 0) { js_destroy(most); return JS_ERROR; } #else if((ar = js_create(600,1)) == 0) { js_destroy(most); return JS_ERROR; } #endif /* Make the header a placeholder for now */ init_header(&header); header.id = id; if(make_hdr(&header,most) == JS_ERROR) goto giveerror; /* Sanity check */ if(where == 0) { goto giveerror; } if(where->query == 0) { goto giveerror; } if(js_has_sanity(where->query) == JS_ERROR) { goto giveerror; } if(where->data == 0) { goto giveerror; } if(js_has_sanity(where->data) == JS_ERROR) { goto giveerror; } if(js_has_sanity(query) == JS_ERROR) { goto giveerror; } first_rr_type = get_rtype(query); /* Somewhat hacky way to determine that this is a NS delegation */ ns_delegation = 0; if(first_rr_type != RR_NS && where->rr_type == RR_NS) { ns_delegation = 1; } /* With the cache, this may be a rtype of RR_ANY. We need to handle this special case */ /* We have to add this header here--authoritative depends on the authorative status of the first record we find */ if(force_authoritative != 1) { header.aa = where->authoritative; } else { header.aa = 1; } is_auth = where->authoritative; /* The data must be between 0 and 65535 bytes in length (16-bit unsigned value) */ if(where->data->unit_count < 0 || where->data->unit_count > 65535) { goto giveerror; } /* Append the question to the answer */ if(js_append(query,most) == JS_ERROR) { goto giveerror; } /* Append the class (in) to the answer */ if(js_adduint16(most,1) == JS_ERROR) { goto giveerror; } /* We will increment the ancount, nscount, an arcount, starting at 0 */ header.ancount = 0; header.nscount = 0; header.arcount = 0; /* Initialize some temporary pointers used for round robin rotation */ rotate_1st = where; rotate_2nd = where->next; /* We do not round robin if there is but a single record */ if(rotate_2nd != 0 && first_rr_type != RR_NS && rotate_2nd->rr_type == RR_NS) rotate_2nd = 0; /* OK, we now add the answers */ while(where != 0) { /* Increment the number of answers -or- ns records */ if(first_rr_type != RR_NS && where->rr_type == RR_NS && in_ns == 0) { /* Due to the data structure MaraDNS currently uses, the behavior is buggy if we round-robin rotate data when we allow more than one additional record to be create per answer/authoritative record. */ if(rotate_2nd != 0 && max_ar_chain == 1 && rotate_last != 0 && first_rr_type != RR_NS) { /* If it makes sense to do a round-robin rotation, do so. * Make rotate_1st, which was the first record, the last * record; make rotate_2nd, which was the second record, * the first record; and make rotate_last, which is the last * record in the chain, have its next record be the first * record */ rotate_1st->next = where; rotate_last->next = rotate_1st; *rotate_point = rotate_2nd; rotate_2nd = 0; /* Make sure we can not rotate again */ } in_ns = 1; a_count = 0; /* The NS chain is different than the AN chain of answers: If we only allow eight answers in a chain, we can still have 16 answers: 8 records in the answer section then 8 records in the authority section */ } if(a_count < max_chain && total_count < max_total && (in_ns == 0 || is_auth == 1 || ns_delegation == 1)) { a_count++; total_count++; if(!in_ns) { header.ancount++; } else { header.nscount++; } /* Append the name for this answer to the answer */ if(js_append(where->query,most) == JS_ERROR) goto giveerror; /* Append the class (in) to the answer */ if(js_adduint16(most,1) == JS_ERROR) goto giveerror; /* Append the ttl to the answer */ if(js_adduint32(most,determine_ttl(where->expire,where->ttl)) == JS_ERROR) goto giveerror; /* Add the rdlength to the answer */ if(js_adduint16(most,where->data->unit_count) == JS_ERROR) goto giveerror; /* Add the record itself to the answer */ if(js_append(where->data,most) == JS_ERROR) goto giveerror; /* If there is an IP, and this is *not* a CNAME record, append the IP of the answer to the AR section */ if(where->ip != 0 && where->rr_type != RR_CNAME) { /* Reset the number of an records we have seen */ an_count = 0; ipwhere = where->ip; while(ipwhere != 0 && ipwhere->rr_type != RR_NS) { /* We only show a given additional record once */ if(ipwhere->seen == 1) { /* If we have displayed this RR already */ /* Go to the next link in the linked list */ ipwhere = ipwhere->next; continue; } /* Stop showing records if we have exceeded our limit */ if(an_count >= max_ar_chain || total_count >= max_total) break; an_count++; total_count++; /* Increment the number of additional records */ header.arcount++; /* Append the name for this answer to the ip */ if(js_append(ipwhere->query,ar) == JS_ERROR) goto giveerror; /* Append the class (in) to the ip */ if(js_adduint16(ar,1) == JS_ERROR) goto giveerror; /* Append the TTL to the ip */ if(js_adduint32(ar, determine_ttl(ipwhere->expire,ipwhere->ttl)) == JS_ERROR) goto giveerror; /* Add the rdlength to the ip */ if(js_adduint16(ar,ipwhere->data->unit_count) == JS_ERROR) goto giveerror; /* Add the record itself to the ip */ if(js_append(ipwhere->data,ar) == JS_ERROR) goto giveerror; /* Mark that we have seen this record already */ if(seenlist_where < 250) { ipwhere->seen = 1; seenlist[seenlist_where] = ipwhere; seenlist_where++; } /* Go to the next link in the linked list */ ipwhere = ipwhere->next; } } #ifdef IPV6 if(where->ip6 != 0 && where->rr_type != RR_CNAME) { /* Reset the number of an records we have seen */ an_count = 0; ipwhere = where->ip6; while(ipwhere != 0 && ipwhere->rr_type != RR_NS) { /* We only show a given additional record once */ if(ipwhere->seen == 1) { /* If we have displayed this RR already */ /* Go to the next link in the linked list */ ipwhere = ipwhere->next; continue; } /* Stop showing records if we have exceeded our limit */ if(an_count >= max_ar_chain || total_count >= max_total) break; an_count++; total_count++; /* Increment the number of additional records */ header.arcount++; /* Append the name for this answer to the ip */ if(js_append(ipwhere->query,ar) == JS_ERROR) goto giveerror; /* Append the class (in) to the ip */ if(js_adduint16(ar,1) == JS_ERROR) goto giveerror; /* Append the TTL to the ip */ if(js_adduint32(ar, determine_ttl(ipwhere->expire,ipwhere->ttl)) == JS_ERROR) goto giveerror; /* Add the rdlength to the ip */ if(js_adduint16(ar,ipwhere->data->unit_count) == JS_ERROR) goto giveerror; /* Add the record itself to the ip */ if(js_append(ipwhere->data,ar) == JS_ERROR) goto giveerror; /* Mark that we have seen this record already */ if(seenlist_where < 250) { ipwhere->seen = 1; seenlist[seenlist_where] = ipwhere; seenlist_where++; } /* Go to the next link in the linked list */ ipwhere = ipwhere->next; } } #endif /* This code is only used by the recursive code; the * authoritative code now uses where->list to attach * a CNAME record to its corresponding rddata * If there is an IP, and this is a CNAME record, and * show_cname_a is set to one (argument to this function) * append the IP in question to the answer section */ if(where->ip != 0 && where->rr_type == RR_CNAME && show_cname_a == RR_A && where->list == 0) { /* Reset the number of an records we have seen */ an_count = 0; ipwhere = where->ip; while(ipwhere != 0 && ipwhere->rr_type != RR_NS) { /* We only show a given additional record once */ if(ipwhere->seen == 1) { /* If we have displayed this RR already */ /* Go to the next link in the linked list */ ipwhere = ipwhere->next; continue; } /* If the IP in question is 255.255.255.255, we do not show the data in question */ if(ipwhere->rr_type == RR_A && ipwhere->data->unit_count == 4 && *(ipwhere->data->string) == 0xff && *(ipwhere->data->string + 1) == 0xff && *(ipwhere->data->string + 2) == 0xff && *(ipwhere->data->string + 3) == 0xff) { ipwhere = ipwhere->next; continue; } /* Stop showing records if we have exceeded our limit */ if(an_count >= max_ar_chain || total_count >= max_total) break; an_count++; total_count++; /* Increment the number of answer records */ header.ancount++; /* Append the name for this answer to the ip */ if(js_append(ipwhere->query,most) == JS_ERROR) goto giveerror; /* Append the class (in) to the ip */ if(js_adduint16(most,1) == JS_ERROR) goto giveerror; /* Append the TTL to the ip */ if(js_adduint32(most, determine_ttl(ipwhere->expire,ipwhere->ttl)) == JS_ERROR) goto giveerror; /* Add the rdlength to the ip */ if(js_adduint16(most,ipwhere->data->unit_count) == JS_ERROR) goto giveerror; /* Add the record itself to the ip */ if(js_append(ipwhere->data,most) == JS_ERROR) goto giveerror; /* Mark that we have seen this record already */ if(seenlist_where < 250) { ipwhere->seen = 1; seenlist[seenlist_where] = ipwhere; seenlist_where++; } /* Go to the next link in the linked list */ ipwhere = ipwhere->next; } } /* Again, this code is only used by the recursive half. * The authoritative half now has a way of showing the record * that correspods to any RR type attached to a CNAME record. * * If there is an PTR, and this is a CNAME record, and * show_cname_a is set to one (argument to this function) * append the IP in question to the answer section */ else if(top->ptr != 0 && top->rr_type == RR_CNAME && show_cname_a == RR_PTR && seen_ptr_record == 0 && where->list == 0) { /* Mark that we have seen this record already */ seen_ptr_record = 1; /* Increment the total number of answers seen */ total_count++; /* Increment the number of answer records */ header.ancount++; /* Append the name for this answer to the ip */ if(js_append(top->data,most) == JS_ERROR) goto giveerror; /* Append the type for this query */ if(js_adduint16(most,RR_PTR) == JS_ERROR) goto giveerror; /* Append the class (in) to the ip */ if(js_adduint16(most,1) == JS_ERROR) goto giveerror; /* Append the TTL to the ip */ if(js_adduint32(most, determine_ttl(top->expire,top->ttl)) == JS_ERROR) goto giveerror; /* Add the rdlength to the ip */ if(js_adduint16(most,top->ptr->unit_count) == JS_ERROR) goto giveerror; /* Add the record itself to the ip */ if(js_append(top->ptr,most) == JS_ERROR) goto giveerror; } /* This code is currently only used by the authoritative half; * bascially, if we see a CNAME record we see if we have a list * which lists all record types for the host name the CNAME * is pointing to. We used this list to add, in the answer * section, the answer the person is looking for. */ else if(where->rr_type == RR_CNAME && where->list != 0) { struct rr_list *any_list = 0; uint16 this_rr_type = 0; int counter = 0; /* Start at the top of list of RRs */ any_list = where->list; this_rr_type = first_rr_type; /* The rtype they want */ /* We go down the list until we find the desired rr_type */ for(counter = 0; counter < 1000; counter++) { if(any_list->rr_type == this_rr_type) { break; } if(any_list->next == 0) { break; } any_list = any_list->next; } /* If we found the desired record type... */ if(any_list->rr_type == this_rr_type && any_list->data != 0) { rr *answer; int counter = 0; answer = any_list->data; while(answer != 0 && answer->rr_type == this_rr_type && counter < 100) { /* Then we add this information to the AN section of * the answer */ /* Increase the number of answers in the header */ header.ancount++; /* RFC 1035 section 3.2.1 header */ /* Name + Type */ if(js_append(answer->query,most) == JS_ERROR) goto giveerror; /* Class */ if(js_adduint16(most,1) == JS_ERROR) goto giveerror; /* TTL */ /* Since this currently only returns authoritative * data, answer->expire should always be zero and * determine_ttl is a redundant call. However, we'll * keep it that way just in case things change in * the future */ if(js_adduint32(most,determine_ttl(answer->expire, answer->ttl)) == JS_ERROR) goto giveerror; /* Rdlength */ if(answer->data == 0) goto giveerror; if(answer->data->unit_count < 0 || answer->data->unit_count > 65535) goto giveerror; if(js_adduint16(most,answer->data->unit_count) == JS_ERROR) goto giveerror; /* rdata */ if(js_append(answer->data,most) == JS_ERROR) goto giveerror; counter++; answer = answer->next; } } } } /* Go on to the next record in the linked list */ rotate_last = where; where = where->next; /* If it makes sense to do a round-robin rotation, do so */ if(where == 0 && rotate_2nd != 0 && max_ar_chain == 1 && first_rr_type != RR_NS) { /* For records in the cache, we need to make sure that the custodian properly points to the first record in the chain or we will leak memory */ if(rotate_1st->zap != 0) { zap_point = rotate_1st->zap; rotate_1st->zap = 0; rotate_2nd->zap = zap_point; zap_point->record = rotate_2nd; } rotate_1st->next = 0; rotate_last->next = rotate_1st; *rotate_point = rotate_2nd; rotate_2nd = 0; /* Make sure we can not rotate again */ } } /* Customize the header */ /* header.id already set */ header.qr = 1; header.opcode = 0; header.tc = 0; header.rd = rd_val; /* RDBUG udpsuccess */ header.ra = calc_ra_value(ra_value); header.z = 0; header.rcode = 0; /* No error */ header.qdcount = 1; /* OBhack: Tack on the header at the beginning without molesting the rest of the string */ length_save = most->unit_count; make_hdr(&header,most); most->unit_count = length_save; /* Add the ar records to the end */ if(js_append(ar,most) == JS_ERROR) { goto giveerror; } compress_error_happened = 0; if(compress_data(most,ar) == JS_ERROR) { compress_error_happened = 1; } /* Check to make sure the data fits in under 512 bytes (4096 bytes * if it's a long_packet_ipv4 address) truncate if not */ if(ar->unit_count > 512 || compress_error_happened == 1) { int x; #ifdef AUTHONLY /* If this is an ipv4 connection and we didn't get a compress error */ if(ect->type == 4 && compress_error_happened == 0) { struct sockaddr_in *dq; uint32 ip_test; dq = (struct sockaddr_in *)(ect->d); ip_test = ntohl(dq->sin_addr.s_addr); /* See if we are allowed to send a long packet up to * 4096 bytes to this ip address */ if(check_ipv4_acl(ip_test,long_packet) == 1) { if(ar->unit_count < 4096) { goto long_packet_ok; } } } #endif for(x = 0; x < 20; x++) { compress_error_happened = 0; /* OK, try to squeeze the packet in by removing records */ if(squeeze_to_fit(most) == 0) { goto giveerror; } if(most->unit_count > 12) { if(compress_data(most,ar) == JS_ERROR) { compress_error_happened = 1; } if(ar->unit_count <= 512 && compress_error_happened == 0) { break; } } else if(most->unit_count == 12) { if(js_copy(most,ar) == JS_ERROR) { goto giveerror; } } else { goto giveerror; } } } #ifdef AUTHONLY long_packet_ok: #endif if(compress_error_happened == 1) { goto giveerror; } /* Success! Put out the good data */ if(ect == 0) { sendto(sock,ar->string,ar->unit_count,0, (struct sockaddr *)client,len_inet); } else { mara_send(ect,sock,ar); } js_destroy(most); js_destroy(ar); /* Clean up the seenlist_where list */ while(seenlist_where > 0) { seenlist_where--; if(seenlist[seenlist_where] != 0) (seenlist[seenlist_where])->seen = 0; } return JS_SUCCESS; /* We use gotos to make up for C's lack of error trapping */ giveerror: js_destroy(ar); udperror(sock,most,client,0,SERVER_FAIL,"giveerror in udpsuccess",2, rd_val,ect,1); js_destroy(most); /* Clean up the seenlist_where list */ while(seenlist_where > 0) { seenlist_where--; if(seenlist[seenlist_where] != 0) (seenlist[seenlist_where])->seen = 0; } return JS_ERROR; }