/* If any queries have timed out, note the timeout and move them on. */ static void process_timeouts(ares_channel channel, struct timeval *now) { time_t t; /* the time of the timeouts we're processing */ struct query *query; struct list_node* list_head; struct list_node* list_node; /* Process all the timeouts that have fired since the last time we processed * timeouts. If things are going well, then we'll have hundreds/thousands of * queries that fall into future buckets, and only a handful of requests * that fall into the "now" bucket, so this should be quite quick. */ for (t = channel->last_timeout_processed; t <= now->tv_sec; t++) { list_head = &(channel->queries_by_timeout[t % ARES_TIMEOUT_TABLE_SIZE]); for (list_node = list_head->next; list_node != list_head; ) { query = list_node->data; list_node = list_node->next; /* in case the query gets deleted */ if (query->timeout.tv_sec && ares__timedout(now, &query->timeout)) { query->error_status = ARES_ETIMEOUT; ++query->timeouts; next_server(channel, query, now); } } } channel->last_timeout_processed = now->tv_sec; }
static void handle_error(ares_channel channel, int whichserver, time_t now) { struct query *query; /* Reset communications with this server. */ //fprintf(stderr,"kennard:ares:handle_error: ...\n"); ares__close_poll(channel, whichserver); ares__close_sockets(&channel->servers[whichserver]); /* Tell all queries talking to this server to move on and not try * this server again. */ for (query = channel->queries; query != 0; query = query->next) { assert( query != 0 ); assert( channel->queries != 0 ); if (query->server == whichserver) { query->skip_server[whichserver] = 1; #if 0 // !cj! - this seem to corrput memory when it is called next_server(channel, query, now); #endif } } }
static gboolean send_timeout(gpointer user_data) { DBG("send timeout (retries %d)", retries); if (retries++ == NTP_SEND_RETRIES) next_server(); else send_packet(transmit_fd, timeserver); return FALSE; }
/* send to result to client */ void send_result_to_client(int sockfd, char *function, char **own_service_table, int *param_list, int param_len, char **client_server_list, int client_server_list_len, char *own_server_name, struct ServiceList *service_list, char *func_name){ int i=0; char *saveptr1; char *str; char *ns; int seed; int n; srand(time(NULL)); n = rand() % 100; for(i=0; i<own_service_table_size; i++){ char s[strlen(own_service_table[i])+1]; strcpy(s, own_service_table[i]); str = strtok_r(s, " ", &saveptr1); if( strcmp(func_name, str)==0 ){ if( strcmp(own_service_table[i], function)==0 ){ break; } else{ send_mismatch_message(sockfd, own_service_table[i]); return; } } } int service_num = i; ns = next_server(function, service_list, client_server_list, client_server_list_len); if( strcmp(own_service_table[i], "get_int int")==0 ){ if (n < BUSY_PERCENT){ if(ns == NULL){ send_out_message(sockfd); } else{ send_busy_message(sockfd, function, ns); } } else{ int r = get_int(param_list[0]); send_result_message(sockfd, function, r); } } else if( strcmp(own_service_table[i], "add int int")==0 ){ if (n < BUSY_PERCENT){ if(ns == NULL){ send_out_message(sockfd); } else{ send_busy_message(sockfd, function, ns); } } else{ int r = add(param_list[0], param_list[1]); send_result_message(sockfd, function, r); } } else if( strcmp(own_service_table[i], "sub int int")==0 ){ if (n < BUSY_PERCENT){ if(ns == NULL){ send_out_message(sockfd); } else{ send_busy_message(sockfd, function, ns); } } else{ int r = sub(param_list[0], param_list[1]); send_result_message(sockfd, function, r); } } else if( strcmp(own_service_table[i], "mul int int")==0 ){ if (n < BUSY_PERCENT){ if(ns == NULL){ send_out_message(sockfd); } else{ send_busy_message(sockfd, function, ns); } } else{ int r = mul(param_list[0], param_list[1]); send_result_message(sockfd, function, r); } } else if( strcmp(own_service_table[i], "a int int")==0 ){ if (n < BUSY_PERCENT){ if(ns == NULL){ send_out_message(sockfd); } else{ send_busy_message(sockfd, function, ns); } } else{ int r = a(param_list[0], param_list[1]); send_result_message(sockfd, function, r); } } else if( strcmp(own_service_table[i], "b int int")==0 ){ if (n < BUSY_PERCENT){ if(ns == NULL){ send_out_message(sockfd); } else{ send_busy_message(sockfd, function, ns); } } else{ int r = b(param_list[0], param_list[1]); send_result_message(sockfd, function, r); } } else if( strcmp(own_service_table[i], "c int int")==0 ){ if (n < BUSY_PERCENT){ if(ns == NULL){ send_out_message(sockfd); } else{ send_busy_message(sockfd, function, ns); } } else{ int r = c(param_list[0], param_list[1]); send_result_message(sockfd, function, r); } } else if( strcmp(own_service_table[i], "d int int")==0 ){ if (n < BUSY_PERCENT){ if(ns == NULL){ send_out_message(sockfd); } else{ send_busy_message(sockfd, function, ns); } } else{ int r = d(param_list[0], param_list[1]); send_result_message(sockfd, function, r); } } else if( strcmp(own_service_table[i], "e int int")==0 ){ if (n < BUSY_PERCENT){ if(ns == NULL){ send_out_message(sockfd); } else{ send_busy_message(sockfd, function, ns); } } else{ int r = e(param_list[0], param_list[1]); send_result_message(sockfd, function, r); } } else if( strcmp(own_service_table[i], "f int int")==0 ){ if (n < BUSY_PERCENT){ if(ns == NULL){ send_out_message(sockfd); } else{ send_busy_message(sockfd, function, ns); } } else{ int r = f(param_list[0], param_list[1]); send_result_message(sockfd, function, r); } } else{ if(ns == NULL) send_out_message(sockfd); else{ send_unknown_message(sockfd, function, ns); } } /* free */ if(ns != NULL) free(ns); }
/* Hook up to a server */ static void connect_server(void) { char pass[121], botserver[UHOSTLEN]; int servidx; unsigned int botserverport = 0; lastpingcheck = 0; trying_server = now; empty_msgq(); if (newserverport) { /* Jump to specified server */ curserv = -1; /* Reset server list */ strcpy(botserver, newserver); botserverport = newserverport; strcpy(pass, newserverpass); newserver[0] = 0; newserverport = 0; newserverpass[0] = 0; } else { if (curserv == -1) curserv = 999; pass[0] = 0; } if (!cycle_time) { struct chanset_t *chan; struct server_list *x = serverlist; if (!x && !botserverport) { putlog(LOG_SERV, "*", "No servers in server list"); cycle_time = 300; return; } servidx = new_dcc(&DCC_DNSWAIT, sizeof(struct dns_info)); if (servidx < 0) { putlog(LOG_SERV, "*", "NO MORE DCC CONNECTIONS -- Can't create server connection."); return; } if (connectserver[0]) /* drummer */ do_tcl("connect-server", connectserver); check_tcl_event("connect-server"); next_server(&curserv, botserver, &botserverport, pass); #ifdef TLS putlog(LOG_SERV, "*", "%s [%s]:%s%d", IRC_SERVERTRY, botserver, use_ssl ? "+" : "", botserverport); dcc[servidx].ssl = use_ssl; #else putlog(LOG_SERV, "*", "%s [%s]:%d", IRC_SERVERTRY, botserver, botserverport); #endif dcc[servidx].port = botserverport; strcpy(dcc[servidx].nick, "(server)"); strncpyz(dcc[servidx].host, botserver, UHOSTLEN); botuserhost[0] = 0; nick_juped = 0; for (chan = chanset; chan; chan = chan->next) chan->status &= ~CHAN_JUPED; dcc[servidx].timeval = now; dcc[servidx].sock = -1; dcc[servidx].u.dns->host = get_data_ptr(strlen(dcc[servidx].host) + 1); strcpy(dcc[servidx].u.dns->host, dcc[servidx].host); dcc[servidx].u.dns->cbuf = get_data_ptr(strlen(pass) + 1); strcpy(dcc[servidx].u.dns->cbuf, pass); dcc[servidx].u.dns->dns_success = server_resolve_success; dcc[servidx].u.dns->dns_failure = server_resolve_failure; dcc[servidx].u.dns->dns_type = RES_IPBYHOST; dcc[servidx].u.dns->type = &SERVER_SOCKET; if (server_cycle_wait) /* Back to 1st server & set wait time. * Note: Put it here, just in case the server quits on us quickly */ cycle_time = server_cycle_wait; else cycle_time = 0; /* I'm resolving... don't start another server connect request */ resolvserv = 1; /* Resolve the hostname. */ dcc_dnsipbyhost(dcc[servidx].host); } }
void ares__send_query(ares_channel channel, struct query *query, time_t now) { struct send_request *sendreq; struct server_state *server; server = &channel->servers[query->server]; if (query->using_tcp) { int tryWrite = 0; /* Make sure the TCP socket for this server is set up and queue * a send request. */ if (server->tcp_socket == -1) { if (open_tcp_socket(channel, server) == -1) { query->skip_server[query->server] = 1; next_server(channel, query, now); return; } if ( channel->poll_cb_func ) { // printf("ares_send_q: pollopen tcp fd=%d\n", server->tcp_socket); (*(channel->poll_cb_func))( channel->poll_cb_data, channel, query->server, server->tcp_socket, ARES_POLLACTION_OPEN); } } sendreq = malloc(sizeof(struct send_request)); if (!sendreq) end_query(channel, query, ARES_ENOMEM, NULL, 0); sendreq->data = query->tcpbuf; sendreq->len = query->tcplen; sendreq->next = NULL; if (server->qtail) { server->qtail->next = sendreq; } else { server->qhead = sendreq; tryWrite = 1; } server->qtail = sendreq; query->timeout = 0; if ( tryWrite ) { #if 0 time_t now; time(&now); write_tcp_data(channel, query->server, now); /* XXX: the write code doesn't seem to handle EAGAIN properly! */ #else if ( channel->poll_cb_func ) (*(channel->poll_cb_func))( channel->poll_cb_data, channel, query->server, server->tcp_socket, ARES_POLLACTION_WRITEON); #endif } } else { if (server->udp_socket == -1) { if (open_udp_socket(channel, server) == -1) { //fprintf(stderr,"kennard:ares:send_query:open_udp failed\n"); query->skip_server[query->server] = 1; next_server(channel, query, now); return; } if ( channel->poll_cb_func ) { // printf("ares_send_q: pollopen udp fd=%d\n", server->udp_socket); (*(channel->poll_cb_func))( channel->poll_cb_data, channel, query->server, server->udp_socket, ARES_POLLACTION_OPEN); } } if (send(server->udp_socket, query->qbuf, query->qlen, 0) == -1) { //fprintf(stderr,"kennard:ares:send_query:send_udp failed\n"); query->skip_server[query->server] = 1; next_server(channel, query, now); return; } query->timeout = now + ((query->itry == 0) ? channel->timeout : channel->timeout << query->itry / channel->nservers); } }
/* If any TCP sockets select true for writing, write out queued data * we have for them. */ static void write_tcp_data_core(ares_channel channel, int server_idx, time_t now) { struct server_state *server; struct send_request *sendreq; #ifdef WIN32 WSABUF *vec; #else struct iovec *vec; #endif int n, count; server = &channel->servers[server_idx]; if (!server->qhead || server->tcp_socket == -1 ) return; /* Count the number of send queue items. */ n = 0; for (sendreq = server->qhead; sendreq; sendreq = sendreq->next) n++; #ifdef WIN32 /* Allocate iovecs so we can send all our data at once. */ vec = malloc(n * sizeof(WSABUF)); if (vec) { int err; /* Fill in the iovecs and send. */ n = 0; for (sendreq = server->qhead; sendreq; sendreq = sendreq->next) { vec[n].buf = (char *) sendreq->data; vec[n].len = sendreq->len; n++; } err = WSASend(server->tcp_socket, vec, n, &count,0,0,0 ); if ( err == SOCKET_ERROR ) { count =-1; } free(vec); #else /* Allocate iovecs so we can send all our data at once. */ vec = malloc(n * sizeof(struct iovec)); if (vec) { // int err; /* Fill in the iovecs and send. */ n = 0; for (sendreq = server->qhead; sendreq; sendreq = sendreq->next) { vec[n].iov_base = (char *) sendreq->data; vec[n].iov_len = sendreq->len; n++; } count = writev(server->tcp_socket, vec, n); free(vec); #endif if (count < 0) { handle_error(channel, server_idx, now); return; } /* Advance the send queue by as many bytes as we sent. */ while (count) { sendreq = server->qhead; if (count >= sendreq->len) { count -= sendreq->len; server->qhead = sendreq->next; free(sendreq); if (server->qhead == NULL) { server->qtail = NULL; assert(count==0); break; } } else { sendreq->data += count; sendreq->len -= count; break; } } } else { /* Can't allocate iovecs; just send the first request. */ sendreq = server->qhead; #ifndef UNDER_CE count = write(server->tcp_socket, sendreq->data, sendreq->len); #else count = send(server->tcp_socket, sendreq->data, sendreq->len,0); #endif if (count < 0) { handle_error(channel, server_idx, now); return; } /* Advance the send queue by as many bytes as we sent. */ if (count == sendreq->len) { server->qhead = sendreq->next; if (server->qhead == NULL) server->qtail = NULL; free(sendreq); } else { sendreq->data += count; sendreq->len -= count; } } if ( server->qhead==NULL && channel->poll_cb_func ) { (*(channel->poll_cb_func))( channel->poll_cb_data, channel, server_idx, server->tcp_socket, ARES_POLLACTION_WRITEOFF); } } static void write_tcp_data(ares_channel channel, fd_set *write_fds, time_t now) { struct server_state *server; int i; for (i = 0; i < channel->nservers; i++) { /* Make sure server has data to send and is selected in write_fds. */ server = &channel->servers[i]; if (!server->qhead || server->tcp_socket == -1 ) continue; if ( write_fds && !FD_ISSET(server->tcp_socket, write_fds)) continue; write_tcp_data_core(channel, i, now); } } /* If any TCP socket selects true for reading, read some data, * allocate a buffer if we finish reading the length word, and process * a packet if we finish reading one. */ static void read_tcp_data(ares_channel channel, int server_idx, fd_set *read_fds, time_t now) { struct server_state *server; int i, count; for (i = 0; i < channel->nservers; i++) { /* Make sure the server has a socket and is selected in read_fds. */ if ( server_idx>=0 && i != server_idx ) continue; server = &channel->servers[i]; if (server->tcp_socket == -1 ) continue; if (!FD_ISSET(server->tcp_socket, read_fds)) continue; if (server->tcp_lenbuf_pos != 2) { /* We haven't yet read a length word, so read that (or * what's left to read of it). */ #if defined UNDER_CE || defined WIN32 count = recv(server->tcp_socket, server->tcp_lenbuf + server->tcp_lenbuf_pos, 2 - server->tcp_lenbuf_pos,0); #else count = read(server->tcp_socket, server->tcp_lenbuf + server->tcp_lenbuf_pos, 2 - server->tcp_lenbuf_pos); #endif if (count <= 0) { handle_error(channel, i, now); continue; } server->tcp_lenbuf_pos += count; if (server->tcp_lenbuf_pos == 2) { /* We finished reading the length word. Decode the * length and allocate a buffer for the data. */ server->tcp_length = server->tcp_lenbuf[0] << 8 | server->tcp_lenbuf[1]; server->tcp_buffer = malloc(server->tcp_length); if (!server->tcp_buffer) handle_error(channel, i, now); server->tcp_buffer_pos = 0; } } else { /* Read data into the allocated buffer. */ #if defined UNDER_CE || defined WIN32 count = recv(server->tcp_socket, server->tcp_buffer + server->tcp_buffer_pos, server->tcp_length - server->tcp_buffer_pos,0); #else count = read(server->tcp_socket, server->tcp_buffer + server->tcp_buffer_pos, server->tcp_length - server->tcp_buffer_pos); #endif if (count <= 0) { handle_error(channel, i, now); continue; } server->tcp_buffer_pos += count; if (server->tcp_buffer_pos == server->tcp_length) { /* We finished reading this answer; process it and * prepare to read another length word. */ process_answer(channel, server->tcp_buffer, server->tcp_length, i, 1, now); free(server->tcp_buffer); server->tcp_buffer = NULL; server->tcp_lenbuf_pos = 0; } } } } /* If any UDP sockets select true for reading, process them. */ static void read_udp_packets(ares_channel channel, int server_idx, fd_set *read_fds, time_t now) { struct server_state *server; int i, count; unsigned char buf[PACKETSZ + 1]; for (i = 0; i < channel->nservers; i++) { if ( server_idx>=0 && i != server_idx ) continue; /* Make sure the server has a socket and is selected in read_fds. */ server = &channel->servers[i]; if ( (server->udp_socket == -1) ) continue; if ( read_fds && !FD_ISSET(server->udp_socket, read_fds) ) continue; assert( server->udp_socket != -1 ); count = recv(server->udp_socket, buf, sizeof(buf), 0); if (count <= 0) { #if defined(WIN32) //int err; //err = WSAGetLastError(); //err = errno; switch (getErrno()) { case WSAEWOULDBLOCK: if ( read_fds ) { // read_fds is only null when using epoll // which shouldn't happen under windows // don't know why CLR is here anyways FD_CLR(server->udp_socket, read_fds); } continue; case WSAECONNABORTED: break; case WSAECONNRESET: // got an ICMP error on a previous send break; } #endif handle_error(channel, i, now); } else { process_answer(channel, buf, count, i, 0, now); } } } /* If any queries have timed out, note the timeout and move them on. */ static void process_timeouts(ares_channel channel, time_t now) { struct query *query, *next; for (query = channel->queries; query; query = next) { next = query->next; if (query->timeout != 0 && now >= query->timeout) { //fprintf(stderr, "kennard:ares:process_timeouts: got timeout\n"); query->error_status = ARES_ETIMEOUT; next_server(channel, query, now); } } } /* Handle an answer from a server. */ static void process_answer(ares_channel channel, unsigned char *abuf, int alen, int whichserver, int tcp, time_t now) { int id, tc, rcode; struct query *query; /* If there's no room in the answer for a header, we can't do much * with it. */ if (alen < HFIXEDSZ) return; /* Grab the query ID, truncate bit, and response code from the packet. */ id = DNS_HEADER_QID(abuf); tc = DNS_HEADER_TC(abuf); rcode = DNS_HEADER_RCODE(abuf); /* Find the query corresponding to this packet. */ for (query = channel->queries; query; query = query->next) { if (query->qid == id) break; } if (!query) return; /* If we got a truncated UDP packet and are not ignoring truncation, * don't accept the packet, and switch the query to TCP if we hadn't * done so already. */ if ((tc || alen > PACKETSZ) && !tcp && !(channel->flags & ARES_FLAG_IGNTC)) { if (!query->using_tcp) { query->using_tcp = 1; ares__send_query(channel, query, now); } return; } /* Limit alen to PACKETSZ if we aren't using TCP (only relevant if we * are ignoring truncation. */ if (alen > PACKETSZ && !tcp) alen = PACKETSZ; /* If we aren't passing through all error packets, discard packets * with SERVFAIL, NOTIMP, or REFUSED response codes. */ if (!(channel->flags & ARES_FLAG_NOCHECKRESP)) { if (rcode == SERVFAIL || rcode == NOTIMP || rcode == REFUSED) { query->skip_server[whichserver] = 1; if (query->server == whichserver) next_server(channel, query, now); return; } if (!same_questions((unsigned char*)query->qbuf, query->qlen, abuf, alen)) { if (query->server == whichserver) next_server(channel, query, now); return; } /* 'No such name' */ if ((channel->flags & ARES_FLAG_TRY_NEXT_SERVER_ON_RCODE3) && rcode == NXDOMAIN) { if (query->server == whichserver) { if (next_server_new_network(channel, query, now)) return; } } } end_query(channel, query, ARES_SUCCESS, abuf, alen); }