/* Send the query to the server and read the response back. Return -1 if it fails, otherwise put the response back in msg and return the length of the response. */ static int send_recv(char * msg, int len, int msglen) { struct dns_header *dns_hdr; int finished = false; int read = 0; dns_hdr = (struct dns_header *) msg; do { int len_togo = len; struct timeval timeout; struct sockaddr_in local_addr, from_addr; memset((char *)&local_addr, 0, sizeof(local_addr)); local_addr.sin_family = AF_INET; local_addr.sin_addr.s_addr = htonl(INADDR_ANY); local_addr.sin_port = htons(get_port++); if (__udp_sendto(msg, len_togo, &server, &local_addr) < 0) return -1; memset((char *)&from_addr, 0, sizeof(from_addr)); timeout.tv_sec = CYGNUM_REDBOOT_NETWORKING_DNS_TIMEOUT; timeout.tv_usec = 0; read = __udp_recvfrom(msg, len, &from_addr, &local_addr, &timeout); if (read < 0) return -1; /* Reply to an old query. Ignore it */ if (ntohs(dns_hdr->id) != (id-1)) { continue; } finished = true; } while (!finished); return read; }
int tftp_stream_read(char *buf, int len, int *err) { int total_bytes = 0; int size, recv_len, data_len; struct timeval timeout; struct tftphdr *hdr = (struct tftphdr *)tftp_stream.data; while (total_bytes < len) { // Move any bytes which we've already read/buffered if (tftp_stream.avail > 0) { size = tftp_stream.avail; if (size > (len - total_bytes)) size = len - total_bytes; memcpy(buf, tftp_stream.bufp, size); buf += size; tftp_stream.bufp += size; tftp_stream.avail -= size; total_bytes += size; } else { if (tftp_ack(err) < 0) { return -1; } if ((tftp_stream.actual_len >= 0) && (tftp_stream.actual_len < SEGSIZE)) { // Out of data break; } timeout.tv_sec = (tftp_stream.last_good_block == 0) ? 10*TFTP_TIMEOUT_PERIOD : TFTP_TIMEOUT_PERIOD; timeout.tv_usec = 0; recv_len = sizeof(tftp_stream.data); if ((data_len = __udp_recvfrom(&tftp_stream.data[0], recv_len, &tftp_stream.from_addr, &tftp_stream.local_addr, &timeout)) < 0) { // No data, try again diag_printf("TFTP timed out %d/%d\n", tftp_stream.total_timeouts+1, TFTP_TIMEOUT_MAX); if ((++tftp_stream.total_timeouts > TFTP_TIMEOUT_MAX) || (tftp_stream.last_good_block == 0)) { // Timeout - no data received *err = TFTP_TIMEOUT; return -1; } // Send out the ACK for the last block - maybe server will retry if (tftp_ack(err) < 0) { return -1; } } else { tftp_stream.packets_received++; if (ntohs(hdr->th_opcode) == DATA) { if (ntohs(hdr->th_block) == (cyg_uint16)((tftp_stream.last_good_block+1) & 0xFFFF)) { // Consume this data data_len -= 4; /* Sizeof TFTP header */ tftp_stream.avail = tftp_stream.actual_len = data_len; tftp_stream.bufp = hdr->th_data; tftp_stream.last_good_block++; } } else { if (ntohs(hdr->th_opcode) == ERROR) { *err = ntohs(hdr->th_code); return -1; } else { // What kind of packet is this? *err = TFTP_PROTOCOL; return -1; } } } } } return total_bytes; }