/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 * 
 *   http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */



#include "pagespeed/kernel/util/hashed_nonce_generator.h"

#include <unistd.h>

#include "base/logging.h"
#include "pagespeed/kernel/base/basictypes.h"
#include "pagespeed/kernel/base/hasher.h"
#include "pagespeed/kernel/base/string.h"
#include "pagespeed/kernel/base/string_util.h"
#include "pagespeed/kernel/util/nonce_generator.h"

namespace net_instaweb {

HashedNonceGenerator::HashedNonceGenerator(
    const Hasher* hasher, StringPiece key, AbstractMutex* mutex)
    : NonceGenerator(mutex),
      hasher_(hasher),
      key_size_(key.size() - sizeof(counter_)) {
  DCHECK_LE(2 * hasher->RawHashSizeInBytes(), static_cast<int>(key.size()));
  // Allocate enough space in key_ to hold future data for hashing.  Note in
  // particular that we use the last sizeof(counter_) bits of the passed in key
  // to initialize counter_, and thus exclude it from key_size_.  But we will
  // ultimately need to buffer the initial key_size_ bytes of the passed-in key,
  // the counter_, and the pid.
  char *key_data = new char[key_size_ + sizeof(counter_) + sizeof(pid_t)];
  memcpy(key_data, key.data(), key_size_);
  memcpy(&counter_, key.data() + key_size_, sizeof(counter_));
  key_.reset(key_data);
  counter_ = hasher_->HashToUint64(key);
}

HashedNonceGenerator::~HashedNonceGenerator() { }

uint64 HashedNonceGenerator::NewNonceImpl() {
  ++counter_;
  // We look up the pid here and include it because we may have forked since
  // this HashedNonceGenerator was created, and we want to make sure the forked
  // values yield distinct nonce streams.
  pid_t pid = getpid();
  // We append data to key_, then hash the whole buffer.
  memcpy(&key_[key_size_], &counter_, sizeof(counter_));
  memcpy(&key_[key_size_ + sizeof(counter_)], &pid, sizeof(pid));
  return hasher_->HashToUint64(
      StringPiece(key_.get(), key_size_ + sizeof(counter_) + sizeof(pid)));
}

}  // namespace net_instaweb
