<commit_before>//===-- ArchiveWriter.cpp - Write LLVM archive files ----------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Builds up an LLVM archive file (.a) containing LLVM bitcode.
//
//===----------------------------------------------------------------------===//

#include "Archive.h"
#include "ArchiveInternals.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/Bitcode/ReaderWriter.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Process.h"
#include "llvm/Support/Signals.h"
#include "llvm/Support/system_error.h"
#include <fstream>
#include <iomanip>
#include <ostream>
using namespace llvm;

// Write an integer using variable bit rate encoding. This saves a few bytes
// per entry in the symbol table.
static inline void writeInteger(unsigned num, std::ofstream& ARFile) {
  while (1) {
    if (num < 0x80) { // done?
      ARFile << (unsigned char)num;
      return;
    }

    // Nope, we are bigger than a character, output the next 7 bits and set the
    // high bit to say that there is more coming...
    ARFile << (unsigned char)(0x80 | ((unsigned char)num & 0x7F));
    num >>= 7;  // Shift out 7 bits now...
  }
}

// Compute how many bytes are taken by a given VBR encoded value. This is needed
// to pre-compute the size of the symbol table.
static inline unsigned numVbrBytes(unsigned num) {

  // Note that the following nested ifs are somewhat equivalent to a binary
  // search. We split it in half by comparing against 2^14 first. This allows
  // most reasonable values to be done in 2 comparisons instead of 1 for
  // small ones and four for large ones. We expect this to access file offsets
  // in the 2^10 to 2^24 range and symbol lengths in the 2^0 to 2^8 range,
  // so this approach is reasonable.
  if (num < 1<<14) {
    if (num < 1<<7)
      return 1;
    else
      return 2;
  }
  if (num < 1<<21)
    return 3;

  if (num < 1<<28)
    return 4;
  return 5; // anything >= 2^28 takes 5 bytes
}

// Create an empty archive.
Archive* Archive::CreateEmpty(StringRef FilePath, LLVMContext& C) {
  Archive* result = new Archive(FilePath, C);
  return result;
}

// Fill the ArchiveMemberHeader with the information from a member. If
// TruncateNames is true, names are flattened to 15 chars or less. The sz field
// is provided here instead of coming from the mbr because the member might be
// stored compressed and the compressed size is not the ArchiveMember's size.
// Furthermore compressed files have negative size fields to identify them as
// compressed.
bool
Archive::fillHeader(const ArchiveMember &mbr, ArchiveMemberHeader& hdr,
                    int sz, bool TruncateNames) const {

  // Set the permissions mode, uid and gid
  hdr.init();
  char buffer[32];
  sprintf(buffer, "%-8o", mbr.getMode());
  memcpy(hdr.mode,buffer,8);
  sprintf(buffer,  "%-6u", mbr.getUser());
  memcpy(hdr.uid,buffer,6);
  sprintf(buffer,  "%-6u", mbr.getGroup());
  memcpy(hdr.gid,buffer,6);

  // Set the last modification date
  uint64_t secondsSinceEpoch = mbr.getModTime().toEpochTime();
  sprintf(buffer,"%-12u", unsigned(secondsSinceEpoch));
  memcpy(hdr.date,buffer,12);

  std::string mbrPath = sys::path::filename(mbr.getPath());

  // Set the name field in one of its various flavors.
  bool writeLongName = false;
  if (mbr.isStringTable()) {
    memcpy(hdr.name,ARFILE_STRTAB_NAME,16);
  } else if (mbr.isSVR4SymbolTable()) {
    memcpy(hdr.name,ARFILE_SVR4_SYMTAB_NAME,16);
  } else if (mbr.isBSD4SymbolTable()) {
    memcpy(hdr.name,ARFILE_BSD4_SYMTAB_NAME,16);
  } else if (TruncateNames) {
    const char* nm = mbrPath.c_str();
    unsigned len = mbrPath.length();
    size_t slashpos = mbrPath.rfind('/');
    if (slashpos != std::string::npos) {
      nm += slashpos + 1;
      len -= slashpos +1;
    }
    if (len > 15)
      len = 15;
    memcpy(hdr.name,nm,len);
    hdr.name[len] = '/';
  } else if (mbrPath.length() < 16 && mbrPath.find('/') == std::string::npos) {
    memcpy(hdr.name,mbrPath.c_str(),mbrPath.length());
    hdr.name[mbrPath.length()] = '/';
  } else {
    std::string nm = "#1/";
    nm += utostr(mbrPath.length());
    memcpy(hdr.name,nm.data(),nm.length());
    if (sz < 0)
      sz -= mbrPath.length();
    else
      sz += mbrPath.length();
    writeLongName = true;
  }

  // Set the size field
  if (sz < 0) {
    buffer[0] = '-';
    sprintf(&buffer[1],"%-9u",(unsigned)-sz);
  } else {
    sprintf(buffer, "%-10u", (unsigned)sz);
  }
  memcpy(hdr.size,buffer,10);

  return writeLongName;
}

// Insert a file into the archive before some other member. This also takes care
// of extracting the necessary flags and information from the file.
bool Archive::addFileBefore(StringRef filePath, iterator where,
                            std::string *ErrMsg) {
  if (!sys::fs::exists(filePath)) {
    if (ErrMsg)
      *ErrMsg = "Can not add a non-existent file to archive";
    return true;
  }

  ArchiveMember* mbr = new ArchiveMember(this);

  mbr->data = 0;
  mbr->path = filePath;
  sys::fs::file_status Status;
  error_code EC = sys::fs::status(filePath, Status);
  if (EC) {
    delete mbr;
    return true;
  }
  mbr->User = Status.getUser();
  mbr->Group = Status.getGroup();
  mbr->Mode = Status.permissions();
  mbr->ModTime = Status.getLastModificationTime();
  // FIXME: On posix this is a second stat.
  EC =  sys::fs::file_size(filePath, mbr->Size);
  if (EC) {
    delete mbr;
    return true;
  }

  unsigned flags = 0;
  if (sys::path::filename(filePath).size() > 15)
    flags |= ArchiveMember::HasLongFilenameFlag;

  sys::fs::file_magic type;
  if (sys::fs::identify_magic(mbr->path, type))
    type = sys::fs::file_magic::unknown;
  mbr->flags = flags;
  members.insert(where,mbr);
  return false;
}

// Write one member out to the file.
bool
Archive::writeMember(
  const ArchiveMember& member,
  raw_fd_ostream& ARFile,
  bool TruncateNames,
  std::string* ErrMsg
) {

  uint64_t filepos = ARFile.tell();
  filepos -= 8;

  // Get the data and its size either from the
  // member's in-memory data or directly from the file.
  size_t fSize = member.getSize();
  const char *data = (const char*)member.getData();
  MemoryBuffer *mFile = 0;
  if (!data) {
    OwningPtr<MemoryBuffer> File;
    if (error_code ec = MemoryBuffer::getFile(member.getPath(), File)) {
      if (ErrMsg)
        *ErrMsg = ec.message();
      return true;
    }
    mFile = File.take();
    data = mFile->getBufferStart();
    fSize = mFile->getBufferSize();
  }

  int hdrSize = fSize;

  // Compute the fields of the header
  ArchiveMemberHeader Hdr;
  bool writeLongName = fillHeader(member,Hdr,hdrSize,TruncateNames);

  // Write header to archive file
  ARFile.write((char*)&Hdr, sizeof(Hdr));

  // Write the long filename if its long
  if (writeLongName) {
    StringRef Name = sys::path::filename(member.getPath());
    ARFile.write(Name.data(), Name.size());
  }

  // Write the (possibly compressed) member's content to the file.
  ARFile.write(data,fSize);

  // Make sure the member is an even length
  if ((ARFile.tell() & 1) == 1)
    ARFile << ARFILE_PAD;

  // Close the mapped file if it was opened
  delete mFile;
  return false;
}

// Write the entire archive to the file specified when the archive was created.
// This writes to a temporary file first. Options are for creating a symbol
// table, flattening the file names (no directories, 15 chars max) and
// compressing each archive member.
bool Archive::writeToDisk(bool TruncateNames, std::string *ErrMsg) {
  // Make sure they haven't opened up the file, not loaded it,
  // but are now trying to write it which would wipe out the file.
  if (members.empty() && mapfile && mapfile->getBufferSize() > 8) {
    if (ErrMsg)
      *ErrMsg = "Can't write an archive not opened for writing";
    return true;
  }

  // Create a temporary file to store the archive in
  int TmpArchiveFD;
  SmallString<128> TmpArchive;
  error_code EC = sys::fs::createUniqueFile("temp-archive-%%%%%%%.a",
                                            TmpArchiveFD, TmpArchive);
  if (EC)
    return true;

  // Make sure the temporary gets removed if we crash
  sys::RemoveFileOnSignal(TmpArchive);

  // Create archive file for output.
  raw_fd_ostream ArchiveFile(TmpArchiveFD, true);

  // Write magic string to archive.
  ArchiveFile << ARFILE_MAGIC;

  // Loop over all member files, and write them out. Note that this also
  // builds the symbol table, symTab.
  for (MembersList::iterator I = begin(), E = end(); I != E; ++I) {
    if (writeMember(*I, ArchiveFile, TruncateNames, ErrMsg)) {
      sys::fs::remove(Twine(TmpArchive));
      ArchiveFile.close();
      return true;
    }
  }

  // Close archive file.
  ArchiveFile.close();

  // Before we replace the actual archive, we need to forget all the
  // members, since they point to data in that old archive. We need to do
  // this because we cannot replace an open file on Windows.
  cleanUpMemory();

  if (sys::fs::rename(Twine(TmpArchive), archPath)) {
    *ErrMsg = EC.message();
    return true;
  }

  return false;
}
<commit_msg>Fixes problem when calling llvm-ar from an unmodifiable directory.<commit_after>//===-- ArchiveWriter.cpp - Write LLVM archive files ----------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Builds up an LLVM archive file (.a) containing LLVM bitcode.
//
//===----------------------------------------------------------------------===//

#include "Archive.h"
#include "ArchiveInternals.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/Bitcode/ReaderWriter.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Process.h"
#include "llvm/Support/Signals.h"
#include "llvm/Support/system_error.h"
#include <fstream>
#include <iomanip>
#include <ostream>
using namespace llvm;

// Write an integer using variable bit rate encoding. This saves a few bytes
// per entry in the symbol table.
static inline void writeInteger(unsigned num, std::ofstream& ARFile) {
  while (1) {
    if (num < 0x80) { // done?
      ARFile << (unsigned char)num;
      return;
    }

    // Nope, we are bigger than a character, output the next 7 bits and set the
    // high bit to say that there is more coming...
    ARFile << (unsigned char)(0x80 | ((unsigned char)num & 0x7F));
    num >>= 7;  // Shift out 7 bits now...
  }
}

// Compute how many bytes are taken by a given VBR encoded value. This is needed
// to pre-compute the size of the symbol table.
static inline unsigned numVbrBytes(unsigned num) {

  // Note that the following nested ifs are somewhat equivalent to a binary
  // search. We split it in half by comparing against 2^14 first. This allows
  // most reasonable values to be done in 2 comparisons instead of 1 for
  // small ones and four for large ones. We expect this to access file offsets
  // in the 2^10 to 2^24 range and symbol lengths in the 2^0 to 2^8 range,
  // so this approach is reasonable.
  if (num < 1<<14) {
    if (num < 1<<7)
      return 1;
    else
      return 2;
  }
  if (num < 1<<21)
    return 3;

  if (num < 1<<28)
    return 4;
  return 5; // anything >= 2^28 takes 5 bytes
}

// Create an empty archive.
Archive* Archive::CreateEmpty(StringRef FilePath, LLVMContext& C) {
  Archive* result = new Archive(FilePath, C);
  return result;
}

// Fill the ArchiveMemberHeader with the information from a member. If
// TruncateNames is true, names are flattened to 15 chars or less. The sz field
// is provided here instead of coming from the mbr because the member might be
// stored compressed and the compressed size is not the ArchiveMember's size.
// Furthermore compressed files have negative size fields to identify them as
// compressed.
bool
Archive::fillHeader(const ArchiveMember &mbr, ArchiveMemberHeader& hdr,
                    int sz, bool TruncateNames) const {

  // Set the permissions mode, uid and gid
  hdr.init();
  char buffer[32];
  sprintf(buffer, "%-8o", mbr.getMode());
  memcpy(hdr.mode,buffer,8);
  sprintf(buffer,  "%-6u", mbr.getUser());
  memcpy(hdr.uid,buffer,6);
  sprintf(buffer,  "%-6u", mbr.getGroup());
  memcpy(hdr.gid,buffer,6);

  // Set the last modification date
  uint64_t secondsSinceEpoch = mbr.getModTime().toEpochTime();
  sprintf(buffer,"%-12u", unsigned(secondsSinceEpoch));
  memcpy(hdr.date,buffer,12);

  std::string mbrPath = sys::path::filename(mbr.getPath());

  // Set the name field in one of its various flavors.
  bool writeLongName = false;
  if (mbr.isStringTable()) {
    memcpy(hdr.name,ARFILE_STRTAB_NAME,16);
  } else if (mbr.isSVR4SymbolTable()) {
    memcpy(hdr.name,ARFILE_SVR4_SYMTAB_NAME,16);
  } else if (mbr.isBSD4SymbolTable()) {
    memcpy(hdr.name,ARFILE_BSD4_SYMTAB_NAME,16);
  } else if (TruncateNames) {
    const char* nm = mbrPath.c_str();
    unsigned len = mbrPath.length();
    size_t slashpos = mbrPath.rfind('/');
    if (slashpos != std::string::npos) {
      nm += slashpos + 1;
      len -= slashpos +1;
    }
    if (len > 15)
      len = 15;
    memcpy(hdr.name,nm,len);
    hdr.name[len] = '/';
  } else if (mbrPath.length() < 16 && mbrPath.find('/') == std::string::npos) {
    memcpy(hdr.name,mbrPath.c_str(),mbrPath.length());
    hdr.name[mbrPath.length()] = '/';
  } else {
    std::string nm = "#1/";
    nm += utostr(mbrPath.length());
    memcpy(hdr.name,nm.data(),nm.length());
    if (sz < 0)
      sz -= mbrPath.length();
    else
      sz += mbrPath.length();
    writeLongName = true;
  }

  // Set the size field
  if (sz < 0) {
    buffer[0] = '-';
    sprintf(&buffer[1],"%-9u",(unsigned)-sz);
  } else {
    sprintf(buffer, "%-10u", (unsigned)sz);
  }
  memcpy(hdr.size,buffer,10);

  return writeLongName;
}

// Insert a file into the archive before some other member. This also takes care
// of extracting the necessary flags and information from the file.
bool Archive::addFileBefore(StringRef filePath, iterator where,
                            std::string *ErrMsg) {
  if (!sys::fs::exists(filePath)) {
    if (ErrMsg)
      *ErrMsg = "Can not add a non-existent file to archive";
    return true;
  }

  ArchiveMember* mbr = new ArchiveMember(this);

  mbr->data = 0;
  mbr->path = filePath;
  sys::fs::file_status Status;
  error_code EC = sys::fs::status(filePath, Status);
  if (EC) {
    delete mbr;
    return true;
  }
  mbr->User = Status.getUser();
  mbr->Group = Status.getGroup();
  mbr->Mode = Status.permissions();
  mbr->ModTime = Status.getLastModificationTime();
  // FIXME: On posix this is a second stat.
  EC =  sys::fs::file_size(filePath, mbr->Size);
  if (EC) {
    delete mbr;
    return true;
  }

  unsigned flags = 0;
  if (sys::path::filename(filePath).size() > 15)
    flags |= ArchiveMember::HasLongFilenameFlag;

  sys::fs::file_magic type;
  if (sys::fs::identify_magic(mbr->path, type))
    type = sys::fs::file_magic::unknown;
  mbr->flags = flags;
  members.insert(where,mbr);
  return false;
}

// Write one member out to the file.
bool
Archive::writeMember(
  const ArchiveMember& member,
  raw_fd_ostream& ARFile,
  bool TruncateNames,
  std::string* ErrMsg
) {

  uint64_t filepos = ARFile.tell();
  filepos -= 8;

  // Get the data and its size either from the
  // member's in-memory data or directly from the file.
  size_t fSize = member.getSize();
  const char *data = (const char*)member.getData();
  MemoryBuffer *mFile = 0;
  if (!data) {
    OwningPtr<MemoryBuffer> File;
    if (error_code ec = MemoryBuffer::getFile(member.getPath(), File)) {
      if (ErrMsg)
        *ErrMsg = ec.message();
      return true;
    }
    mFile = File.take();
    data = mFile->getBufferStart();
    fSize = mFile->getBufferSize();
  }

  int hdrSize = fSize;

  // Compute the fields of the header
  ArchiveMemberHeader Hdr;
  bool writeLongName = fillHeader(member,Hdr,hdrSize,TruncateNames);

  // Write header to archive file
  ARFile.write((char*)&Hdr, sizeof(Hdr));

  // Write the long filename if its long
  if (writeLongName) {
    StringRef Name = sys::path::filename(member.getPath());
    ARFile.write(Name.data(), Name.size());
  }

  // Write the (possibly compressed) member's content to the file.
  ARFile.write(data,fSize);

  // Make sure the member is an even length
  if ((ARFile.tell() & 1) == 1)
    ARFile << ARFILE_PAD;

  // Close the mapped file if it was opened
  delete mFile;
  return false;
}

// Write the entire archive to the file specified when the archive was created.
// This writes to a temporary file first. Options are for creating a symbol
// table, flattening the file names (no directories, 15 chars max) and
// compressing each archive member.
bool Archive::writeToDisk(bool TruncateNames, std::string *ErrMsg) {
  // Make sure they haven't opened up the file, not loaded it,
  // but are now trying to write it which would wipe out the file.
  if (members.empty() && mapfile && mapfile->getBufferSize() > 8) {
    if (ErrMsg)
      *ErrMsg = "Can't write an archive not opened for writing";
    return true;
  }

  // Create a temporary file to store the archive in
  int TmpArchiveFD;
  SmallString<128> TmpArchive;
  error_code EC = sys::fs::createUniqueFile(
      archPath + ".temp-archive-%%%%%%%.a", TmpArchiveFD, TmpArchive);
  if (EC)
    return true;

  // Make sure the temporary gets removed if we crash
  sys::RemoveFileOnSignal(TmpArchive);

  // Create archive file for output.
  raw_fd_ostream ArchiveFile(TmpArchiveFD, true);

  // Write magic string to archive.
  ArchiveFile << ARFILE_MAGIC;

  // Loop over all member files, and write them out. Note that this also
  // builds the symbol table, symTab.
  for (MembersList::iterator I = begin(), E = end(); I != E; ++I) {
    if (writeMember(*I, ArchiveFile, TruncateNames, ErrMsg)) {
      sys::fs::remove(Twine(TmpArchive));
      ArchiveFile.close();
      return true;
    }
  }

  // Close archive file.
  ArchiveFile.close();

  // Before we replace the actual archive, we need to forget all the
  // members, since they point to data in that old archive. We need to do
  // this because we cannot replace an open file on Windows.
  cleanUpMemory();

  if (sys::fs::rename(Twine(TmpArchive), archPath)) {
    *ErrMsg = EC.message();
    return true;
  }

  return false;
}
<|endoftext|>


<commit_before>// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/icon_manager.h"

#include "base/file_util.h"
#include "base/scoped_ptr.h"
#include "chrome/common/stl_util-inl.h"
#include "SkBitmap.h"
#include "SkCanvas.h"

IconManager::IconManager() {
}

IconManager::~IconManager() {
  STLDeleteValues(&icon_cache_);
}

SkBitmap* IconManager::LookupIcon(const std::wstring& file_name,
                                  IconLoader::IconSize size) {
  std::wstring path = file_name;
  std::wstring extension = file_util::GetFileExtensionFromPath(path);
  if (extension != L"exe" && extension != L"dll" && extension != L"ico")
    path = L'.' + extension;

  IconMap::iterator it = icon_cache_.find(CacheKey(path, size));
  if (it != icon_cache_.end())
    return it->second;

  return NULL;
}

IconManager::Handle IconManager::LoadIcon(
    const std::wstring& file_name,
    IconLoader::IconSize size,
    CancelableRequestConsumerBase* consumer,
    IconRequestCallback* callback) {
  std::wstring path = file_name;
  std::wstring extension = file_util::GetFileExtensionFromPath(path);
  if (extension != L"exe" && extension != L"dll" && extension != L"ico")
    path = L'.' + extension;

  IconRequest* request = new IconRequest(callback);
  AddRequest(request, consumer);

  IconLoader* loader =
      IconLoader::CreateIconLoaderForFileResource(path, size, this);
  loader->Start();
  ClientRequest client_request = { request, path, size };
  requests_[loader] = client_request;
  return request->handle();
}

// IconLoader::Delegate implementation -----------------------------------------

bool IconManager::OnSkBitmapLoaded(IconLoader* source, SkBitmap* result) {
  scoped_ptr<IconLoader> scoped_source(source);

  // Look up our client state.
  ClientRequests::iterator rit = requests_.find(source);
  if (rit == requests_.end()) {
    NOTREACHED();
    return false;
  }

  ClientRequest client_request = rit->second;
  if (client_request.request->canceled()) {
    requests_.erase(rit);
    return true;
  }

  CacheKey key(client_request.file_name, client_request.size);
  IconMap::iterator it = icon_cache_.find(key);
  if (it != icon_cache_.end()) {
    it->second->swap(*result);
    delete result;
  } else {
    icon_cache_[key] = result;
  }

  // Inform our client that the request has completed.
  IconRequest* icon_request = client_request.request;
  icon_request->ForwardResult(IconRequest::TupleType(icon_request->handle(),
                                                     result));
  requests_.erase(rit);

  return true;
}

bool IconManager::OnHICONLoaded(IconLoader* source,
                                HICON small_icon,
                                HICON large_icon) {
  NOTREACHED();
  return false;
}

IconManager::CacheKey::CacheKey(std::wstring file_name,
                                IconLoader::IconSize size)
    : file_name(file_name),
      size(size) {
}

bool IconManager::CacheKey::operator<(const CacheKey &other) const {
  if (file_name != other.file_name)
    return file_name < other.file_name;
  return size < other.size;
}

<commit_msg>Fixes bug in IconManager where it was possible for callback to be invoked with a deleted pointer. We never hit this as none of the callers use the SkBitmap supplied to the callback. I was tempted to nuke the SkBitmap from the callback, but seems useful.<commit_after>// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/icon_manager.h"

#include "base/file_util.h"
#include "base/scoped_ptr.h"
#include "chrome/common/stl_util-inl.h"
#include "SkBitmap.h"
#include "SkCanvas.h"

IconManager::IconManager() {
}

IconManager::~IconManager() {
  STLDeleteValues(&icon_cache_);
}

SkBitmap* IconManager::LookupIcon(const std::wstring& file_name,
                                  IconLoader::IconSize size) {
  std::wstring path = file_name;
  std::wstring extension = file_util::GetFileExtensionFromPath(path);
  if (extension != L"exe" && extension != L"dll" && extension != L"ico")
    path = L'.' + extension;

  IconMap::iterator it = icon_cache_.find(CacheKey(path, size));
  if (it != icon_cache_.end())
    return it->second;

  return NULL;
}

IconManager::Handle IconManager::LoadIcon(
    const std::wstring& file_name,
    IconLoader::IconSize size,
    CancelableRequestConsumerBase* consumer,
    IconRequestCallback* callback) {
  std::wstring path = file_name;
  std::wstring extension = file_util::GetFileExtensionFromPath(path);
  if (extension != L"exe" && extension != L"dll" && extension != L"ico")
    path = L'.' + extension;

  IconRequest* request = new IconRequest(callback);
  AddRequest(request, consumer);

  IconLoader* loader =
      IconLoader::CreateIconLoaderForFileResource(path, size, this);
  loader->Start();
  ClientRequest client_request = { request, path, size };
  requests_[loader] = client_request;
  return request->handle();
}

// IconLoader::Delegate implementation -----------------------------------------

bool IconManager::OnSkBitmapLoaded(IconLoader* source, SkBitmap* result) {
  scoped_ptr<IconLoader> scoped_source(source);

  // Look up our client state.
  ClientRequests::iterator rit = requests_.find(source);
  if (rit == requests_.end()) {
    NOTREACHED();
    return false;  // Return false to indicate result should be deleted.
  }

  ClientRequest client_request = rit->second;
  if (client_request.request->canceled()) {
    requests_.erase(rit);
    return false;  // Return false to indicate result should be deleted.
  }

  CacheKey key(client_request.file_name, client_request.size);
  IconMap::iterator it = icon_cache_.find(key);
  if (it != icon_cache_.end()) {
    it->second->swap(*result);
    delete result;
    result = it->second;
  } else {
    icon_cache_[key] = result;
  }

  // Inform our client that the request has completed.
  IconRequest* icon_request = client_request.request;
  icon_request->ForwardResult(IconRequest::TupleType(icon_request->handle(),
                                                     result));
  requests_.erase(rit);

  return true;  // Indicates we took ownership of result.
}

bool IconManager::OnHICONLoaded(IconLoader* source,
                                HICON small_icon,
                                HICON large_icon) {
  NOTREACHED();
  return false;
}

IconManager::CacheKey::CacheKey(std::wstring file_name,
                                IconLoader::IconSize size)
    : file_name(file_name),
      size(size) {
}

bool IconManager::CacheKey::operator<(const CacheKey &other) const {
  if (file_name != other.file_name)
    return file_name < other.file_name;
  return size < other.size;
}

<|endoftext|>


<commit_before><commit_msg>Store the proxy's hostname rather than the first site visited via the proxy when storing proxy passwords. BUG=12992 TEST=none<commit_after><|endoftext|>


<commit_before><commit_msg>Fix autofill popups not closing when there are no suggestions. We have to call through on an empty suggestion array so that the popup is told to close.<commit_after><|endoftext|>


<commit_before>/*
The MIT License (MIT)

Copyright (c) 2013-2015 SRS(ossrs)

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

#ifndef SRS_CORE_HPP
#define SRS_CORE_HPP

/*
#include <srs_core.hpp>
*/

// current release version
#define VERSION_MAJOR       2
#define VERSION_MINOR       0
#define VERSION_REVISION    209

// generated by configure, only macros.
#include <srs_auto_headers.hpp>

// provider info.
#define RTMP_SIG_SRS_KEY "SRS"
#define RTMP_SIG_SRS_CODE "ZhouGuowen"
#define RTMP_SIG_SRS_AUTHROS "winlin,wenjie.zhao"
// contact info.
#define RTMP_SIG_SRS_WEB "http://ossrs.net"
#define RTMP_SIG_SRS_EMAIL "winlin@vip.126.com"
// debug info.
#define RTMP_SIG_SRS_ROLE "cluster"
#define RTMP_SIG_SRS_NAME RTMP_SIG_SRS_KEY"(Simple RTMP Server)"
#define RTMP_SIG_SRS_URL_SHORT "github.com/ossrs/srs"
#define RTMP_SIG_SRS_URL "https://"RTMP_SIG_SRS_URL_SHORT
#define RTMP_SIG_SRS_LICENSE "The MIT License (MIT)"
#define RTMP_SIG_SRS_COPYRIGHT "Copyright (c) 2013-2015 SRS(ossrs)"
#define RTMP_SIG_SRS_PRIMARY RTMP_SIG_SRS_KEY"/"VERSION_STABLE_BRANCH
#define RTMP_SIG_SRS_CONTRIBUTORS_URL RTMP_SIG_SRS_URL"/blob/master/AUTHORS.txt"
#define RTMP_SIG_SRS_HANDSHAKE RTMP_SIG_SRS_KEY"("RTMP_SIG_SRS_VERSION")"
#define RTMP_SIG_SRS_RELEASE RTMP_SIG_SRS_URL"/tree/"VERSION_STABLE_BRANCH".0release"
#define RTMP_SIG_SRS_ISSUES(id) RTMP_SIG_SRS_URL"/issues/"#id
#define RTMP_SIG_SRS_VERSION SRS_XSTR(VERSION_MAJOR)"."SRS_XSTR(VERSION_MINOR)"."SRS_XSTR(VERSION_REVISION)
#define RTMP_SIG_SRS_SERVER RTMP_SIG_SRS_KEY"/"RTMP_SIG_SRS_VERSION"("RTMP_SIG_SRS_CODE")"

// stable major version
#define VERSION_STABLE 1
#define VERSION_STABLE_BRANCH SRS_XSTR(VERSION_STABLE)".0release"

// internal macros, covert macro values to str,
// see: read https://gcc.gnu.org/onlinedocs/cpp/Stringification.html#Stringification
#define SRS_XSTR(v) SRS_INTERNAL_STR(v)
#define SRS_INTERNAL_STR(v) #v

/**
* the core provides the common defined macros, utilities,
* user must include the srs_core.hpp before any header, or maybe
* build failed.
*/

// for 32bit os, 2G big file limit for unistd io,
// ie. read/write/lseek to use 64bits size for huge file.
#ifndef _FILE_OFFSET_BITS
    #define _FILE_OFFSET_BITS 64
#endif

// for int64_t print using PRId64 format.
#ifndef __STDC_FORMAT_MACROS
    #define __STDC_FORMAT_MACROS
#endif

// for srs-librtmp, @see https://github.com/ossrs/srs/issues/213
#ifndef _WIN32
#include <inttypes.h>
#endif

#include <assert.h>
#define srs_assert(expression) assert(expression)

#include <stddef.h>
#include <sys/types.h>

// important performance options.
#include <srs_core_performance.hpp>

// free the p and set to NULL.
// p must be a T*.
#define srs_freep(p) \
    if (p) { \
        delete p; \
        p = NULL; \
    } \
    (void)0
// please use the freepa(T[]) to free an array,
// or the behavior is undefined.
#define srs_freepa(pa) \
    if (pa) { \
        delete[] pa; \
        pa = NULL; \
    } \
    (void)0

/**
* disable copy constructor of class,
* to avoid the memory leak or corrupt by copy instance.
*/
#define disable_default_copy(className)\
    private:\
        /** \
        * disable the copy constructor and operator=, donot allow directly copy. \
        */ \
        className(const className&); \
        className& operator= (const className&)

/**
 * important check for st(state-threads),
 * only support the following cpus:
 *      1. i386/amd64/x86_64
 *      2. arm, glibc <= 2.15
 */
#if !defined(__amd64__) && !defined(__x86_64__) && !defined(__i386__) && !defined(__arm__)
    #error "only support i386/amd64/x86_64/arm cpu"
#endif
#if defined(__arm__) && (__GLIBC__ != 2 || __GLIBC_MINOR__ > 15)
    #error "for arm, only support glibc <= 2.15"
#endif

#endif
<commit_msg>2.0.210<commit_after>/*
The MIT License (MIT)

Copyright (c) 2013-2015 SRS(ossrs)

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

#ifndef SRS_CORE_HPP
#define SRS_CORE_HPP

/*
#include <srs_core.hpp>
*/

// current release version
#define VERSION_MAJOR       2
#define VERSION_MINOR       0
#define VERSION_REVISION    210

// generated by configure, only macros.
#include <srs_auto_headers.hpp>

// provider info.
#define RTMP_SIG_SRS_KEY "SRS"
#define RTMP_SIG_SRS_CODE "ZhouGuowen"
#define RTMP_SIG_SRS_AUTHROS "winlin,wenjie.zhao"
// contact info.
#define RTMP_SIG_SRS_WEB "http://ossrs.net"
#define RTMP_SIG_SRS_EMAIL "winlin@vip.126.com"
// debug info.
#define RTMP_SIG_SRS_ROLE "cluster"
#define RTMP_SIG_SRS_NAME RTMP_SIG_SRS_KEY"(Simple RTMP Server)"
#define RTMP_SIG_SRS_URL_SHORT "github.com/ossrs/srs"
#define RTMP_SIG_SRS_URL "https://"RTMP_SIG_SRS_URL_SHORT
#define RTMP_SIG_SRS_LICENSE "The MIT License (MIT)"
#define RTMP_SIG_SRS_COPYRIGHT "Copyright (c) 2013-2015 SRS(ossrs)"
#define RTMP_SIG_SRS_PRIMARY RTMP_SIG_SRS_KEY"/"VERSION_STABLE_BRANCH
#define RTMP_SIG_SRS_CONTRIBUTORS_URL RTMP_SIG_SRS_URL"/blob/master/AUTHORS.txt"
#define RTMP_SIG_SRS_HANDSHAKE RTMP_SIG_SRS_KEY"("RTMP_SIG_SRS_VERSION")"
#define RTMP_SIG_SRS_RELEASE RTMP_SIG_SRS_URL"/tree/"VERSION_STABLE_BRANCH".0release"
#define RTMP_SIG_SRS_ISSUES(id) RTMP_SIG_SRS_URL"/issues/"#id
#define RTMP_SIG_SRS_VERSION SRS_XSTR(VERSION_MAJOR)"."SRS_XSTR(VERSION_MINOR)"."SRS_XSTR(VERSION_REVISION)
#define RTMP_SIG_SRS_SERVER RTMP_SIG_SRS_KEY"/"RTMP_SIG_SRS_VERSION"("RTMP_SIG_SRS_CODE")"

// stable major version
#define VERSION_STABLE 1
#define VERSION_STABLE_BRANCH SRS_XSTR(VERSION_STABLE)".0release"

// internal macros, covert macro values to str,
// see: read https://gcc.gnu.org/onlinedocs/cpp/Stringification.html#Stringification
#define SRS_XSTR(v) SRS_INTERNAL_STR(v)
#define SRS_INTERNAL_STR(v) #v

/**
* the core provides the common defined macros, utilities,
* user must include the srs_core.hpp before any header, or maybe
* build failed.
*/

// for 32bit os, 2G big file limit for unistd io,
// ie. read/write/lseek to use 64bits size for huge file.
#ifndef _FILE_OFFSET_BITS
    #define _FILE_OFFSET_BITS 64
#endif

// for int64_t print using PRId64 format.
#ifndef __STDC_FORMAT_MACROS
    #define __STDC_FORMAT_MACROS
#endif

// for srs-librtmp, @see https://github.com/ossrs/srs/issues/213
#ifndef _WIN32
#include <inttypes.h>
#endif

#include <assert.h>
#define srs_assert(expression) assert(expression)

#include <stddef.h>
#include <sys/types.h>

// important performance options.
#include <srs_core_performance.hpp>

// free the p and set to NULL.
// p must be a T*.
#define srs_freep(p) \
    if (p) { \
        delete p; \
        p = NULL; \
    } \
    (void)0
// please use the freepa(T[]) to free an array,
// or the behavior is undefined.
#define srs_freepa(pa) \
    if (pa) { \
        delete[] pa; \
        pa = NULL; \
    } \
    (void)0

/**
* disable copy constructor of class,
* to avoid the memory leak or corrupt by copy instance.
*/
#define disable_default_copy(className)\
    private:\
        /** \
        * disable the copy constructor and operator=, donot allow directly copy. \
        */ \
        className(const className&); \
        className& operator= (const className&)

/**
 * important check for st(state-threads),
 * only support the following cpus:
 *      1. i386/amd64/x86_64
 *      2. arm, glibc <= 2.15
 */
#if !defined(__amd64__) && !defined(__x86_64__) && !defined(__i386__) && !defined(__arm__)
    #error "only support i386/amd64/x86_64/arm cpu"
#endif
#if defined(__arm__) && (__GLIBC__ != 2 || __GLIBC_MINOR__ > 15)
    #error "for arm, only support glibc <= 2.15"
#endif

#endif
<|endoftext|>


<commit_before>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/file_util.h"
#include "base/path_service.h"
#include "base/test/test_timeouts.h"
#include "build/build_config.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/test/automation/tab_proxy.h"
#include "chrome/test/ui/ui_test.h"
#include "net/base/net_util.h"
#include "net/test/test_server.h"
#include "webkit/plugins/plugin_switches.h"

namespace {

// Platform-specific filename relative to the chrome executable.
#if defined(OS_WIN)
const wchar_t library_name[] = L"ppapi_tests.dll";
#elif defined(OS_MACOSX)
const char library_name[] = "ppapi_tests.plugin";
#elif defined(OS_POSIX)
const char library_name[] = "libppapi_tests.so";
#endif

}  // namespace

// In-process plugin test runner.  See OutOfProcessPPAPITest below for the
// out-of-process version.
class PPAPITest : public UITest {
 public:
  PPAPITest() {
    // Append the switch to register the pepper plugin.
    // library name = <out dir>/<test_name>.<library_extension>
    // MIME type = application/x-ppapi-<test_name>
    FilePath plugin_dir;
    PathService::Get(base::DIR_EXE, &plugin_dir);

    FilePath plugin_lib = plugin_dir.Append(library_name);
    EXPECT_TRUE(file_util::PathExists(plugin_lib));
    FilePath::StringType pepper_plugin = plugin_lib.value();
    pepper_plugin.append(FILE_PATH_LITERAL(";application/x-ppapi-tests"));
    launch_arguments_.AppendSwitchNative(switches::kRegisterPepperPlugins,
                                         pepper_plugin);

    // The test sends us the result via a cookie.
    launch_arguments_.AppendSwitch(switches::kEnableFileCookies);

    // Some stuff is hung off of the testing interface which is not enabled
    // by default.
    launch_arguments_.AppendSwitch(switches::kEnablePepperTesting);

    // Give unlimited quota for files to Pepper tests.
    // TODO(dumi): remove this switch once we have a quota management
    // system in place.
    launch_arguments_.AppendSwitch(switches::kUnlimitedQuotaForFiles);

#if defined(ENABLE_P2P_APIS)
    // Enable P2P API.
    launch_arguments_.AppendSwitch(switches::kEnableP2PApi);
#endif // ENABLE_P2P_APIS
  }

  void RunTest(const std::string& test_case) {
    FilePath test_path;
    PathService::Get(base::DIR_SOURCE_ROOT, &test_path);
    test_path = test_path.Append(FILE_PATH_LITERAL("ppapi"));
    test_path = test_path.Append(FILE_PATH_LITERAL("tests"));
    test_path = test_path.Append(FILE_PATH_LITERAL("test_case.html"));

    // Sanity check the file name.
    EXPECT_TRUE(file_util::PathExists(test_path));

    GURL::Replacements replacements;
    std::string query("testcase=");
    query += test_case;
    replacements.SetQuery(query.c_str(), url_parse::Component(0, query.size()));
    GURL test_url = net::FilePathToFileURL(test_path);
    RunTestURL(test_url.ReplaceComponents(replacements));
  }

  void RunTestViaHTTP(const std::string& test_case) {
    net::TestServer test_server(
        net::TestServer::TYPE_HTTP,
        FilePath(FILE_PATH_LITERAL("ppapi/tests")));
    ASSERT_TRUE(test_server.Start());
    RunTestURL(
        test_server.GetURL("files/test_case.html?testcase=" + test_case));
  }

 private:
  void RunTestURL(const GURL& test_url) {
    scoped_refptr<TabProxy> tab(GetActiveTab());
    ASSERT_TRUE(tab.get());
    ASSERT_TRUE(tab->NavigateToURL(test_url));

    // First wait for the "starting" signal. This cookie is set at the start
    // of every test. Waiting for this separately allows us to avoid a single
    // long timeout. Instead, we can have two timeouts which allow startup +
    // test execution time to take a while on a loaded computer, while also
    // making sure we're making forward progress.
    std::string startup_cookie =
        WaitUntilCookieNonEmpty(tab.get(), test_url,
            "STARTUP_COOKIE", TestTimeouts::action_max_timeout_ms());

    // If this fails, the plugin couldn't be loaded in the given amount of
    // time. This may mean the plugin was not found or possibly the system
    // can't load it due to missing symbols, etc.
    ASSERT_STREQ("STARTED", startup_cookie.c_str())
        << "Plugin couldn't be loaded. Make sure the PPAPI test plugin is "
        << "built, in the right place, and doesn't have any missing symbols.";

    std::string escaped_value =
        WaitUntilCookieNonEmpty(tab.get(), test_url,
            "COMPLETION_COOKIE", TestTimeouts::large_test_timeout_ms());
    EXPECT_STREQ("PASS", escaped_value.c_str());
  }
};

// Variant of PPAPITest that runs plugins out-of-process to test proxy
// codepaths.
class OutOfProcessPPAPITest : public PPAPITest {
 public:
  OutOfProcessPPAPITest() {
    // Run PPAPI out-of-process to exercise proxy implementations.
    launch_arguments_.AppendSwitch(switches::kPpapiOutOfProcess);
  }
};

TEST_F(PPAPITest, Broker) {
  RunTest("Broker");
}

TEST_F(PPAPITest, CursorControl) {
  RunTest("CursorControl");
}

TEST_F(PPAPITest, FAILS_Instance) {
  RunTest("Instance");
}

TEST_F(PPAPITest, Graphics2D) {
  RunTest("Graphics2D");
}

TEST_F(PPAPITest, ImageData) {
  RunTest("ImageData");
}

TEST_F(PPAPITest, Buffer) {
  RunTest("Buffer");
}
#if !defined(OS_MACOSX)
TEST_F(OutOfProcessPPAPITest, Buffer) {
  RunTest("Buffer");
}
#endif

TEST_F(PPAPITest, URLLoader) {
  RunTestViaHTTP("URLLoader");
}

TEST_F(PPAPITest,PaintAggregator) {
  RunTestViaHTTP("PaintAggregator");
}

TEST_F(PPAPITest, Scrollbar) {
  RunTest("Scrollbar");
}

TEST_F(PPAPITest, URLUtil) {
  RunTest("URLUtil");
}

TEST_F(PPAPITest, CharSet) {
  RunTest("CharSet");
}

TEST_F(PPAPITest, Var) {
  RunTest("Var");
}

TEST_F(PPAPITest, VarDeprecated) {
  RunTest("VarDeprecated");
}

TEST_F(PPAPITest, PostMessage) {
  RunTest("PostMessage");
}

// http://crbug.com/83443
TEST_F(PPAPITest, FAILS_FileIO) {
  RunTestViaHTTP("FileIO");
}

TEST_F(PPAPITest, FileRef) {
  RunTestViaHTTP("FileRef");
}

#if defined(OS_POSIX)
#define MAYBE_DirectoryReader FLAKY_DirectoryReader
#else
#define MAYBE_DirectoryReader DirectoryReader
#endif

// Flaky on Mac + Linux, maybe http://codereview.chromium.org/7094008
TEST_F(PPAPITest, MAYBE_DirectoryReader) {
  RunTestViaHTTP("DirectoryReader");
}

#if defined(ENABLE_P2P_APIS)
TEST_F(PPAPITest, Transport) {
  RunTest("Transport");
}
#endif // ENABLE_P2P_APIS
<commit_msg>Stop excluding out-of-process tests on OS_MACOSX<commit_after>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/file_util.h"
#include "base/path_service.h"
#include "base/test/test_timeouts.h"
#include "build/build_config.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/test/automation/tab_proxy.h"
#include "chrome/test/ui/ui_test.h"
#include "net/base/net_util.h"
#include "net/test/test_server.h"
#include "webkit/plugins/plugin_switches.h"

namespace {

// Platform-specific filename relative to the chrome executable.
#if defined(OS_WIN)
const wchar_t library_name[] = L"ppapi_tests.dll";
#elif defined(OS_MACOSX)
const char library_name[] = "ppapi_tests.plugin";
#elif defined(OS_POSIX)
const char library_name[] = "libppapi_tests.so";
#endif

}  // namespace

// In-process plugin test runner.  See OutOfProcessPPAPITest below for the
// out-of-process version.
class PPAPITest : public UITest {
 public:
  PPAPITest() {
    // Append the switch to register the pepper plugin.
    // library name = <out dir>/<test_name>.<library_extension>
    // MIME type = application/x-ppapi-<test_name>
    FilePath plugin_dir;
    PathService::Get(base::DIR_EXE, &plugin_dir);

    FilePath plugin_lib = plugin_dir.Append(library_name);
    EXPECT_TRUE(file_util::PathExists(plugin_lib));
    FilePath::StringType pepper_plugin = plugin_lib.value();
    pepper_plugin.append(FILE_PATH_LITERAL(";application/x-ppapi-tests"));
    launch_arguments_.AppendSwitchNative(switches::kRegisterPepperPlugins,
                                         pepper_plugin);

    // The test sends us the result via a cookie.
    launch_arguments_.AppendSwitch(switches::kEnableFileCookies);

    // Some stuff is hung off of the testing interface which is not enabled
    // by default.
    launch_arguments_.AppendSwitch(switches::kEnablePepperTesting);

    // Give unlimited quota for files to Pepper tests.
    // TODO(dumi): remove this switch once we have a quota management
    // system in place.
    launch_arguments_.AppendSwitch(switches::kUnlimitedQuotaForFiles);

#if defined(ENABLE_P2P_APIS)
    // Enable P2P API.
    launch_arguments_.AppendSwitch(switches::kEnableP2PApi);
#endif // ENABLE_P2P_APIS
  }

  void RunTest(const std::string& test_case) {
    FilePath test_path;
    PathService::Get(base::DIR_SOURCE_ROOT, &test_path);
    test_path = test_path.Append(FILE_PATH_LITERAL("ppapi"));
    test_path = test_path.Append(FILE_PATH_LITERAL("tests"));
    test_path = test_path.Append(FILE_PATH_LITERAL("test_case.html"));

    // Sanity check the file name.
    EXPECT_TRUE(file_util::PathExists(test_path));

    GURL::Replacements replacements;
    std::string query("testcase=");
    query += test_case;
    replacements.SetQuery(query.c_str(), url_parse::Component(0, query.size()));
    GURL test_url = net::FilePathToFileURL(test_path);
    RunTestURL(test_url.ReplaceComponents(replacements));
  }

  void RunTestViaHTTP(const std::string& test_case) {
    net::TestServer test_server(
        net::TestServer::TYPE_HTTP,
        FilePath(FILE_PATH_LITERAL("ppapi/tests")));
    ASSERT_TRUE(test_server.Start());
    RunTestURL(
        test_server.GetURL("files/test_case.html?testcase=" + test_case));
  }

 private:
  void RunTestURL(const GURL& test_url) {
    scoped_refptr<TabProxy> tab(GetActiveTab());
    ASSERT_TRUE(tab.get());
    ASSERT_TRUE(tab->NavigateToURL(test_url));

    // First wait for the "starting" signal. This cookie is set at the start
    // of every test. Waiting for this separately allows us to avoid a single
    // long timeout. Instead, we can have two timeouts which allow startup +
    // test execution time to take a while on a loaded computer, while also
    // making sure we're making forward progress.
    std::string startup_cookie =
        WaitUntilCookieNonEmpty(tab.get(), test_url,
            "STARTUP_COOKIE", TestTimeouts::action_max_timeout_ms());

    // If this fails, the plugin couldn't be loaded in the given amount of
    // time. This may mean the plugin was not found or possibly the system
    // can't load it due to missing symbols, etc.
    ASSERT_STREQ("STARTED", startup_cookie.c_str())
        << "Plugin couldn't be loaded. Make sure the PPAPI test plugin is "
        << "built, in the right place, and doesn't have any missing symbols.";

    std::string escaped_value =
        WaitUntilCookieNonEmpty(tab.get(), test_url,
            "COMPLETION_COOKIE", TestTimeouts::large_test_timeout_ms());
    EXPECT_STREQ("PASS", escaped_value.c_str());
  }
};

// Variant of PPAPITest that runs plugins out-of-process to test proxy
// codepaths.
class OutOfProcessPPAPITest : public PPAPITest {
 public:
  OutOfProcessPPAPITest() {
    // Run PPAPI out-of-process to exercise proxy implementations.
    launch_arguments_.AppendSwitch(switches::kPpapiOutOfProcess);
  }
};

TEST_F(PPAPITest, Broker) {
  RunTest("Broker");
}

TEST_F(PPAPITest, CursorControl) {
  RunTest("CursorControl");
}

TEST_F(PPAPITest, FAILS_Instance) {
  RunTest("Instance");
}

TEST_F(PPAPITest, Graphics2D) {
  RunTest("Graphics2D");
}

TEST_F(PPAPITest, ImageData) {
  RunTest("ImageData");
}

TEST_F(PPAPITest, Buffer) {
  RunTest("Buffer");
}
TEST_F(OutOfProcessPPAPITest, Buffer) {
  RunTest("Buffer");
}

TEST_F(PPAPITest, URLLoader) {
  RunTestViaHTTP("URLLoader");
}

TEST_F(PPAPITest,PaintAggregator) {
  RunTestViaHTTP("PaintAggregator");
}

TEST_F(PPAPITest, Scrollbar) {
  RunTest("Scrollbar");
}

TEST_F(PPAPITest, URLUtil) {
  RunTest("URLUtil");
}

TEST_F(PPAPITest, CharSet) {
  RunTest("CharSet");
}

TEST_F(PPAPITest, Var) {
  RunTest("Var");
}

TEST_F(PPAPITest, VarDeprecated) {
  RunTest("VarDeprecated");
}

TEST_F(PPAPITest, PostMessage) {
  RunTest("PostMessage");
}

// http://crbug.com/83443
TEST_F(PPAPITest, FAILS_FileIO) {
  RunTestViaHTTP("FileIO");
}

TEST_F(PPAPITest, FileRef) {
  RunTestViaHTTP("FileRef");
}

#if defined(OS_POSIX)
#define MAYBE_DirectoryReader FLAKY_DirectoryReader
#else
#define MAYBE_DirectoryReader DirectoryReader
#endif

// Flaky on Mac + Linux, maybe http://codereview.chromium.org/7094008
TEST_F(PPAPITest, MAYBE_DirectoryReader) {
  RunTestViaHTTP("DirectoryReader");
}

#if defined(ENABLE_P2P_APIS)
TEST_F(PPAPITest, Transport) {
  RunTest("Transport");
}
#endif // ENABLE_P2P_APIS
<|endoftext|>


<commit_before><commit_msg>Disable WorkerHttpLayoutTests which is flaky (both debug and release winxp).<commit_after><|endoftext|>


<commit_before>// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/string_util.h"
#include "chrome/app/chrome_dll_resource.h"
#include "chrome/browser/worker_host/worker_service.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/test/automation/browser_proxy.h"
#include "chrome/test/automation/tab_proxy.h"
#include "chrome/test/ui/ui_layout_test.h"

static const char kTestCompleteCookie[] = "status";
static const char kTestCompleteSuccess[] = "OK";

class WorkerTest : public UILayoutTest {
 protected:
  virtual ~WorkerTest() { }

  void RunTest(const std::wstring& test_case) {
    scoped_refptr<TabProxy> tab(GetActiveTab());
    ASSERT_TRUE(tab.get());

    GURL url = GetTestUrl(L"workers", test_case);
    ASSERT_TRUE(tab->NavigateToURL(url));

    std::string value = WaitUntilCookieNonEmpty(tab.get(), url,
        kTestCompleteCookie, kTestIntervalMs, kTestWaitTimeoutMs);
    ASSERT_STREQ(kTestCompleteSuccess, value.c_str());
  }

  void RunIncognitoTest(const std::wstring& test_case) {
    scoped_refptr<BrowserProxy> browser(automation()->GetBrowserWindow(0));
    // Open an Incognito window.
    int window_count;
    ASSERT_TRUE(browser->RunCommand(IDC_NEW_INCOGNITO_WINDOW));
    scoped_refptr<BrowserProxy> incognito(automation()->GetBrowserWindow(1));
    scoped_refptr<TabProxy> tab(incognito->GetTab(0));
    ASSERT_TRUE(automation()->GetBrowserWindowCount(&window_count));
    ASSERT_EQ(2, window_count);

    GURL url = GetTestUrl(L"workers", test_case);
    ASSERT_TRUE(tab->NavigateToURL(url));

    std::string value = WaitUntilCookieNonEmpty(tab.get(), url,
        kTestCompleteCookie, kTestIntervalMs, kTestWaitTimeoutMs);

    // Close the incognito window
    ASSERT_TRUE(incognito->RunCommand(IDC_CLOSE_WINDOW));
    ASSERT_TRUE(automation()->GetBrowserWindowCount(&window_count));
    ASSERT_EQ(1, window_count);

    ASSERT_STREQ(kTestCompleteSuccess, value.c_str());
  }

  bool WaitForProcessCountToBe(int tabs, int workers) {
    // The 1 is for the browser process.
    int number_of_processes = 1 + workers +
        (UITest::in_process_renderer() ? 0 : tabs);
#if defined(OS_LINUX)
    // On Linux, we also have a zygote process and a sandbox host process.
    number_of_processes += 2;
#endif

    int cur_process_count;
    for (int i = 0; i < 10; ++i) {
      cur_process_count = GetBrowserProcessCount();
      if (cur_process_count == number_of_processes)
        return true;

      PlatformThread::Sleep(sleep_timeout_ms() / 10);
    }

    EXPECT_EQ(number_of_processes, cur_process_count);
    return false;
  }
};

TEST_F(WorkerTest, SingleWorker) {
  RunTest(L"single_worker.html");
}

#if defined(OS_LINUX)
// MultipleWorkers times out (process hangs, does not exit) occasionally.
// http://crbug.com/30353
#define MultipleWorkers DISABLED_MultipleWorkers
#endif

TEST_F(WorkerTest, MultipleWorkers) {
  RunTest(L"multi_worker.html");
}

TEST_F(WorkerTest, SingleSharedWorker) {
  RunTest(L"single_worker.html?shared=true");
}

TEST_F(WorkerTest, MultipleSharedWorkers) {
  RunTest(L"multi_worker.html?shared=true");
}

#if defined(OS_LINUX)
#define IncognitoSharedWorkers FLAKY_IncognitoSharedWorkers
#endif

// Incognito windows should not share workers with non-incognito windows
TEST_F(WorkerTest, IncognitoSharedWorkers) {
  // Load a non-incognito tab and have it create a shared worker
  RunTest(L"incognito_worker.html");
  // Incognito worker should not share with non-incognito
  RunIncognitoTest(L"incognito_worker.html");
}

#if defined(OS_LINUX)
// Crashes on Linux - http://crbug.com/22898
#define WorkerFastLayoutTests DISABLED_WorkerFastLayoutTests
#elif defined (OS_MACOSX)
#define WorkerFastLayoutTests FLAKY_WorkerFastLayoutTests
#endif

TEST_F(WorkerTest, WorkerFastLayoutTests) {
  static const char* kLayoutTestFiles[] = {
    "stress-js-execution.html",
    "use-machine-stack.html",
    "worker-call.html",
#if defined(OS_WIN)
    // This test occasionally fails on valgrind (http://crbug.com/30212).
    "worker-cloneport.html",
#endif
    "worker-close.html",
    "worker-constructor.html",
    "worker-context-gc.html",
    "worker-context-multi-port.html",
    "worker-event-listener.html",
    "worker-gc.html",
    // worker-lifecycle.html relies on layoutTestController.workerThreadCount
    // which is not currently implemented.
    // "worker-lifecycle.html",
    "worker-location.html",
    "worker-messageport.html",
    // Disabled after r27089 (WebKit merge), http://crbug.com/22947
    // "worker-messageport-gc.html",
    "worker-multi-port.html",
    "worker-navigator.html",
    "worker-replace-global-constructor.html",
    "worker-replace-self.html",
    "worker-script-error.html",
    "worker-terminate.html",
    "worker-timeout.html"
  };

  FilePath fast_test_dir;
  fast_test_dir = fast_test_dir.AppendASCII("LayoutTests");
  fast_test_dir = fast_test_dir.AppendASCII("fast");

  FilePath worker_test_dir;
  worker_test_dir = worker_test_dir.AppendASCII("workers");
  InitializeForLayoutTest(fast_test_dir, worker_test_dir, false);

  // Worker tests also rely on common files in js/resources.
  FilePath js_dir = fast_test_dir.AppendASCII("js");
  FilePath resource_dir;
  resource_dir = resource_dir.AppendASCII("resources");
  AddResourceForLayoutTest(js_dir, resource_dir);

  for (size_t i = 0; i < arraysize(kLayoutTestFiles); ++i)
    RunLayoutTest(kLayoutTestFiles[i], false);

  // Navigate away from to a blank page so that any workers are cleaned up. This
  // helps leaks trackers do a better job of reporting.
  scoped_refptr<TabProxy> tab(GetActiveTab());
  GURL about_url(std::string("file://localhost/"));
  ASSERT_EQ(AUTOMATION_MSG_NAVIGATION_SUCCESS, tab->NavigateToURL(about_url));
}

#if defined(OS_WIN) || defined(OS_MACOSX)
// http://crbug.com/27636 - incorrect URL_MISMATCH exceptions sometimes get
// generated on the windows try bots.
// http://crbug.com/28445 - flakiness on mac
#define SharedWorkerFastLayoutTests FLAKY_SharedWorkerFastLayoutTests
#endif

TEST_F(WorkerTest, SharedWorkerFastLayoutTests) {
  static const char* kLayoutTestFiles[] = {
    "shared-worker-constructor.html",
    "shared-worker-context-gc.html",
    "shared-worker-event-listener.html",
    "shared-worker-exception.html",
    "shared-worker-gc.html",
    // Lifecycle tests rely on layoutTestController.workerThreadCount which is
    // not currently implemented.
    //"shared-worker-frame-lifecycle.html",
    //"shared-worker-lifecycle.html",
    "shared-worker-load-error.html",
    "shared-worker-location.html",
    "shared-worker-name.html",
    "shared-worker-navigator.html",
    "shared-worker-replace-global-constructor.html",
    "shared-worker-replace-self.html",
    "shared-worker-script-error.html",
    "shared-worker-shared.html",
    "shared-worker-simple.html",
  };

  FilePath fast_test_dir;
  fast_test_dir = fast_test_dir.AppendASCII("LayoutTests");
  fast_test_dir = fast_test_dir.AppendASCII("fast");

  FilePath worker_test_dir;
  worker_test_dir = worker_test_dir.AppendASCII("workers");
  InitializeForLayoutTest(fast_test_dir, worker_test_dir, false);

  // Worker tests also rely on common files in js/resources.
  FilePath js_dir = fast_test_dir.AppendASCII("js");
  FilePath resource_dir;
  resource_dir = resource_dir.AppendASCII("resources");
  AddResourceForLayoutTest(js_dir, resource_dir);

  for (size_t i = 0; i < arraysize(kLayoutTestFiles); ++i) {
    RunLayoutTest(kLayoutTestFiles[i], false);
    // Shared workers will error out if we ever have more than one tab open.
    int window_count = 0;
    ASSERT_TRUE(automation()->GetBrowserWindowCount(&window_count));
    ASSERT_EQ(1, window_count);
    EXPECT_EQ(1, GetTabCount());
  }
}

TEST_F(WorkerTest, WorkerHttpLayoutTests) {
  static const char* kLayoutTestFiles[] = {
    "shared-worker-importScripts.html",
    "shared-worker-redirect.html",
    // flakey? BUG 16934 "text-encoding.html",
#if defined(OS_WIN)
    // Fails on the mac (and linux?):
    // http://code.google.com/p/chromium/issues/detail?id=22599
    "worker-importScripts.html",
#endif
    "worker-redirect.html",
  };

  FilePath http_test_dir;
  http_test_dir = http_test_dir.AppendASCII("LayoutTests");
  http_test_dir = http_test_dir.AppendASCII("http");
  http_test_dir = http_test_dir.AppendASCII("tests");

  FilePath worker_test_dir;
  worker_test_dir = worker_test_dir.AppendASCII("workers");
  InitializeForLayoutTest(http_test_dir, worker_test_dir, true);

  StartHttpServer(new_http_root_dir_);
  for (size_t i = 0; i < arraysize(kLayoutTestFiles); ++i)
    RunLayoutTest(kLayoutTestFiles[i], true);
  StopHttpServer();
}

TEST_F(WorkerTest, WorkerXhrHttpLayoutTests) {
  static const char* kLayoutTestFiles[] = {
    "abort-exception-assert.html",
#if defined(OS_WIN)
    // Fails on the mac (and linux?):
    // http://code.google.com/p/chromium/issues/detail?id=22599
    "close.html",
#endif
    // These tests (and the shared-worker versions below) are disabled due to
    // limitations in lighttpd (doesn't handle all of the HTTP methods).
    //"methods-async.html",
    //"methods.html",

    "shared-worker-close.html",
    // Disabled due to limitations in lighttpd (does not handle methods other
    // than GET/PUT/POST).
    //"shared-worker-methods-async.html",
    //"shared-worker-methods.html",
    "shared-worker-xhr-file-not-found.html",

    "xmlhttprequest-file-not-found.html"
  };

  FilePath http_test_dir;
  http_test_dir = http_test_dir.AppendASCII("LayoutTests");
  http_test_dir = http_test_dir.AppendASCII("http");
  http_test_dir = http_test_dir.AppendASCII("tests");

  FilePath worker_test_dir;
  worker_test_dir = worker_test_dir.AppendASCII("xmlhttprequest");
  worker_test_dir = worker_test_dir.AppendASCII("workers");
  InitializeForLayoutTest(http_test_dir, worker_test_dir, true);

  StartHttpServer(new_http_root_dir_);
  for (size_t i = 0; i < arraysize(kLayoutTestFiles); ++i)
    RunLayoutTest(kLayoutTestFiles[i], true);
  StopHttpServer();
}

TEST_F(WorkerTest, MessagePorts) {
  static const char* kLayoutTestFiles[] = {
    "message-channel-gc.html",
    "message-channel-gc-2.html",
    "message-channel-gc-3.html",
    "message-channel-gc-4.html",
    "message-port.html",
    "message-port-clone.html",
    "message-port-constructor-for-deleted-document.html",
    "message-port-deleted-document.html",
    "message-port-deleted-frame.html",
    "message-port-inactive-document.html",
    "message-port-multi.html",
    "message-port-no-wrapper.html",
    // Only works with run-webkit-tests --leaks.
    //"message-channel-listener-circular-ownership.html",
  };

  FilePath fast_test_dir;
  fast_test_dir = fast_test_dir.AppendASCII("LayoutTests");
  fast_test_dir = fast_test_dir.AppendASCII("fast");

  FilePath worker_test_dir;
  worker_test_dir = worker_test_dir.AppendASCII("events");
  InitializeForLayoutTest(fast_test_dir, worker_test_dir, false);

  // MessagePort tests also rely on common files in js/resources.
  FilePath js_dir = fast_test_dir.AppendASCII("js");
  FilePath resource_dir;
  resource_dir = resource_dir.AppendASCII("resources");
  AddResourceForLayoutTest(js_dir, resource_dir);

  for (size_t i = 0; i < arraysize(kLayoutTestFiles); ++i)
    RunLayoutTest(kLayoutTestFiles[i], false);
}

TEST_F(WorkerTest, LimitPerPage) {
  int max_workers_per_tab = WorkerService::kMaxWorkersPerTabWhenSeparate;
  GURL url = GetTestUrl(L"workers", L"many_workers.html");
  url = GURL(url.spec() + StringPrintf("?count=%d", max_workers_per_tab + 1));

  scoped_refptr<TabProxy> tab(GetActiveTab());
  ASSERT_TRUE(tab.get());
  ASSERT_TRUE(tab->NavigateToURL(url));

  ASSERT_TRUE(WaitForProcessCountToBe(1, max_workers_per_tab));
}

#if defined(OS_LINUX) || defined(OS_MACOSX)
// Doesn't crash, but on Mac it sometimes fails for a few runs in a row,
// http://crbug.com/28445
#define LimitTotal FLAKY_LimitTotal
#endif

TEST_F(WorkerTest, LimitTotal) {
#if !defined(OS_LINUX)
  int max_workers_per_tab = WorkerService::kMaxWorkersPerTabWhenSeparate;
  int total_workers = WorkerService::kMaxWorkersWhenSeparate;

  int tab_count = (total_workers / max_workers_per_tab) + 1;
  GURL url = GetTestUrl(L"workers", L"many_workers.html");
  url = GURL(url.spec() + StringPrintf("?count=%d", max_workers_per_tab));

  scoped_refptr<TabProxy> tab(GetActiveTab());
  ASSERT_TRUE(tab.get());
  ASSERT_TRUE(tab->NavigateToURL(url));
  scoped_refptr<BrowserProxy> window(automation()->GetBrowserWindow(0));
  for (int i = 1; i < tab_count; ++i)
    window->AppendTab(url);

  // Check that we didn't create more than the max number of workers.
  ASSERT_TRUE(WaitForProcessCountToBe(tab_count, total_workers));

  // Now close a page and check that the queued workers were started.
  tab->NavigateToURL(GetTestUrl(L"google", L"google.html"));

  ASSERT_TRUE(WaitForProcessCountToBe(tab_count, total_workers));
#endif
}
<commit_msg>Mark WorkerTest.LimitPerPage as flaky on Linux.<commit_after>// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/string_util.h"
#include "chrome/app/chrome_dll_resource.h"
#include "chrome/browser/worker_host/worker_service.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/test/automation/browser_proxy.h"
#include "chrome/test/automation/tab_proxy.h"
#include "chrome/test/ui/ui_layout_test.h"

static const char kTestCompleteCookie[] = "status";
static const char kTestCompleteSuccess[] = "OK";

class WorkerTest : public UILayoutTest {
 protected:
  virtual ~WorkerTest() { }

  void RunTest(const std::wstring& test_case) {
    scoped_refptr<TabProxy> tab(GetActiveTab());
    ASSERT_TRUE(tab.get());

    GURL url = GetTestUrl(L"workers", test_case);
    ASSERT_TRUE(tab->NavigateToURL(url));

    std::string value = WaitUntilCookieNonEmpty(tab.get(), url,
        kTestCompleteCookie, kTestIntervalMs, kTestWaitTimeoutMs);
    ASSERT_STREQ(kTestCompleteSuccess, value.c_str());
  }

  void RunIncognitoTest(const std::wstring& test_case) {
    scoped_refptr<BrowserProxy> browser(automation()->GetBrowserWindow(0));
    // Open an Incognito window.
    int window_count;
    ASSERT_TRUE(browser->RunCommand(IDC_NEW_INCOGNITO_WINDOW));
    scoped_refptr<BrowserProxy> incognito(automation()->GetBrowserWindow(1));
    scoped_refptr<TabProxy> tab(incognito->GetTab(0));
    ASSERT_TRUE(automation()->GetBrowserWindowCount(&window_count));
    ASSERT_EQ(2, window_count);

    GURL url = GetTestUrl(L"workers", test_case);
    ASSERT_TRUE(tab->NavigateToURL(url));

    std::string value = WaitUntilCookieNonEmpty(tab.get(), url,
        kTestCompleteCookie, kTestIntervalMs, kTestWaitTimeoutMs);

    // Close the incognito window
    ASSERT_TRUE(incognito->RunCommand(IDC_CLOSE_WINDOW));
    ASSERT_TRUE(automation()->GetBrowserWindowCount(&window_count));
    ASSERT_EQ(1, window_count);

    ASSERT_STREQ(kTestCompleteSuccess, value.c_str());
  }

  bool WaitForProcessCountToBe(int tabs, int workers) {
    // The 1 is for the browser process.
    int number_of_processes = 1 + workers +
        (UITest::in_process_renderer() ? 0 : tabs);
#if defined(OS_LINUX)
    // On Linux, we also have a zygote process and a sandbox host process.
    number_of_processes += 2;
#endif

    int cur_process_count;
    for (int i = 0; i < 10; ++i) {
      cur_process_count = GetBrowserProcessCount();
      if (cur_process_count == number_of_processes)
        return true;

      PlatformThread::Sleep(sleep_timeout_ms() / 10);
    }

    EXPECT_EQ(number_of_processes, cur_process_count);
    return false;
  }
};

TEST_F(WorkerTest, SingleWorker) {
  RunTest(L"single_worker.html");
}

#if defined(OS_LINUX)
// MultipleWorkers times out (process hangs, does not exit) occasionally.
// http://crbug.com/30353
#define MultipleWorkers DISABLED_MultipleWorkers
#endif

TEST_F(WorkerTest, MultipleWorkers) {
  RunTest(L"multi_worker.html");
}

TEST_F(WorkerTest, SingleSharedWorker) {
  RunTest(L"single_worker.html?shared=true");
}

TEST_F(WorkerTest, MultipleSharedWorkers) {
  RunTest(L"multi_worker.html?shared=true");
}

#if defined(OS_LINUX)
#define IncognitoSharedWorkers FLAKY_IncognitoSharedWorkers
#endif

// Incognito windows should not share workers with non-incognito windows
TEST_F(WorkerTest, IncognitoSharedWorkers) {
  // Load a non-incognito tab and have it create a shared worker
  RunTest(L"incognito_worker.html");
  // Incognito worker should not share with non-incognito
  RunIncognitoTest(L"incognito_worker.html");
}

#if defined(OS_LINUX)
// Crashes on Linux - http://crbug.com/22898
#define WorkerFastLayoutTests DISABLED_WorkerFastLayoutTests
#elif defined (OS_MACOSX)
#define WorkerFastLayoutTests FLAKY_WorkerFastLayoutTests
#endif

TEST_F(WorkerTest, WorkerFastLayoutTests) {
  static const char* kLayoutTestFiles[] = {
    "stress-js-execution.html",
    "use-machine-stack.html",
    "worker-call.html",
#if defined(OS_WIN)
    // This test occasionally fails on valgrind (http://crbug.com/30212).
    "worker-cloneport.html",
#endif
    "worker-close.html",
    "worker-constructor.html",
    "worker-context-gc.html",
    "worker-context-multi-port.html",
    "worker-event-listener.html",
    "worker-gc.html",
    // worker-lifecycle.html relies on layoutTestController.workerThreadCount
    // which is not currently implemented.
    // "worker-lifecycle.html",
    "worker-location.html",
    "worker-messageport.html",
    // Disabled after r27089 (WebKit merge), http://crbug.com/22947
    // "worker-messageport-gc.html",
    "worker-multi-port.html",
    "worker-navigator.html",
    "worker-replace-global-constructor.html",
    "worker-replace-self.html",
    "worker-script-error.html",
    "worker-terminate.html",
    "worker-timeout.html"
  };

  FilePath fast_test_dir;
  fast_test_dir = fast_test_dir.AppendASCII("LayoutTests");
  fast_test_dir = fast_test_dir.AppendASCII("fast");

  FilePath worker_test_dir;
  worker_test_dir = worker_test_dir.AppendASCII("workers");
  InitializeForLayoutTest(fast_test_dir, worker_test_dir, false);

  // Worker tests also rely on common files in js/resources.
  FilePath js_dir = fast_test_dir.AppendASCII("js");
  FilePath resource_dir;
  resource_dir = resource_dir.AppendASCII("resources");
  AddResourceForLayoutTest(js_dir, resource_dir);

  for (size_t i = 0; i < arraysize(kLayoutTestFiles); ++i)
    RunLayoutTest(kLayoutTestFiles[i], false);

  // Navigate away from to a blank page so that any workers are cleaned up. This
  // helps leaks trackers do a better job of reporting.
  scoped_refptr<TabProxy> tab(GetActiveTab());
  GURL about_url(std::string("file://localhost/"));
  ASSERT_EQ(AUTOMATION_MSG_NAVIGATION_SUCCESS, tab->NavigateToURL(about_url));
}

#if defined(OS_WIN) || defined(OS_MACOSX)
// http://crbug.com/27636 - incorrect URL_MISMATCH exceptions sometimes get
// generated on the windows try bots.
// http://crbug.com/28445 - flakiness on mac
#define SharedWorkerFastLayoutTests FLAKY_SharedWorkerFastLayoutTests
#endif

TEST_F(WorkerTest, SharedWorkerFastLayoutTests) {
  static const char* kLayoutTestFiles[] = {
    "shared-worker-constructor.html",
    "shared-worker-context-gc.html",
    "shared-worker-event-listener.html",
    "shared-worker-exception.html",
    "shared-worker-gc.html",
    // Lifecycle tests rely on layoutTestController.workerThreadCount which is
    // not currently implemented.
    //"shared-worker-frame-lifecycle.html",
    //"shared-worker-lifecycle.html",
    "shared-worker-load-error.html",
    "shared-worker-location.html",
    "shared-worker-name.html",
    "shared-worker-navigator.html",
    "shared-worker-replace-global-constructor.html",
    "shared-worker-replace-self.html",
    "shared-worker-script-error.html",
    "shared-worker-shared.html",
    "shared-worker-simple.html",
  };

  FilePath fast_test_dir;
  fast_test_dir = fast_test_dir.AppendASCII("LayoutTests");
  fast_test_dir = fast_test_dir.AppendASCII("fast");

  FilePath worker_test_dir;
  worker_test_dir = worker_test_dir.AppendASCII("workers");
  InitializeForLayoutTest(fast_test_dir, worker_test_dir, false);

  // Worker tests also rely on common files in js/resources.
  FilePath js_dir = fast_test_dir.AppendASCII("js");
  FilePath resource_dir;
  resource_dir = resource_dir.AppendASCII("resources");
  AddResourceForLayoutTest(js_dir, resource_dir);

  for (size_t i = 0; i < arraysize(kLayoutTestFiles); ++i) {
    RunLayoutTest(kLayoutTestFiles[i], false);
    // Shared workers will error out if we ever have more than one tab open.
    int window_count = 0;
    ASSERT_TRUE(automation()->GetBrowserWindowCount(&window_count));
    ASSERT_EQ(1, window_count);
    EXPECT_EQ(1, GetTabCount());
  }
}

TEST_F(WorkerTest, WorkerHttpLayoutTests) {
  static const char* kLayoutTestFiles[] = {
    "shared-worker-importScripts.html",
    "shared-worker-redirect.html",
    // flakey? BUG 16934 "text-encoding.html",
#if defined(OS_WIN)
    // Fails on the mac (and linux?):
    // http://code.google.com/p/chromium/issues/detail?id=22599
    "worker-importScripts.html",
#endif
    "worker-redirect.html",
  };

  FilePath http_test_dir;
  http_test_dir = http_test_dir.AppendASCII("LayoutTests");
  http_test_dir = http_test_dir.AppendASCII("http");
  http_test_dir = http_test_dir.AppendASCII("tests");

  FilePath worker_test_dir;
  worker_test_dir = worker_test_dir.AppendASCII("workers");
  InitializeForLayoutTest(http_test_dir, worker_test_dir, true);

  StartHttpServer(new_http_root_dir_);
  for (size_t i = 0; i < arraysize(kLayoutTestFiles); ++i)
    RunLayoutTest(kLayoutTestFiles[i], true);
  StopHttpServer();
}

TEST_F(WorkerTest, WorkerXhrHttpLayoutTests) {
  static const char* kLayoutTestFiles[] = {
    "abort-exception-assert.html",
#if defined(OS_WIN)
    // Fails on the mac (and linux?):
    // http://code.google.com/p/chromium/issues/detail?id=22599
    "close.html",
#endif
    // These tests (and the shared-worker versions below) are disabled due to
    // limitations in lighttpd (doesn't handle all of the HTTP methods).
    //"methods-async.html",
    //"methods.html",

    "shared-worker-close.html",
    // Disabled due to limitations in lighttpd (does not handle methods other
    // than GET/PUT/POST).
    //"shared-worker-methods-async.html",
    //"shared-worker-methods.html",
    "shared-worker-xhr-file-not-found.html",

    "xmlhttprequest-file-not-found.html"
  };

  FilePath http_test_dir;
  http_test_dir = http_test_dir.AppendASCII("LayoutTests");
  http_test_dir = http_test_dir.AppendASCII("http");
  http_test_dir = http_test_dir.AppendASCII("tests");

  FilePath worker_test_dir;
  worker_test_dir = worker_test_dir.AppendASCII("xmlhttprequest");
  worker_test_dir = worker_test_dir.AppendASCII("workers");
  InitializeForLayoutTest(http_test_dir, worker_test_dir, true);

  StartHttpServer(new_http_root_dir_);
  for (size_t i = 0; i < arraysize(kLayoutTestFiles); ++i)
    RunLayoutTest(kLayoutTestFiles[i], true);
  StopHttpServer();
}

TEST_F(WorkerTest, MessagePorts) {
  static const char* kLayoutTestFiles[] = {
    "message-channel-gc.html",
    "message-channel-gc-2.html",
    "message-channel-gc-3.html",
    "message-channel-gc-4.html",
    "message-port.html",
    "message-port-clone.html",
    "message-port-constructor-for-deleted-document.html",
    "message-port-deleted-document.html",
    "message-port-deleted-frame.html",
    "message-port-inactive-document.html",
    "message-port-multi.html",
    "message-port-no-wrapper.html",
    // Only works with run-webkit-tests --leaks.
    //"message-channel-listener-circular-ownership.html",
  };

  FilePath fast_test_dir;
  fast_test_dir = fast_test_dir.AppendASCII("LayoutTests");
  fast_test_dir = fast_test_dir.AppendASCII("fast");

  FilePath worker_test_dir;
  worker_test_dir = worker_test_dir.AppendASCII("events");
  InitializeForLayoutTest(fast_test_dir, worker_test_dir, false);

  // MessagePort tests also rely on common files in js/resources.
  FilePath js_dir = fast_test_dir.AppendASCII("js");
  FilePath resource_dir;
  resource_dir = resource_dir.AppendASCII("resources");
  AddResourceForLayoutTest(js_dir, resource_dir);

  for (size_t i = 0; i < arraysize(kLayoutTestFiles); ++i)
    RunLayoutTest(kLayoutTestFiles[i], false);
}

#if defined(OS_LINUX)
// http://crbug.com/30307
#define LimitPerPage FLAKY_LimitPerPage
#endif

TEST_F(WorkerTest, LimitPerPage) {
  int max_workers_per_tab = WorkerService::kMaxWorkersPerTabWhenSeparate;
  GURL url = GetTestUrl(L"workers", L"many_workers.html");
  url = GURL(url.spec() + StringPrintf("?count=%d", max_workers_per_tab + 1));

  scoped_refptr<TabProxy> tab(GetActiveTab());
  ASSERT_TRUE(tab.get());
  ASSERT_TRUE(tab->NavigateToURL(url));

  ASSERT_TRUE(WaitForProcessCountToBe(1, max_workers_per_tab));
}

#if defined(OS_LINUX) || defined(OS_MACOSX)
// Doesn't crash, but on Mac it sometimes fails for a few runs in a row,
// http://crbug.com/28445
#define LimitTotal FLAKY_LimitTotal
#endif

TEST_F(WorkerTest, LimitTotal) {
#if !defined(OS_LINUX)
  int max_workers_per_tab = WorkerService::kMaxWorkersPerTabWhenSeparate;
  int total_workers = WorkerService::kMaxWorkersWhenSeparate;

  int tab_count = (total_workers / max_workers_per_tab) + 1;
  GURL url = GetTestUrl(L"workers", L"many_workers.html");
  url = GURL(url.spec() + StringPrintf("?count=%d", max_workers_per_tab));

  scoped_refptr<TabProxy> tab(GetActiveTab());
  ASSERT_TRUE(tab.get());
  ASSERT_TRUE(tab->NavigateToURL(url));
  scoped_refptr<BrowserProxy> window(automation()->GetBrowserWindow(0));
  for (int i = 1; i < tab_count; ++i)
    window->AppendTab(url);

  // Check that we didn't create more than the max number of workers.
  ASSERT_TRUE(WaitForProcessCountToBe(tab_count, total_workers));

  // Now close a page and check that the queued workers were started.
  tab->NavigateToURL(GetTestUrl(L"google", L"google.html"));

  ASSERT_TRUE(WaitForProcessCountToBe(tab_count, total_workers));
#endif
}
<|endoftext|>


<commit_before>/* Copyright (C) 2010- Imperial College London and others.

   Please see the AUTHORS file in the main source directory for a full
   list of copyright holders.

   Dr Gerard J Gorman
   Applied Modelling and Computation Group
   Department of Earth Science and Engineering
   Imperial College London

   g.gorman@imperial.ac.uk

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public
   License as published by the Free Software Foundation; either
   version 2.1 of the License.

   This library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Lesser General Public License for more details.

   You should have received a copy of the GNU Lesser General Public
   License along with this library; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
   USA
*/

#include "Profiler.h"

using namespace std;

Profiler::Profiler(){}

Profiler::~Profiler(){}

double Profiler::get(const std::string &key) const{
  double time = timings.find(key)->second.second;
  if(MPI::Is_initialized()){
    double gtime;
    MPI::COMM_WORLD.Reduce(&time, &gtime, 1, MPI::DOUBLE, MPI::MAX, 0);
    return gtime;
  }

  return time;
}

void Profiler::print() const{
  for(map< string, pair<double, double> >::const_iterator it=timings.begin();it!=timings.end();++it){
    cout<<it->first<<" :: "<<get(it->first)<<endl;
  }
}

void Profiler::tic(const std::string &key){
  timings[key].first = wall_time();
}

void Profiler::toc(const std::string &key){
  timings[key].second += wall_time() - timings[key].first;
}

double Profiler::wall_time() const{
#ifdef HAVE_MPI
  return MPI::Wtime();
#else
  return 0.0;
#endif
}

void Profiler::zero(){
  for(map< string, pair<double, double> >::iterator it=timings.begin();it!=timings.end();++it){
    it->second.second = 0.0;
  }
}

void Profiler::zero(const std::string &key){
  timings[key].second = 0.0;
}

// Opaque instance of profiler.
Profiler flprofiler;

// Fortran interface
extern "C" {
#define cprofiler_get_fc F77_FUNC(cprofiler_get, CPROFILER_GET)
  void cprofiler_get_fc(const char *key, const int *key_len, double *time){
    *time = flprofiler.get(string(key, *key_len));
  }

#define cprofiler_tic_fc F77_FUNC(cprofiler_tic, CPROFILER_TIC)
  void cprofiler_tic_fc(const char *key, const int *key_len){
    flprofiler.tic(string(key, *key_len));
  }

#define cprofiler_toc_fc F77_FUNC(cprofiler_toc, CPROFILER_TOC)
  void cprofiler_toc_fc(const char *key, const int *key_len){
    flprofiler.toc(string(key, *key_len));
  }

#define cprofiler_zero_fc F77_FUNC(cprofiler_zero, CPROFILER_ZERO)
  void cprofiler_zero_fc(){
    flprofiler.zero();
  }
}
<commit_msg>Ensure profiling info is only printed on rank 0<commit_after>/* Copyright (C) 2010- Imperial College London and others.

   Please see the AUTHORS file in the main source directory for a full
   list of copyright holders.

   Dr Gerard J Gorman
   Applied Modelling and Computation Group
   Department of Earth Science and Engineering
   Imperial College London

   g.gorman@imperial.ac.uk

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public
   License as published by the Free Software Foundation; either
   version 2.1 of the License.

   This library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Lesser General Public License for more details.

   You should have received a copy of the GNU Lesser General Public
   License along with this library; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
   USA
*/

#include "Profiler.h"

using namespace std;

Profiler::Profiler(){}

Profiler::~Profiler(){}

double Profiler::get(const std::string &key) const{
  double time = timings.find(key)->second.second;
  if(MPI::Is_initialized()){
    double gtime;
    MPI::COMM_WORLD.Reduce(&time, &gtime, 1, MPI::DOUBLE, MPI::MAX, 0);
    return gtime;
  }

  return time;
}

void Profiler::print() const{
  bool print;
  double val;
  print = !MPI::Is_initialized() || MPI::COMM_WORLD.Get_rank() == 0;
  for(map< string, pair<double, double> >::const_iterator it=timings.begin();it!=timings.end();++it){
    val = get(it->first);
    if ( print ) {
      cout<<it->first<<" :: "<<val<<endl;
    }
  }
}

void Profiler::tic(const std::string &key){
  timings[key].first = wall_time();
}

void Profiler::toc(const std::string &key){
  timings[key].second += wall_time() - timings[key].first;
}

double Profiler::wall_time() const{
#ifdef HAVE_MPI
  return MPI::Wtime();
#else
  return 0.0;
#endif
}

void Profiler::zero(){
  for(map< string, pair<double, double> >::iterator it=timings.begin();it!=timings.end();++it){
    it->second.second = 0.0;
  }
}

void Profiler::zero(const std::string &key){
  timings[key].second = 0.0;
}

// Opaque instance of profiler.
Profiler flprofiler;

// Fortran interface
extern "C" {
#define cprofiler_get_fc F77_FUNC(cprofiler_get, CPROFILER_GET)
  void cprofiler_get_fc(const char *key, const int *key_len, double *time){
    *time = flprofiler.get(string(key, *key_len));
  }

#define cprofiler_tic_fc F77_FUNC(cprofiler_tic, CPROFILER_TIC)
  void cprofiler_tic_fc(const char *key, const int *key_len){
    flprofiler.tic(string(key, *key_len));
  }

#define cprofiler_toc_fc F77_FUNC(cprofiler_toc, CPROFILER_TOC)
  void cprofiler_toc_fc(const char *key, const int *key_len){
    flprofiler.toc(string(key, *key_len));
  }

#define cprofiler_zero_fc F77_FUNC(cprofiler_zero, CPROFILER_ZERO)
  void cprofiler_zero_fc(){
    flprofiler.zero();
  }
}
<|endoftext|>


<commit_before>/*
TCP:
(PF_INET, PF_INET6), (SOCK_STREAM), (IPPROTO_TCP)
TCP Server:
1) Create a TCP socket
2) Bind socket to the listen port, with a call to bind()
3) Prepare socket to listen for connections with a call to listen()
4) Accepting incoming connections, via a call to accept()
5) Communicate with remote host, which can be done through, e.g., send()
6) Close each socket that was opened, once it is no longer needed, using close()

From http://stackoverflow.com/questions/6189831/whats-the-purpose-of-using-sendto-recvfrom-instead-of-connect-send-recv-with-ud:

It is important to understand that TCP is "Connection Oriented" and UDP is "Connection-less" protocol:

TCP: You need to connect first prior to sending/receiving data to/from a remote host.
UDP: No connection is required. You can send/receive data to/from any host.
Therefore, you will need to use sendto() on UDP socket in order to specify the destination. Similarly, you would want to use recvfrom() to know where the UDP data was received from.

You can actually use connect() on UDP socket as an option. In that case, you can use send()/recv() on the UDP socket to send data to the address specified with the connect() and to receive data only from the address. (The connect() on UDP socket merely sets the default peer address and you can call connect() on UDP socket as many times as you want, and the connect() on UDP socket, of course, does not perform any handshake for connection.)
*/

#include <cstring>
#include "allocore/io/al_Socket.hpp"
#include "allocore/system/al_Config.h"
#include "allocore/system/al_Printing.hpp"

#include "../private/al_ImplAPR.h"
#if defined(AL_LINUX)
#include "apr-1.0/apr_network_io.h"
#else
#include "apr-1/apr_network_io.h"
#endif

#define PRINT_SOCKADDR(s)\
	printf("%s %s\n", s->hostname, s->servname);

namespace al{

struct Socket::Impl : public ImplAPR {

	Impl()
	:	mPort(0), mAddress(""), mSockAddr(0), mSock(0), mTimeout(-1), mType(0)
	{}

	Impl(uint16_t port, const char * address, al_sec timeout_, int type)
	:	mPort(port), mAddress(address), mSockAddr(0), mSock(0), mTimeout(-1), mType(0)
	{
		// opens the socket also:
		if (! open(port, address, timeout_, type)) {
			AL_WARN("Socket::Impl failed to open port %d / address \"%s\"\n", port, address);
		}
	}

	void close(){
		if(opened()){
			check_apr(apr_socket_close(mSock));
			mSock=0;
		}
	}

	#define BAILONFAIL(func)\
		if(APR_SUCCESS != check_apr(func)){\
			AL_WARN("failed to create socket at %s:%i\n", address.c_str(), port);\
			close();\
			return false;\
		}

	bool open(uint16_t port, std::string address, al_sec timeoutSec, int type){
		close();

		mPort = port;
		mAddress = address;
		mType = type;

		int sockProto = type & 127;
		switch(sockProto){
		case TCP:  sockProto = APR_PROTO_TCP; break;
		case UDP:  sockProto = APR_PROTO_UDP; break;
		case SCTP: sockProto = APR_PROTO_SCTP; break;
		default:;
		}

		int sockType = type & (127<<8);
		switch(sockType){
		case STREAM: sockType = SOCK_STREAM; break;
		case DGRAM:  sockType = SOCK_DGRAM; break;
		case 0: // unspecified; choose sensible default, if possible
			switch(sockProto){
			case TCP:  sockType = SOCK_STREAM; break;
			case UDP:
			case SCTP: sockType = SOCK_DGRAM; break;
			default:;
			}
		}

		int sockFamily = type & (127<<16);
		switch(sockFamily){
		case 0: // unspecified
		case INET:  sockFamily = APR_INET; break;
		case INET6:
		#ifdef APR_INET6
			sockFamily = APR_INET6; break;
		#else
			AL_WARN("Socket::INET6 not supported on this platform.");
			return false;
		#endif
		default:;
		}

		/*
		The APR setup procedure is as follows:
		Client:
			apr_sockaddr_info_get
			apr_socket_create

			apr_socket_opt_set		| Set timeout for connect
			apr_socket_timeout_set	|

			apr_socket_connect

			apr_socket_opt_set		| Set timeout for send/recv
			apr_socket_timeout_set	|

		Server:
			apr_sockaddr_info_get
			apr_socket_create

			apr_socket_opt_set		| Set timeout for send/recv
			apr_socket_timeout_set	|

			apr_socket_bind			| These are always non-blocking calls
			apr_socket_listen		|

		@see http://dev.ariel-networks.com/apr/apr-tutorial/html/apr-tutorial-13.html
		*/

		BAILONFAIL(
			apr_sockaddr_info_get(
				&mSockAddr,
				mAddress[0] ? mAddress.c_str() : NULL, sockFamily, mPort, 0, mPool
			)
		);

		BAILONFAIL(
			apr_socket_create(&mSock, mSockAddr->family, sockType, sockProto, mPool)
		);

		// Set timeout
		timeout(timeoutSec);

		return true;
	}

	bool reopen(){
		return open(mPort, mAddress, mTimeout, mType);
	}

	bool bind(){ // for server-side
		if(opened()){
			apr_status_t res = check_apr(apr_socket_bind(mSock, mSockAddr));
			return APR_SUCCESS == res;
		}
		return false;
	}

	bool connect(){ // for client-side
		if(opened()){
			// The timeout works differently for a blocking-with-timeout connect
			if(mTimeout > 0){
				check_apr(apr_socket_opt_set(mSock, APR_SO_NONBLOCK, 1));
				check_apr(apr_socket_timeout_set(mSock, apr_interval_time_t(mTimeout * 1.0e6)));
			}

			apr_status_t res = check_apr(apr_socket_connect(mSock, mSockAddr));

			// Set timeout back to what it was if blocking-with-timeout
			if(mTimeout > 0){
				timeout(mTimeout);
			}

			return APR_SUCCESS == res;
		}
		return false;
	}

	void timeout(al_sec v){
		mTimeout = v;

		// Note: these timeouts apply only for send/recv and accept
		// Non-blocking:
		if(mTimeout == 0){
			check_apr(apr_socket_opt_set(mSock, APR_SO_NONBLOCK, 1));
			check_apr(apr_socket_timeout_set(mSock, 0));
		}

		// Blocking-with-timeout:
		else if(mTimeout > 0){
			#ifdef AL_WINDOWS
				check_apr(apr_socket_opt_set(mSock, APR_SO_NONBLOCK, 0));
			#else
				check_apr(apr_socket_opt_set(mSock, APR_SO_NONBLOCK, 1));
			#endif
			check_apr(apr_socket_timeout_set(mSock, apr_interval_time_t(mTimeout * 1.0e6)));
		}

		// Blocking-forever:
		else{
			check_apr(apr_socket_opt_set(mSock, APR_SO_NONBLOCK, 0));
			check_apr(apr_socket_timeout_set(mSock, -1));
		}
	}

	bool listen(){
		/* APR_SO_REUSEADDR is useful for a socket listening process.
		It specifies that the "The rules used in validating addresses supplied
		to bind should allow reuse of local addresses." */
		apr_socket_opt_set(mSock, APR_SO_REUSEADDR, 1);
		apr_status_t res = apr_socket_listen(mSock, SOMAXCONN);
		if(APR_SUCCESS != res){
			//AL_WARN("Failed to listen on socket");
			return false;
		}
		return true;
	}

	bool accept(Socket::Impl * newSock){
		newSock->close();
		// TODO: timeout for accept
		apr_status_t res = apr_socket_accept(&newSock->mSock, mSock, mPool);
		if(APR_SUCCESS != res){
			//AL_WARN("Failed to accept socket");
			return false;
		}
		// Inherit timeout from parent
		newSock->timeout(mTimeout);
		return true;
	}

	bool opened() const { return 0!=mSock; }

	uint16_t mPort;
	std::string mAddress;
	apr_sockaddr_t * mSockAddr;
	apr_socket_t * mSock;
	al_sec mTimeout;
	int mType;
};

Socket::Socket()
:	mImpl(new Impl)
{}

Socket::Socket(uint16_t port, const char * address, al_sec timeout, int type)
: mImpl(0)
{
	mImpl = new Impl(port, address, timeout, type);
	if (mImpl == 0) {
		AL_WARN("Socket::Socket(uint16_t, const char *, al_sec, bool): mImpl is zero!!!\n");
	}

}

Socket::~Socket(){
	close();
	delete mImpl;
}

const std::string& Socket::address() const { return mImpl->mAddress; }

bool Socket::opened() const { return mImpl->opened(); }

uint16_t Socket::port() const { return mImpl->mPort; }

al_sec Socket::timeout() const { return mImpl->mTimeout; }

bool Socket::bind(){ return mImpl->bind(); }

bool Socket::connect(){ return mImpl->connect(); }

void Socket::close(){ mImpl->close(); }

bool Socket::open(uint16_t port, const char * address, al_sec timeout, int type){
	return
		mImpl->open(port, address, timeout, type)
		&& onOpen();
}

void Socket::timeout(al_sec v){
	mImpl->timeout(v);
}

size_t Socket::recv(char * buffer, size_t maxlen) {
	apr_size_t len = maxlen;

	// printf("About to call apr_socket_recv(%p, %p, %d)\n", mImpl->mSock, buffer, len);

	apr_status_t r = apr_socket_recv(mImpl->mSock, buffer, &len);

	// printf("apr_socket_recv returned\n");

	// only error check if not error# 35: Resource temporarily unavailable
	if(len){ check_apr(r); }
	return len;
}

size_t Socket::send(const char * buffer, size_t len) {
	apr_size_t size = len;
	if (mImpl->opened()) {
		//check_apr(apr_socket_send(mSock, buffer, &size));
		apr_socket_send(mImpl->mSock, buffer, &size);
	} else {
		size = 0;
	}
	return size;
}

std::string Socket::hostIP(){
	ImplAPR apr;
	char * addr;
	apr_sockaddr_t * sa;
	check_apr(apr_sockaddr_info_get(&sa, hostName().c_str(), APR_INET, 8000, 0, apr.pool()));
	//printf("%p sa\n", sa);
	while(sa != 0) {
		check_apr(apr_sockaddr_ip_get(&addr, sa));
		//printf("%s %s %s %d %d\n", addr, sa->hostname, sa->servname, sa->port, sa->family);
		sa = sa->next;
	}
	return addr;
}

std::string Socket::hostName(){
	char buf[APRMAXHOSTLEN+1];
	ImplAPR apr;
	check_apr(apr_gethostname(buf, sizeof(buf), apr.pool()));
	//printf("host %s\n", buf);
	return buf;
}

bool Socket::listen(){
	return mImpl->listen();
}

bool Socket::accept(Socket& sock){
	return mImpl->accept(sock.mImpl);
}

bool SocketClient::onOpen(){
	return connect();
}

bool SocketServer::onOpen(){
	return bind();
}

} // al::
<commit_msg>Socket: add proper APR_UNSPEC family support<commit_after>/*
TCP:
(PF_INET, PF_INET6), (SOCK_STREAM), (IPPROTO_TCP)
TCP Server:
1) Create a TCP socket
2) Bind socket to the listen port, with a call to bind()
3) Prepare socket to listen for connections with a call to listen()
4) Accepting incoming connections, via a call to accept()
5) Communicate with remote host, which can be done through, e.g., send()
6) Close each socket that was opened, once it is no longer needed, using close()

From http://stackoverflow.com/questions/6189831/whats-the-purpose-of-using-sendto-recvfrom-instead-of-connect-send-recv-with-ud:

It is important to understand that TCP is "Connection Oriented" and UDP is "Connection-less" protocol:

TCP: You need to connect first prior to sending/receiving data to/from a remote host.
UDP: No connection is required. You can send/receive data to/from any host.
Therefore, you will need to use sendto() on UDP socket in order to specify the destination. Similarly, you would want to use recvfrom() to know where the UDP data was received from.

You can actually use connect() on UDP socket as an option. In that case, you can use send()/recv() on the UDP socket to send data to the address specified with the connect() and to receive data only from the address. (The connect() on UDP socket merely sets the default peer address and you can call connect() on UDP socket as many times as you want, and the connect() on UDP socket, of course, does not perform any handshake for connection.)
*/

#include <cstring>
#include "allocore/io/al_Socket.hpp"
#include "allocore/system/al_Config.h"
#include "allocore/system/al_Printing.hpp"

#include "../private/al_ImplAPR.h"
#if defined(AL_LINUX)
#include "apr-1.0/apr_network_io.h"
#else
#include "apr-1/apr_network_io.h"
#endif

#define PRINT_SOCKADDR(s)\
	printf("%s %s\n", s->hostname, s->servname);

namespace al{

struct Socket::Impl : public ImplAPR {

	Impl()
	:	mPort(0), mAddress(""), mSockAddr(0), mSock(0), mTimeout(-1), mType(0)
	{}

	Impl(uint16_t port, const char * address, al_sec timeout_, int type)
	:	mPort(port), mAddress(address), mSockAddr(0), mSock(0), mTimeout(-1), mType(0)
	{
		// opens the socket also:
		if (! open(port, address, timeout_, type)) {
			AL_WARN("Socket::Impl failed to open port %d / address \"%s\"\n", port, address);
		}
	}

	void close(){
		if(opened()){
			check_apr(apr_socket_close(mSock));
			mSock=0;
		}
	}

	#define BAILONFAIL(func)\
		if(APR_SUCCESS != check_apr(func)){\
			AL_WARN("failed to create socket at %s:%i\n", address.c_str(), port);\
			close();\
			return false;\
		}

	bool open(uint16_t port, std::string address, al_sec timeoutSec, int type){
		close();

		mPort = port;
		mAddress = address;
		mType = type;

		int sockProto = type & 127;
		switch(sockProto){
		case TCP:  sockProto = APR_PROTO_TCP; break;
		case UDP:  sockProto = APR_PROTO_UDP; break;
		case SCTP: sockProto = APR_PROTO_SCTP; break;
		default:;
		}

		int sockType = type & (127<<8);
		switch(sockType){
		case STREAM: sockType = SOCK_STREAM; break;
		case DGRAM:  sockType = SOCK_DGRAM; break;
		case 0: // unspecified; choose sensible default, if possible
			switch(sockProto){
			case TCP:  sockType = SOCK_STREAM; break;
			case UDP:
			case SCTP: sockType = SOCK_DGRAM; break;
			default:;
			}
		}

		int sockFamily = type & (127<<16);
		switch(sockFamily){
		case 0: 	sockFamily = APR_UNSPEC; break;
		case INET:  sockFamily = APR_INET; break;
		case INET6:
		#ifdef APR_INET6
			sockFamily = APR_INET6; break;
		#else
			AL_WARN("Socket::INET6 not supported on this platform.");
			return false;
		#endif
		default:;
		}

		/*
		The APR setup procedure is as follows:
		Client:
			apr_sockaddr_info_get
			apr_socket_create

			apr_socket_opt_set		| Set timeout for connect
			apr_socket_timeout_set	|

			apr_socket_connect

			apr_socket_opt_set		| Set timeout for send/recv
			apr_socket_timeout_set	|

		Server:
			apr_sockaddr_info_get
			apr_socket_create

			apr_socket_opt_set		| Set timeout for send/recv
			apr_socket_timeout_set	|

			apr_socket_bind			| These are always non-blocking calls
			apr_socket_listen		|

		@see http://dev.ariel-networks.com/apr/apr-tutorial/html/apr-tutorial-13.html
		*/

		BAILONFAIL(
			apr_sockaddr_info_get(
				&mSockAddr,
				mAddress[0] ? mAddress.c_str() : NULL, sockFamily, mPort, 0, mPool
			)
		);

		BAILONFAIL(
			apr_socket_create(&mSock, mSockAddr->family, sockType, sockProto, mPool)
		);

		// Set timeout
		timeout(timeoutSec);

		return true;
	}

	bool reopen(){
		return open(mPort, mAddress, mTimeout, mType);
	}

	bool bind(){ // for server-side
		if(opened()){
			apr_status_t res = check_apr(apr_socket_bind(mSock, mSockAddr));
			return APR_SUCCESS == res;
		}
		return false;
	}

	bool connect(){ // for client-side
		if(opened()){
			// The timeout works differently for a blocking-with-timeout connect
			if(mTimeout > 0){
				check_apr(apr_socket_opt_set(mSock, APR_SO_NONBLOCK, 1));
				check_apr(apr_socket_timeout_set(mSock, apr_interval_time_t(mTimeout * 1.0e6)));
			}

			apr_status_t res = check_apr(apr_socket_connect(mSock, mSockAddr));

			// Set timeout back to what it was if blocking-with-timeout
			if(mTimeout > 0){
				timeout(mTimeout);
			}

			return APR_SUCCESS == res;
		}
		return false;
	}

	void timeout(al_sec v){
		mTimeout = v;

		// Note: these timeouts apply only for send/recv and accept
		// Non-blocking:
		if(mTimeout == 0){
			check_apr(apr_socket_opt_set(mSock, APR_SO_NONBLOCK, 1));
			check_apr(apr_socket_timeout_set(mSock, 0));
		}

		// Blocking-with-timeout:
		else if(mTimeout > 0){
			#ifdef AL_WINDOWS
				check_apr(apr_socket_opt_set(mSock, APR_SO_NONBLOCK, 0));
			#else
				check_apr(apr_socket_opt_set(mSock, APR_SO_NONBLOCK, 1));
			#endif
			check_apr(apr_socket_timeout_set(mSock, apr_interval_time_t(mTimeout * 1.0e6)));
		}

		// Blocking-forever:
		else{
			check_apr(apr_socket_opt_set(mSock, APR_SO_NONBLOCK, 0));
			check_apr(apr_socket_timeout_set(mSock, -1));
		}
	}

	bool listen(){
		/* APR_SO_REUSEADDR is useful for a socket listening process.
		It specifies that the "The rules used in validating addresses supplied
		to bind should allow reuse of local addresses." */
		apr_socket_opt_set(mSock, APR_SO_REUSEADDR, 1);
		apr_status_t res = apr_socket_listen(mSock, SOMAXCONN);
		if(APR_SUCCESS != res){
			//AL_WARN("Failed to listen on socket");
			return false;
		}
		return true;
	}

	bool accept(Socket::Impl * newSock){
		newSock->close();
		// TODO: timeout for accept
		apr_status_t res = apr_socket_accept(&newSock->mSock, mSock, mPool);
		if(APR_SUCCESS != res){
			//AL_WARN("Failed to accept socket");
			return false;
		}
		// Inherit timeout from parent
		newSock->timeout(mTimeout);
		return true;
	}

	bool opened() const { return 0!=mSock; }

	uint16_t mPort;
	std::string mAddress;
	apr_sockaddr_t * mSockAddr;
	apr_socket_t * mSock;
	al_sec mTimeout;
	int mType;
};

Socket::Socket()
:	mImpl(new Impl)
{}

Socket::Socket(uint16_t port, const char * address, al_sec timeout, int type)
: mImpl(0)
{
	mImpl = new Impl(port, address, timeout, type);
	if (mImpl == 0) {
		AL_WARN("Socket::Socket(uint16_t, const char *, al_sec, bool): mImpl is zero!!!\n");
	}

}

Socket::~Socket(){
	close();
	delete mImpl;
}

const std::string& Socket::address() const { return mImpl->mAddress; }

bool Socket::opened() const { return mImpl->opened(); }

uint16_t Socket::port() const { return mImpl->mPort; }

al_sec Socket::timeout() const { return mImpl->mTimeout; }

bool Socket::bind(){ return mImpl->bind(); }

bool Socket::connect(){ return mImpl->connect(); }

void Socket::close(){ mImpl->close(); }

bool Socket::open(uint16_t port, const char * address, al_sec timeout, int type){
	return
		mImpl->open(port, address, timeout, type)
		&& onOpen();
}

void Socket::timeout(al_sec v){
	mImpl->timeout(v);
}

size_t Socket::recv(char * buffer, size_t maxlen) {
	apr_size_t len = maxlen;

	// printf("About to call apr_socket_recv(%p, %p, %d)\n", mImpl->mSock, buffer, len);

	apr_status_t r = apr_socket_recv(mImpl->mSock, buffer, &len);

	// printf("apr_socket_recv returned\n");

	// only error check if not error# 35: Resource temporarily unavailable
	if(len){ check_apr(r); }
	return len;
}

size_t Socket::send(const char * buffer, size_t len) {
	apr_size_t size = len;
	if (mImpl->opened()) {
		//check_apr(apr_socket_send(mSock, buffer, &size));
		apr_socket_send(mImpl->mSock, buffer, &size);
	} else {
		size = 0;
	}
	return size;
}

std::string Socket::hostIP(){
	ImplAPR apr;
	char * addr;
	apr_sockaddr_t * sa;
	check_apr(apr_sockaddr_info_get(&sa, hostName().c_str(), APR_INET, 8000, 0, apr.pool()));
	//printf("%p sa\n", sa);
	while(sa != 0) {
		check_apr(apr_sockaddr_ip_get(&addr, sa));
		//printf("%s %s %s %d %d\n", addr, sa->hostname, sa->servname, sa->port, sa->family);
		sa = sa->next;
	}
	return addr;
}

std::string Socket::hostName(){
	char buf[APRMAXHOSTLEN+1];
	ImplAPR apr;
	check_apr(apr_gethostname(buf, sizeof(buf), apr.pool()));
	//printf("host %s\n", buf);
	return buf;
}

bool Socket::listen(){
	return mImpl->listen();
}

bool Socket::accept(Socket& sock){
	return mImpl->accept(sock.mImpl);
}

bool SocketClient::onOpen(){
	return connect();
}

bool SocketServer::onOpen(){
	return bind();
}

} // al::
<|endoftext|>