static void xfrd_notify_send_udp(struct notify_zone_t* zone, buffer_type* packet) { int fd; if(zone->notify_send_enable) { notify_send_disable(zone); } /* Set timeout for next reply */ zone->notify_timeout.tv_sec = XFRD_NOTIFY_RETRY_TIMOUT; /* send NOTIFY to secondary. */ xfrd_setup_packet(packet, TYPE_SOA, CLASS_IN, zone->apex, qid_generate()); zone->notify_query_id = ID(packet); OPCODE_SET(packet, OPCODE_NOTIFY); AA_SET(packet); if(zone->current_soa->serial != 0) { /* add current SOA to answer section */ ANCOUNT_SET(packet, 1); xfrd_write_soa_buffer(packet, zone->apex, zone->current_soa); } if(zone->notify_current->key_options) { xfrd_tsig_sign_request(packet, &zone->notify_tsig, zone->notify_current); } buffer_flip(packet); fd = xfrd_send_udp(zone->notify_current, packet, zone->options->pattern->outgoing_interface); if(fd == -1) { log_msg(LOG_ERR, "xfrd: zone %s: could not send notify #%d to %s", zone->apex_str, zone->notify_retry, zone->notify_current->ip_address_spec); event_set(&zone->notify_send_handler, -1, EV_TIMEOUT, xfrd_handle_notify_send, zone); if(event_base_set(xfrd->event_base, &zone->notify_send_handler) != 0) log_msg(LOG_ERR, "notify_send: event_base_set failed"); if(evtimer_add(&zone->notify_send_handler, &zone->notify_timeout) != 0) log_msg(LOG_ERR, "notify_send: evtimer_add failed"); zone->notify_send_enable = 1; return; } event_set(&zone->notify_send_handler, fd, EV_READ | EV_TIMEOUT, xfrd_handle_notify_send, zone); if(event_base_set(xfrd->event_base, &zone->notify_send_handler) != 0) log_msg(LOG_ERR, "notify_send: event_base_set failed"); if(event_add(&zone->notify_send_handler, &zone->notify_timeout) != 0) log_msg(LOG_ERR, "notify_send: evtimer_add failed"); zone->notify_send_enable = 1; DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: zone %s: sent notify #%d to %s", zone->apex_str, zone->notify_retry, zone->notify_current->ip_address_spec)); }
/** * Send notify. * */ void notify_send(notify_type* notify) { xfrhandler_type* xfrhandler = NULL; zone_type* zone = NULL; ods_log_assert(notify); ods_log_assert(notify->secondary); ods_log_assert(notify->secondary->address); xfrhandler = (xfrhandler_type*) notify->xfrhandler; zone = (zone_type*) notify->zone; ods_log_assert(xfrhandler); ods_log_assert(zone); ods_log_assert(zone->name); if (notify->handler.fd != -1) { close(notify->handler.fd); } notify->handler.fd = -1; notify->timeout.tv_sec = notify_time(notify) + NOTIFY_RETRY_TIMEOUT; buffer_pkt_notify(xfrhandler->packet, zone->apex, LDNS_RR_CLASS_IN); notify->query_id = buffer_pkt_id(xfrhandler->packet); buffer_pkt_set_aa(xfrhandler->packet); /* add current SOA to answer section */ if (notify->soa) { if (buffer_write_rr(xfrhandler->packet, notify->soa)) { buffer_pkt_set_ancount(xfrhandler->packet, 1); } } if (notify->secondary->tsig) { notify_tsig_sign(notify, xfrhandler->packet); } buffer_flip(xfrhandler->packet); notify->handler.fd = notify_send_udp(notify, xfrhandler->packet); if (notify->handler.fd == -1) { ods_log_error("[%s] unable to send notify retry %u for zone %s to " "%s: notify_send_udp() failed", notify_str, notify->retry, zone->name, notify->secondary->address); return; } ods_log_verbose("[%s] notify retry %u for zone %s sent to %s", notify_str, notify->retry, zone->name, notify->secondary->address); return; }
static int xfrd_send_ixfr_request_udp(xfrd_zone_t* zone) { int fd; /* make sure we have a master to query the ixfr request to */ assert(zone->master); if(zone->tcp_conn != -1) { /* tcp is using the zone_handler.fd */ log_msg(LOG_ERR, "xfrd: %s tried to send udp whilst tcp engaged", zone->apex_str); return -1; } xfrd_setup_packet(xfrd->packet, TYPE_IXFR, CLASS_IN, zone->apex); zone->query_id = ID(xfrd->packet); zone->msg_seq_nr = 0; zone->msg_rr_count = 0; DEBUG(DEBUG_XFRD,1, (LOG_INFO, "sent query with ID %d", zone->query_id)); NSCOUNT_SET(xfrd->packet, 1); xfrd_write_soa_buffer(xfrd->packet, zone->apex, &zone->soa_disk); /* if we have tsig keys, sign the ixfr query */ if(zone->master->key_options && zone->master->key_options->tsig_key) { xfrd_tsig_sign_request(xfrd->packet, &zone->tsig, zone->master); } buffer_flip(xfrd->packet); xfrd_set_timer(zone, xfrd_time() + XFRD_UDP_TIMEOUT); if((fd = xfrd_send_udp(zone->master, xfrd->packet, zone->zone_options->outgoing_interface)) == -1) return -1; DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd sent udp request for ixfr=%u for zone %s to %s", ntohl(zone->soa_disk.serial), zone->apex_str, zone->master->ip_address_spec)); return fd; }
enum xfrd_packet_result xfrd_handle_received_xfr_packet(xfrd_zone_t* zone, buffer_type* packet) { xfrd_soa_t soa; enum xfrd_packet_result res; /* parse and check the packet - see if it ends the xfr */ switch((res=xfrd_parse_received_xfr_packet(zone, packet, &soa))) { case xfrd_packet_more: case xfrd_packet_transfer: /* continue with commit */ break; case xfrd_packet_newlease: return xfrd_packet_newlease; case xfrd_packet_tcp: return xfrd_packet_tcp; case xfrd_packet_notimpl: case xfrd_packet_bad: default: { /* rollback */ if(zone->msg_seq_nr > 0) { /* do not process xfr - if only one part simply ignore it. */ /* rollback previous parts of commit */ buffer_clear(packet); buffer_printf(packet, "xfrd: zone %s xfr " "rollback serial %u at " "time %u from %s of %u " "parts", zone->apex_str, (int)zone->msg_new_serial, (int)xfrd_time(), zone->master->ip_address_spec, zone->msg_seq_nr); buffer_flip(packet); diff_write_commit(zone->apex_str, zone->msg_old_serial, zone->msg_new_serial, zone->query_id, zone->msg_seq_nr, 0, (char*)buffer_begin(packet), xfrd->nsd->options); DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: zone %s " "xfr reverted " "\"%s\"", zone->apex_str, (char*)buffer_begin(packet))); } if (res == xfrd_packet_notimpl) return res; else return xfrd_packet_bad; } } /* dump reply on disk to diff file */ diff_write_packet(zone->apex_str, zone->msg_new_serial, zone->query_id, zone->msg_seq_nr, buffer_begin(packet), buffer_limit(packet), xfrd->nsd->options); VERBOSITY(1, (LOG_INFO, "xfrd: zone %s written received XFR from %s with serial %u to " "disk", zone->apex_str, zone->master->ip_address_spec, (int)zone->msg_new_serial)); zone->msg_seq_nr++; if(res == xfrd_packet_more) { /* wait for more */ return xfrd_packet_more; } /* done. we are completely sure of this */ buffer_clear(packet); buffer_printf(packet, "xfrd: zone %s received update to serial %u at " "time %u from %s in %u parts", zone->apex_str, (int)zone->msg_new_serial, (int)xfrd_time(), zone->master->ip_address_spec, zone->msg_seq_nr); if(zone->master->key_options) { buffer_printf(packet, " TSIG verified with key %s", zone->master->key_options->name); } buffer_flip(packet); diff_write_commit(zone->apex_str, zone->msg_old_serial, zone->msg_new_serial, zone->query_id, zone->msg_seq_nr, 1, (char*)buffer_begin(packet), xfrd->nsd->options); VERBOSITY(1, (LOG_INFO, "xfrd: zone %s committed \"%s\"", zone->apex_str, (char*)buffer_begin(packet))); /* update the disk serial no. */ zone->soa_disk_acquired = xfrd_time(); zone->soa_disk = soa; if(zone->soa_notified_acquired && ( zone->soa_notified.serial == 0 || compare_serial(htonl(zone->soa_disk.serial), htonl(zone->soa_notified.serial)) >= 0)) { zone->soa_notified_acquired = 0; } if(!zone->soa_notified_acquired) { /* do not set expired zone to ok: * it would cause nsd to start answering * bad data, since the zone is not loaded yet. * if nsd does not reload < retry time, more * queries (for even newer versions) are made. * For expired zone after reload it is set ok (SOAINFO ipc). */ if(zone->state != xfrd_zone_expired) xfrd_set_zone_state(zone, xfrd_zone_ok); DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: zone %s is waiting for reload", zone->apex_str)); zone->round_num = -1; /* next try start anew */ xfrd_set_timer_refresh(zone); xfrd_set_reload_timeout(); return xfrd_packet_transfer; } else { /* try to get an even newer serial */ /* pretend it was bad to continue queries */ xfrd_set_reload_timeout(); return xfrd_packet_bad; } }
int print_rr(FILE *out, struct state_pretty_rr *state, rr_type *record) { region_type *region = region_create(xalloc, free); buffer_type *output = buffer_create(region, MAX_RDLENGTH); rrtype_descriptor_type *descriptor = rrtype_descriptor_by_type(record->type); int result; const dname_type *owner = domain_dname(record->owner); const dname_type *owner_origin = dname_origin(region, owner); int owner_changed = (!state->previous_owner || dname_compare(state->previous_owner, owner) != 0); if (owner_changed) { int origin_changed = (!state->previous_owner_origin || dname_compare( state->previous_owner_origin, owner_origin) != 0); if (origin_changed) { buffer_printf( output, "$ORIGIN %s\n", dname_to_string(owner_origin, NULL)); } set_previous_owner(state, owner); buffer_printf(output, "%s", dname_to_string(owner, state->previous_owner_origin)); } buffer_printf(output, "\t%lu\t%s\t%s", (unsigned long) record->ttl, rrclass_to_string(record->klass), rrtype_to_string(record->type)); result = print_rdata(output, descriptor, record); if (!result) { /* * Some RDATA failed to print, so print the record's * RDATA in unknown format. */ result = rdata_atoms_to_unknown_string(output, descriptor, record->rdata_count, record->rdatas); } if (result) { buffer_printf(output, "\n"); buffer_flip(output); (void)write_data(out, buffer_current(output), buffer_remaining(output)); /* fflush(out); */ } region_destroy(region); return result; }
static int logg_internal(const enum loglevel level, const char *file, const char *func, const unsigned int line, int log_errno, const char *fmt, va_list args ) { struct big_buff *logg_buff; int ret_val, old_errno, retry_cnt; old_errno = errno; /* get our tls-print buf */ if(!(logg_buff = logg_get_buf())) { /* * hmmm, something went wrong, lets see, if we can get the message to * the user by other means */ return do_vlogging(level, fmt, args); } /* add time, if wanted, to buffer */ if(server.settings.logging.add_date_time) logg_buff->pos += add_time_to_buffer(buffer_start(*logg_buff), buffer_remaining(*logg_buff)); /* put out the "extra" stuff, if there */ if(file) { retry_cnt = 0; prefetch(strlpcpy); prefetch(file); prefetch(func); /* * calling snprintf for 2 * strcpy + an itoa is "nice" * but goes round the full stdio bloat: * snprintf->vsnprintf->vfprintf-> myriads of funcs to print */ do { char *sptr, *stmp, *rstart; size_t remaining; stmp = sptr = buffer_start(*logg_buff); remaining = buffer_remaining(*logg_buff); rstart = strlpcpy(sptr, file, remaining); remaining -= rstart - sptr; if(unlikely(remaining < 7)) goto realloc; sptr = rstart; *sptr++ = ':'; remaining--; rstart = strlpcpy(sptr, func, remaining); remaining -= rstart - sptr; if(unlikely(remaining < 18)) /* make sure we have enough space */ goto realloc; sptr = rstart; *sptr++ = '('; *sptr++ = ')'; *sptr++ = '@'; remaining -= 3; rstart = put_dec_trunc(sptr, line); /* 99,999 lines should be... */ strreverse(sptr, rstart - 1); remaining -= rstart - sptr; if(unlikely(remaining < 2)) goto realloc; sptr = rstart; *sptr++ = ':'; *sptr++ = ' '; logg_buff->pos += sptr - stmp; break; realloc: /* now we are in a slow path, no need to hurry */ { struct big_buff *tmp_buff; size_t len = strlen(file) + strlen(func) + 6 + 30 + strlen(fmt) * 3; len = ROUND_ALIGN(len * 2, 2048) + logg_buff->capacity; tmp_buff = realloc(logg_buff, sizeof(*logg_buff) + len); if(tmp_buff) { logg_buff = tmp_buff; logg_buff->limit = logg_buff->capacity = len; } else break; retry_cnt++; } } while(retry_cnt < 4); } ret_val = 0; retry_cnt = 0; /* format the message in tls */ do { size_t len = logg_buff->capacity; va_list tmp_valist; if(ret_val < 0) { len *= 2; if(++retry_cnt > 4) { ret_val = 0; break; } } else if((size_t)ret_val > buffer_remaining(*logg_buff)) len = ROUND_ALIGN((size_t)ret_val * 2, 1024); /* align to a k */ if(unlikely(len != logg_buff->capacity)) { struct big_buff *tmp_buf = realloc(logg_buff, sizeof(*logg_buff) + len); if(tmp_buf) { logg_buff = tmp_buf; logg_buff->limit = logg_buff->capacity = len; } else { ret_val = buffer_remaining(*logg_buff); break; } } /* put msg printed out in buffer */ va_copy(tmp_valist, args); ret_val = my_vsnprintf(buffer_start(*logg_buff), buffer_remaining(*logg_buff), fmt, tmp_valist); va_end(tmp_valist); /* error? repeat */ } while(unlikely(ret_val < 0 || (size_t)ret_val > buffer_remaining(*logg_buff))); logg_buff->pos += (size_t)ret_val; /* add errno string if wanted */ if(log_errno) { if(buffer_remaining(*logg_buff) < STRERROR_R_SIZE + 4) { size_t len = logg_buff->capacity * 2; struct big_buff *tmp_buff = realloc(logg_buff, sizeof(*logg_buff) + len); if(!tmp_buff) goto no_errno; logg_buff = tmp_buff; logg_buff->limit = logg_buff->capacity += len; } *buffer_start(*logg_buff) = ':'; logg_buff->pos++; *buffer_start(*logg_buff) = ' '; logg_buff->pos++; { #if defined STRERROR_R_CHAR_P || defined HAVE_MTSAFE_STRERROR || WIN32 || !(defined HAVE_STRERROR_R || HAVE_DECL_STRERROR_R-0 > 0) size_t err_str_len; # ifdef WIN32 const char *s = buffer_start(*logg_buff); if(!(err_str_len = FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS, /* flags */ 0, /* pointer to other source */ old_errno, /* msg id */ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), /* language */ buffer_start(*logg_buff), /* buffer */ buffer_remaining(*logg_buff)-1, /* size */ 0 /* va_args */ ))) { s = "Unknown system error"; err_str_len = strlen(s) < buffer_remaining(*logg_buff)-2 ? strlen(s) : buffer_remaining(*logg_buff)-2; } # else # ifdef STRERROR_R_CHAR_P /* * the f***ing GNU-Version of strerror_r wich returns * a char * to the buffer.... * This sucks especially in conjunction with strnlen, * wich needs a #define __GNU_SOURCE, but conflicts * with this... */ const char *s = strerror_r(old_errno, buffer_start(*logg_buff), buffer_remaining(*logg_buff)-2); # else /* * Ol Solaris seems to have a static msgtable, so * strerror is threadsafe and we don't have a * _r version */ /* * we also simply fall into here if strerror is not thread * safe, but we have nothing else. * Since what should we do in this case... _sys_errlist * is a bsd extentions. */ const char *s = strerror(old_errno); # endif if(s) err_str_len = strnlen(s, buffer_remaining(*logg_buff)-2); else { s = "Unknown system error"; err_str_len = strlen(s) < (buffer_remaining(*logg_buff)-2) ? strlen(s) : buffer_remaining(*logg_buff)-2; } # endif if(s != buffer_start(*logg_buff)) my_memcpy(buffer_start(*logg_buff), s, err_str_len); logg_buff->pos += err_str_len; #else if(!strerror_r(old_errno, buffer_start(*logg_buff), buffer_remaining(*logg_buff))) // if(!strerror_s(buffer_start(*logg_buff), buffer_remaining(*logg_buff), old_errno)) logg_buff->pos += strnlen(buffer_start(*logg_buff), buffer_remaining(*logg_buff)); else { size_t err_l; const char *bs; if(EINVAL == errno) { err_l = str_size("Unknown errno value!"); bs = "Unknown errno value!"; } else if(ERANGE == errno) { err_l = str_size("errno msg to long for buffer!"); bs = "errno msg to long for buffer!"; } else { err_l = str_size("failure while retrieving errno msg!"); bs = "failure while retrieving errno msg!"; } err_l = (buffer_remaining(*logg_buff)-2) >= err_l ? err_l : (buffer_remaining(*logg_buff)-2); my_memcpy(buffer_start(*logg_buff), bs, err_l); logg_buff->pos += err_l; } #endif } *buffer_start(*logg_buff) = '\n'; logg_buff->pos++; *buffer_start(*logg_buff) = '\0'; } no_errno: /* output that stuff */ buffer_flip(*logg_buff); ret_val = do_logging(level, buffer_start(*logg_buff), buffer_remaining(*logg_buff)); logg_ret_buf(logg_buff); return ret_val; }
static void handle_tcp_reading(netio_type *netio, netio_handler_type *handler, netio_event_types_type event_types) { struct tcp_handler_data *data = (struct tcp_handler_data *) handler->user_data; ssize_t received; if (event_types & NETIO_EVENT_TIMEOUT) { /* Connection timed out. */ cleanup_tcp_handler(netio, handler); return; } if (data->nsd->tcp_query_count > 0 && data->query_count >= data->nsd->tcp_query_count) { /* No more queries allowed on this tcp connection. */ cleanup_tcp_handler(netio, handler); return; } assert(event_types & NETIO_EVENT_READ); if (data->bytes_transmitted == 0) { query_reset(data->query, TCP_MAX_MESSAGE_LEN, 1); } /* * Check if we received the leading packet length bytes yet. */ if (data->bytes_transmitted < sizeof(uint16_t)) { received = read(handler->fd, (char *) &data->query->tcplen + data->bytes_transmitted, sizeof(uint16_t) - data->bytes_transmitted); if (received == -1) { if (errno == EAGAIN || errno == EINTR) { /* * Read would block, wait until more * data is available. */ return; } else { #ifdef ECONNRESET if (verbosity >= 2 || errno != ECONNRESET) #endif /* ECONNRESET */ log_msg(LOG_ERR, "failed reading from tcp: %s", strerror(errno)); cleanup_tcp_handler(netio, handler); return; } } else if (received == 0) { /* EOF */ cleanup_tcp_handler(netio, handler); return; } data->bytes_transmitted += received; if (data->bytes_transmitted < sizeof(uint16_t)) { /* * Not done with the tcplen yet, wait for more * data to become available. */ return; } assert(data->bytes_transmitted == sizeof(uint16_t)); data->query->tcplen = ntohs(data->query->tcplen); /* * Minimum query size is: * * Size of the header (12) * + Root domain name (1) * + Query class (2) * + Query type (2) */ if (data->query->tcplen < QHEADERSZ + 1 + sizeof(uint16_t) + sizeof(uint16_t)) { VERBOSITY(2, (LOG_WARNING, "packet too small, dropping tcp connection")); cleanup_tcp_handler(netio, handler); return; } if (data->query->tcplen > data->query->maxlen) { VERBOSITY(2, (LOG_WARNING, "insufficient tcp buffer, dropping connection")); cleanup_tcp_handler(netio, handler); return; } buffer_set_limit(data->query->packet, data->query->tcplen); } assert(buffer_remaining(data->query->packet) > 0); /* Read the (remaining) query data. */ received = read(handler->fd, buffer_current(data->query->packet), buffer_remaining(data->query->packet)); if (received == -1) { if (errno == EAGAIN || errno == EINTR) { /* * Read would block, wait until more data is * available. */ return; } else { #ifdef ECONNRESET if (verbosity >= 2 || errno != ECONNRESET) #endif /* ECONNRESET */ log_msg(LOG_ERR, "failed reading from tcp: %s", strerror(errno)); cleanup_tcp_handler(netio, handler); return; } } else if (received == 0) { /* EOF */ cleanup_tcp_handler(netio, handler); return; } data->bytes_transmitted += received; buffer_skip(data->query->packet, received); if (buffer_remaining(data->query->packet) > 0) { /* * Message not yet complete, wait for more data to * become available. */ return; } assert(buffer_position(data->query->packet) == data->query->tcplen); /* Account... */ #ifdef BIND8_STATS # ifndef INET6 STATUP(data->nsd, ctcp); # else if (data->query->addr.ss_family == AF_INET) { STATUP(data->nsd, ctcp); } else if (data->query->addr.ss_family == AF_INET6) { STATUP(data->nsd, ctcp6); } # endif #endif /* BIND8_STATS */ /* We have a complete query, process it. */ /* tcp-query-count: handle query counter ++ */ data->query_count++; buffer_flip(data->query->packet); data->query_state = server_process_query(data->nsd, data->query); if (data->query_state == QUERY_DISCARDED) { /* Drop the packet and the entire connection... */ STATUP(data->nsd, dropped); #if defined(BIND8_STATS) && defined(USE_ZONE_STATS) if (data->query->zone) { ZTATUP(data->query->zone, dropped); } #endif cleanup_tcp_handler(netio, handler); return; } #ifdef BIND8_STATS if (RCODE(data->query->packet) == RCODE_OK && !AA(data->query->packet)) { STATUP(data->nsd, nona); ZTATUP(data->query->zone, nona); } # ifdef USE_ZONE_STATS # ifndef INET6 ZTATUP(data->query->zone, ctcp); # else if (data->query->addr.ss_family == AF_INET) { ZTATUP(data->query->zone, ctcp); } else if (data->query->addr.ss_family == AF_INET6) { ZTATUP(data->query->zone, ctcp6); } # endif # endif /* USE_ZONE_STATS */ #endif /* BIND8_STATS */ query_add_optional(data->query, data->nsd); /* Switch to the tcp write handler. */ buffer_flip(data->query->packet); data->query->tcplen = buffer_remaining(data->query->packet); data->bytes_transmitted = 0; handler->timeout->tv_sec = data->nsd->tcp_timeout; handler->timeout->tv_nsec = 0L; timespec_add(handler->timeout, netio_current_time(netio)); handler->event_types = NETIO_EVENT_WRITE | NETIO_EVENT_TIMEOUT; handler->event_handler = handle_tcp_writing; }
static void handle_udp(netio_type *ATTR_UNUSED(netio), netio_handler_type *handler, netio_event_types_type event_types) { struct udp_handler_data *data = (struct udp_handler_data *) handler->user_data; int received, sent; struct query *q = data->query; if (!(event_types & NETIO_EVENT_READ)) { return; } /* Account... */ #ifdef BIND8_STATS if (data->socket->addr->ai_family == AF_INET) { STATUP(data->nsd, qudp); } else if (data->socket->addr->ai_family == AF_INET6) { STATUP(data->nsd, qudp6); } #endif /* Initialize the query... */ query_reset(q, UDP_MAX_MESSAGE_LEN, 0); received = recvfrom(handler->fd, buffer_begin(q->packet), buffer_remaining(q->packet), 0, (struct sockaddr *)&q->addr, &q->addrlen); if (received == -1) { if (errno != EAGAIN && errno != EINTR) { log_msg(LOG_ERR, "recvfrom failed: %s", strerror(errno)); STATUP(data->nsd, rxerr); /* No zone statup */ } } else { buffer_skip(q->packet, received); buffer_flip(q->packet); /* Process and answer the query... */ if (server_process_query(data->nsd, q) != QUERY_DISCARDED) { #ifdef BIND8_STATS if (RCODE(q->packet) == RCODE_OK && !AA(q->packet)) { STATUP(data->nsd, nona); ZTATUP(q->zone, nona); } # ifdef USE_ZONE_STATS if (data->socket->addr->ai_family == AF_INET) { ZTATUP(q->zone, qudp); } else if (data->socket->addr->ai_family == AF_INET6) { ZTATUP(q->zone, qudp6); } # endif #endif /* Add EDNS0 and TSIG info if necessary. */ query_add_optional(q, data->nsd); buffer_flip(q->packet); sent = sendto(handler->fd, buffer_begin(q->packet), buffer_remaining(q->packet), 0, (struct sockaddr *) &q->addr, q->addrlen); if (sent == -1) { log_msg(LOG_ERR, "sendto failed: %s", strerror(errno)); STATUP(data->nsd, txerr); ZTATUP(q->zone, txerr); } else if ((size_t) sent != buffer_remaining(q->packet)) { log_msg(LOG_ERR, "sent %d in place of %d bytes", sent, (int) buffer_remaining(q->packet)); #ifdef BIND8_STATS } else { /* Account the rcode & TC... */ STATUP2(data->nsd, rcode, RCODE(q->packet)); ZTATUP2(q->zone, rcode, RCODE(q->packet)); if (TC(q->packet)) { STATUP(data->nsd, truncated); ZTATUP(q->zone, truncated); } #endif /* BIND8_STATS */ } #ifdef BIND8_STATS } else { STATUP(data->nsd, dropped); # ifdef USE_ZONE_STATS if (q->zone) { ZTATUP(q->zone, dropped); } # endif #endif } } }
static void handle_tcp_writing(netio_type *netio, netio_handler_type *handler, netio_event_types_type event_types) { struct tcp_handler_data *data = (struct tcp_handler_data *) handler->user_data; ssize_t sent; struct query *q = data->query; if (event_types & NETIO_EVENT_TIMEOUT) { /* Connection timed out. */ cleanup_tcp_handler(netio, handler); return; } assert(event_types & NETIO_EVENT_WRITE); if (data->bytes_transmitted < sizeof(q->tcplen)) { /* Writing the response packet length. */ uint16_t n_tcplen = htons(q->tcplen); sent = write(handler->fd, (const char *) &n_tcplen + data->bytes_transmitted, sizeof(n_tcplen) - data->bytes_transmitted); if (sent == -1) { if (errno == EAGAIN || errno == EINTR) { /* * Write would block, wait until * socket becomes writable again. */ return; } else { #ifdef ECONNRESET if(verbosity >= 2 || errno != ECONNRESET) #endif /* ECONNRESET */ #ifdef EPIPE if(verbosity >= 2 || errno != EPIPE) #endif /* EPIPE 'broken pipe' */ log_msg(LOG_ERR, "failed writing to tcp: %s", strerror(errno)); cleanup_tcp_handler(netio, handler); return; } } data->bytes_transmitted += sent; if (data->bytes_transmitted < sizeof(q->tcplen)) { /* * Writing not complete, wait until socket * becomes writable again. */ return; } assert(data->bytes_transmitted == sizeof(q->tcplen)); } assert(data->bytes_transmitted < q->tcplen + sizeof(q->tcplen)); sent = write(handler->fd, buffer_current(q->packet), buffer_remaining(q->packet)); if (sent == -1) { if (errno == EAGAIN || errno == EINTR) { /* * Write would block, wait until * socket becomes writable again. */ return; } else { #ifdef ECONNRESET if(verbosity >= 2 || errno != ECONNRESET) #endif /* ECONNRESET */ #ifdef EPIPE if(verbosity >= 2 || errno != EPIPE) #endif /* EPIPE 'broken pipe' */ log_msg(LOG_ERR, "failed writing to tcp: %s", strerror(errno)); cleanup_tcp_handler(netio, handler); return; } } buffer_skip(q->packet, sent); data->bytes_transmitted += sent; if (data->bytes_transmitted < q->tcplen + sizeof(q->tcplen)) { /* * Still more data to write when socket becomes * writable again. */ return; } assert(data->bytes_transmitted == q->tcplen + sizeof(q->tcplen)); if (data->query_state == QUERY_IN_AXFR) { /* Continue processing AXFR and writing back results. */ buffer_clear(q->packet); data->query_state = query_axfr(data->nsd, q); if (data->query_state != QUERY_PROCESSED) { query_add_optional(data->query, data->nsd); /* Reset data. */ buffer_flip(q->packet); q->tcplen = buffer_remaining(q->packet); data->bytes_transmitted = 0; /* Reset timeout. */ handler->timeout->tv_sec = data->nsd->tcp_timeout; handler->timeout->tv_nsec = 0; timespec_add(handler->timeout, netio_current_time(netio)); /* * Write data if/when the socket is writable * again. */ return; } } /* * Done sending, wait for the next request to arrive on the * TCP socket by installing the TCP read handler. */ if (data->nsd->tcp_query_count > 0 && data->query_count >= data->nsd->tcp_query_count) { (void) shutdown(handler->fd, SHUT_WR); } data->bytes_transmitted = 0; handler->timeout->tv_sec = data->nsd->tcp_timeout; handler->timeout->tv_nsec = 0; timespec_add(handler->timeout, netio_current_time(netio)); handler->event_types = NETIO_EVENT_READ | NETIO_EVENT_TIMEOUT; handler->event_handler = handle_tcp_reading; }
bool do_write(struct epoll_event *p_entry, some_fd epoll_fd) { g2_connection_t *w_entry = (g2_connection_t *)p_entry->data.ptr; bool ret_val = true, more_write; ssize_t result = 0; #ifdef DEBUG_DEVEL if(!w_entry->send) { logg_posd(LOGF_DEBUG, "%s Ip: %p#I\tFDNum: %i\n", "no send buffer!", &w_entry->remote_host, w_entry->com_socket); w_entry->flags.dismissed = true; ret_val = false; } #endif buffer_flip(*w_entry->send); do { set_s_errno(0); result = my_epoll_send(epoll_fd, w_entry->com_socket, w_entry->send->data, w_entry->send->limit, 0); } while(-1 == result && EINTR == s_errno); switch(result) { default: w_entry->send->pos += result; w_entry->flags.has_written = true; w_entry->last_send = local_time_now; if(buffer_remaining(*w_entry->send)) break; shortlock_lock(&w_entry->pts_lock); if(list_empty(&w_entry->packets_to_send)) { w_entry->poll_interrests &= ~((uint32_t)EPOLLOUT); more_write = true; } else more_write = false; if(more_write) { if(!(w_entry->poll_interrests & EPOLLONESHOT)) { struct epoll_event t_entry; t_entry.data.u64 = p_entry->data.u64; t_entry.events = w_entry->poll_interrests; shortlock_unlock(&w_entry->pts_lock); if(0 > my_epoll_ctl(epoll_fd, EPOLL_CTL_MOD, w_entry->com_socket, &t_entry)) { logg_serrno(LOGF_DEBUG, "changing sockets Epoll-interrests"); w_entry->flags.dismissed = true; ret_val = false; } } else { shortlock_unlock(&w_entry->pts_lock); if(w_entry->flags.dismissed) { logg_posd(LOGF_DEVEL_OLD, "%s\tIP: %p#I\tFDNum: %i\n", "Dismissed!", &w_entry->remote_host, w_entry->com_socket); ret_val = false; } } } else shortlock_unlock(&w_entry->pts_lock); break; case 0: if(buffer_remaining(*w_entry->send)) { if(EAGAIN != s_errno) { logg_posd(LOGF_DEVEL_OLD, "%s Ip: %p#I\tFDNum: %i\n", "Dismissed!", &w_entry->remote_host, w_entry->com_socket); w_entry->flags.dismissed = true; ret_val = false; } else logg_devel("not ready to write\n"); } else { shortlock_lock(&w_entry->pts_lock); w_entry->poll_interrests &= ~((uint32_t)EPOLLOUT); if(!(w_entry->poll_interrests & EPOLLONESHOT)) { struct epoll_event t_entry; t_entry.data.u64 = p_entry->data.u64; t_entry.events = w_entry->poll_interrests; shortlock_unlock(&w_entry->pts_lock); if(0 > my_epoll_ctl(epoll_fd, EPOLL_CTL_MOD, w_entry->com_socket, &t_entry)) { logg_serrno(LOGF_DEBUG, "changing sockets Epoll-interrests"); w_entry->flags.dismissed = true; ret_val = false; } } else { shortlock_unlock(&w_entry->pts_lock); if(w_entry->flags.dismissed) { logg_posd(LOGF_DEVEL_OLD, "%s ERRNO=%i Ip: %p#I\tFDNum: %i\n", "EOF reached!", s_errno, &w_entry->remote_host, w_entry->com_socket); ret_val = false; } } } break; case -1: if(!(EAGAIN == errno || EWOULDBLOCK == s_errno)) { logg_serrno(LOGF_DEBUG, "write"); ret_val = false; } break; } logg_develd_old("ret_val: %i\tpos: %u\tlim: %u\n", ret_val, w_entry->send->pos, w_entry->send->limit); buffer_compact(*w_entry->send); logg_develd_old("ret_val: %i\tpos: %u\tlim: %u\n", ret_val, w_entry->send->pos, w_entry->send->limit); return ret_val; }