int lf_get_next_entry(int logfile_fd, lf_entry *nextentry, int vers)
{
  unsigned char blockbuf[60], *tmp;
  int           uln, ret;

  if ((ret = correct_read(logfile_fd, (void *) blockbuf, (size_t) 60)) != 60) {
    if (ret == 0)
      return 1;
/*    fprintf(stderr, "read 60 failed...%d\n", ret); */
    return 2;
  }

  /* We got one! */
  nextentry->version = vers;
  memcpy( &(nextentry->crs),  blockbuf+0,  4);
  memcpy( &(nextentry->cru),  blockbuf+4,  4);
  memcpy( &(nextentry->srs),  blockbuf+8,  4);
  memcpy( &(nextentry->sru),  blockbuf+12, 4);
  memcpy( &(nextentry->sls),  blockbuf+16, 4);
  memcpy( &(nextentry->slu),  blockbuf+20, 4);
  memcpy( &(nextentry->cip),  blockbuf+24, 4);
  memcpy( &(nextentry->cpt),  blockbuf+28, 2);
  memcpy( &(nextentry->sip),  blockbuf+30, 4);
  memcpy( &(nextentry->spt),  blockbuf+34, 2);
  memcpy( &(nextentry->cprg), blockbuf+36, 1);
  memcpy( &(nextentry->sprg), blockbuf+37, 1);
  memcpy( &(nextentry->cims), blockbuf+38, 4);
  memcpy( &(nextentry->sexp), blockbuf+42, 4);
  memcpy( &(nextentry->slmd), blockbuf+46, 4);
  memcpy( &(nextentry->rhl),  blockbuf+50, 4);
  memcpy( &(nextentry->rdl),  blockbuf+54, 4);
  memcpy( &(nextentry->urllen), blockbuf+58, 2);

  /* Now let's read in that url */
  uln = ntohs(nextentry->urllen);
  nextentry->url = (unsigned char *) malloc(sizeof(char) * 
					    (int) (uln + 1));
  if (nextentry->url == NULL) {
    fprintf(stderr, "out of memory in lf_get_next_netry!\n");
    exit(1);
  }
  if ((ret = correct_read(logfile_fd, (void *) (nextentry->url), (size_t) uln))
      != uln ) {
    if (ret == 0) {
      free(nextentry->url);
      return 1;
    }
    fprintf(stderr, "read of %d failed %d\n", (size_t) uln, ret);
    perror("aargh.");
    free(nextentry->url);
    return 2;
  }
  tmp = nextentry->url;
  *(tmp + uln) = '\0';
  return 0;
}
char *read_request(int fd) {
	char *request = (char *) malloc(REQUEST_SIZE * sizeof(char));
	int ret;

	if (request == NULL) {
		fprintf(stderr, "(SERVER): out of memory!\n");
		exit(-1);
	}

	ret = correct_read(fd, request, REQUEST_SIZE);
	if (ret != REQUEST_SIZE) {
		free(request);
		request = NULL;
	}
	return request;
}
int main(int argc, char **argv) {
  int  socket_talk, i;
  char request[REQUEST_SIZE];
  char response[RESPONSE_SIZE];

  if (argc != 3) {
    fprintf(stderr,
	    "(CLIENT): Invoke as  'client machine.name.address socknum'\n");
    exit(1);
  }

  // initialize request to some silly data
  for (i=0; i<REQUEST_SIZE; i++) {
    request[i] = (char) i%255;
  }

  // spin forever, opening connections, and pushing requests
  while(1) {
    int result;

    // open up a connection to the server
    if ((socket_talk = sconnect(argv[1], argv[2])) < 0) {
      perror("(CLIENT): sconnect");
      exit(1);
    }

    // write the request
    result = correct_write(socket_talk, request, REQUEST_SIZE);
    if (result == REQUEST_SIZE) {
      // read the response
      result = correct_read(socket_talk, response, RESPONSE_SIZE);
    }
    fprintf(stderr, "Result from server = %d", result);
    close(socket_talk);
  }
  
  return 0;
}
void C_correct_errors::correct_errors_in_reads(const C_arg& c_inst_args, const std::string& error_correction_info_file_name, CKMCFile& kmc_file) {
    std::ofstream& f_log = Log::get_stream();
    std::size_t current_chunk = 0;
    std::size_t NN = 0;

#ifdef USE_THREADS
#pragma omp parallel num_threads(c_inst_args.n_threads)
#endif
    {
        std::size_t local_chunk = 0;
#ifdef USE_FILE_READER
        FileReader f_read;
#else
        std::ifstream f_read;
#endif

        std::size_t total_num_corrected_errors_step1_1(0);
        std::size_t total_num_corrected_errors_step1_2(0);
        std::size_t total_num_corrected_errors_step1_3(0);
        std::size_t total_num_corrected_errors_step2_1(0);
        std::size_t total_num_corrected_errors_step2_2(0);

        std::size_t num_corrected_errors_step1_1(0);
        std::size_t num_corrected_errors_step1_2(0);
        std::size_t num_corrected_errors_step1_3(0);
        std::size_t num_corrected_errors_step2_1(0);
        std::size_t num_corrected_errors_step2_2(0);

        std::size_t num_corrected_reads(0);

        C_correct_read correct_read(quality_score_offset, c_inst_args.kmer_length, c_inst_args.extend, max_read_length, read_file_name, num_corrected_errors_step1_1, num_corrected_errors_step1_2, num_corrected_errors_step1_3, num_corrected_errors_step2_1, num_corrected_errors_step2_2, kmc_file);

        // perform correction while some chunks are available
        while (true) {
            bool exit_loop = false;
#ifdef USE_THREADS
#pragma omp critical
#endif
            {
                if (current_chunk >= n_chunks) {
                    exit_loop = true;
                }
                local_chunk = current_chunk++;
            }

            if (exit_loop) {
                break;
            }

            // open error correction information files
            std::ofstream f_error_correction;

            f_error_correction.open(get_error_correction_info_file_name(error_correction_info_file_name, local_chunk).c_str(), std::ios::binary);

            // check error correction information files
            if (f_error_correction.is_open() == false) {
                std::cout << std::endl << "ERROR: Cannot open " << get_error_correction_info_file_name(error_correction_info_file_name, local_chunk) << std::endl << std::endl;
                f_log << std::endl << "ERROR: Cannot open " << get_error_correction_info_file_name(error_correction_info_file_name, local_chunk) << std::endl << std::endl;
                exit(EXIT_FAILURE);
            }

#ifdef USE_FILE_READER
            // open read files
            f_read.setFileName(read_file_name, read_file_type);

            // iterate reads
            if (f_read.openFile(FileReader::READ)) {
                f_read.seekPos(chunks[local_chunk]);

                // header
                f_read.getLine(correct_read.header);
#else
            // open read files
            f_read.open(read_file_name.c_str());

            // iterate reads
            if (f_read.is_open()) {
                f_read.seekg(chunks[local_chunk]);

                // header
                getline(f_read, correct_read.header);
#endif
                std::string& sequence_modification = correct_read.sequence_modification;

                const std::size_t chunk_size = n_chunks == 1 ? 0 : num_reads / (n_chunks - 1);
                const std::size_t rest_size = n_chunks == 1 ? num_reads : num_reads % (n_chunks - 1);

                std::size_t local_read = 0;

                // perform correction for every read in current chunk
                while ((local_chunk < (n_chunks - 1) && local_read < chunk_size) || (local_chunk == (n_chunks - 1) && local_read < rest_size)) {
                    if (f_read.eof()) {
                        std::cout << "Erroneous chunk size (reads missing)." << std::endl;
                        f_log << "Erroneous chunk size (reads missing)." << std::endl;
                        exit(EXIT_FAILURE);
                    }

                    num_corrected_errors_step1_1 = 0;
                    num_corrected_errors_step1_2 = 0;
                    num_corrected_errors_step1_3 = 0;
                    num_corrected_errors_step2_1 = 0;
                    num_corrected_errors_step2_2 = 0;

                    ++local_read;
#ifdef USE_FILE_READER
                    // DNA sequence
                    f_read.getLine(correct_read.sequence);
                    std::size_t current_read_length = correct_read.sequence.length();

                    // "+"
                    f_read.getLine(correct_read.connector);

                    // quality score
                    f_read.getLine(correct_read.quality_score);
#else
                    // DNA sequence
                    getline(f_read, correct_read.sequence);
                    std::size_t current_read_length = correct_read.sequence.length();

                    // "+"
                    getline(f_read, correct_read.connector);

                    // quality score
                    getline(f_read, correct_read.quality_score);
#endif
                    bool too_many_errors(false);
                    std::fill(sequence_modification.begin(), sequence_modification.begin() + current_read_length, '0');

                    if (current_read_length > correct_read.kmer_length) {
                        // change sequences to upper case
                        transform(correct_read.sequence.begin(), correct_read.sequence.end(), correct_read.sequence.begin(), ::toupper);

                        // count and substitute Ns other characters
                        std::size_t number_of_Ns = 0;
                        for (std::size_t it = 0; it < current_read_length; ++it) {
                            bool is_nucleotide = false;
                            for (std::size_t it_nucl = 0; it_nucl < NUM_NEOCLEOTIDE; ++it_nucl) {
                                if (correct_read.sequence[it] == NEOCLEOTIDE[it_nucl]) {
                                    is_nucleotide = true;
                                    break;
                                }
                            }
                            if (!is_nucleotide) {
                                ++number_of_Ns;
                                correct_read.sequence[it] = SUBST_CHAR;
                            }
                        }

                        ++NN;

                        //----------------------------------------------------------------------
                        // correct errors in a read
                        //----------------------------------------------------------------------
#ifdef USE_THREADS
#ifndef DONT_PRINT_COUNTER
#pragma omp critical
#endif
#endif
                        {
#ifndef DONT_PRINT_COUNTER
                            if (NN % COUNTER_FREQ == 0) {
                                std::cout << NN << "\r";
                                std::cout.flush();
                            }
#endif
                        }

                        // update num_corrected_reads
                        if (number_of_Ns < current_read_length * MAX_N_RATE) {
                            correct_read.read_length = current_read_length;
                            correct_read.correct_errors_in_a_read_fastq();

                            std::size_t sum_errors = num_corrected_errors_step1_1 + num_corrected_errors_step1_2 + num_corrected_errors_step1_3 + num_corrected_errors_step2_1 + num_corrected_errors_step2_2;
                            if (sum_errors > (current_read_length * MAX_ERROR_RATE)) {
                                too_many_errors = true;
                            }
                            else if (sum_errors > 0) {
                                total_num_corrected_errors_step1_1 += num_corrected_errors_step1_1;
                                total_num_corrected_errors_step1_2 += num_corrected_errors_step1_2;
                                total_num_corrected_errors_step1_3 += num_corrected_errors_step1_3;
                                total_num_corrected_errors_step2_1 += num_corrected_errors_step2_1;
                                total_num_corrected_errors_step2_2 += num_corrected_errors_step2_2;

                                num_corrected_reads++;
                            }
                        }
                        else {
                            too_many_errors = true;
                        }
                    }

                    write_single_read(correct_read.sequence, sequence_modification, current_read_length, too_many_errors, f_error_correction);
#ifdef USE_FILE_READER
                    // header
                    f_read.getLine(correct_read.header);
#else
                    // header
                    getline(f_read, correct_read.header);
#endif
                }
            }
            else {
                std::cout << std::endl << "ERROR: Cannot open " << read_file_name << std::endl << std::endl;
                f_log << std::endl << "ERROR: Cannot open " << read_file_name << std::endl << std::endl;
                exit(EXIT_FAILURE);
            }

            // close read files
            f_read.close();

            // close error correction information files
            f_error_correction.close();
        }
#ifdef USE_THREADS
#pragma omp critical
#endif
        {
            global_num_corrected_reads += num_corrected_reads;
        }
    }
    std::cout << "     Number of corrected reads : " << std::setw(10) << global_num_corrected_reads << std::endl;
    std::cout << "     Correcting errors in reads: done" << std::endl << std::endl;

    f_log << "     Number of corrected reads : " << std::setw(10) << global_num_corrected_reads << std::endl;
    f_log << "     Correcting errors in reads: done" << std::endl << std::endl;
}



//----------------------------------------------------------------------
// Saves corrected read into a temporary file.
//----------------------------------------------------------------------

void C_correct_errors::write_single_read(const std::string& correct_read_sequence, const std::string& sequence_modification, const std::size_t read_length, const bool too_many_errors, std::ofstream& f_error_correction) {
    // write remaining bps into the vectors
    const std::size_t residue_read(read_length % BPS_PER_BYTE);
    //----------------------------------------------------------------------
    // write error correction information to files
    //----------------------------------------------------------------------
    char buffer = ZERO;

    std::size_t it_mod;
    for (it_mod = 0; it_mod < read_length; it_mod++) {
        if (too_many_errors == true) {
            encode_correction_info(buffer, correct_read_sequence[it_mod], '0');
        }
        else {
            encode_correction_info(buffer, correct_read_sequence[it_mod], sequence_modification[it_mod]);
        }

        if ((it_mod % BPS_PER_BYTE) == (BPS_PER_BYTE - 1)) {
            // update write_buffer*
            f_error_correction.write(&buffer, 1);

            // initialize buffer
            buffer &= ZERO;
        }
    }

    // read_length is a multiple of BPS_PER_BYTE
    // do nothing
    if (residue_read == 0) {
    } // read_length is not a multiple of BPS_PER_BYTE
    else {
        for (std::size_t it_fill = 0; it_fill < (BPS_PER_BYTE - residue_read); it_fill++) {
            buffer = buffer << 2;
        }

        // fill the last entry
        f_error_correction.write(&buffer, 1);
    }
}



//----------------------------------------------------------------------
// Saves read symbol in two bits.
//----------------------------------------------------------------------

inline void C_correct_errors::encode_correction_info(char& buffer, const char char_in_read, const char char_in_info) {
    buffer <<= 2;

    if (char_in_info != '0') {
        unsigned char read_id;
        unsigned char in_id;
        switch (char_in_info) {
            case 'A': in_id = 0;
                break;
            case 'C': in_id = 1;
                break;
            case 'G': in_id = 2;
                break;
            case 'T': in_id = 3;
                break;
            default: return;
        }

        switch (char_in_read) {
            case 'A': read_id = 0;
                break;
            case 'C': read_id = 1;
                break;
            case 'G': read_id = 2;
                break;
            case 'T': read_id = 3;
                break;
            default: return;
        }

        buffer |= (in_id - read_id + 4) % 4;
    }
}