<commit_before>// Copyright (c) 2010 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/notifications/desktop_notification_service.h"

#include "app/l10n_util.h"
#include "app/resource_bundle.h"
#include "base/thread.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/child_process_host.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/extensions/extensions_service.h"
#include "chrome/browser/notifications/notification.h"
#include "chrome/browser/notifications/notification_object_proxy.h"
#include "chrome/browser/notifications/notification_ui_manager.h"
#include "chrome/browser/notifications/notifications_prefs_cache.h"
#include "chrome/browser/pref_service.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/renderer_host/render_process_host.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/renderer_host/site_instance.h"
#include "chrome/browser/scoped_pref_update.h"
#include "chrome/browser/tab_contents/infobar_delegate.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/worker_host/worker_process_host.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/render_messages.h"
#include "chrome/common/url_constants.h"
#include "grit/browser_resources.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
#include "net/base/escape.h"
#include "third_party/WebKit/WebKit/chromium/public/WebNotificationPresenter.h"

using WebKit::WebNotificationPresenter;

// static
string16 DesktopNotificationService::CreateDataUrl(
    const GURL& icon_url, const string16& title, const string16& body) {
  int resource;
  string16 line_name;
  string16 line;
  std::vector<string16> subst;
  if (icon_url.is_valid()) {
    resource = IDR_NOTIFICATION_ICON_HTML;
    subst.push_back(UTF8ToUTF16(icon_url.spec()));
    subst.push_back(UTF8ToUTF16(EscapeForHTML(UTF16ToUTF8(title))));
    subst.push_back(UTF8ToUTF16(EscapeForHTML(UTF16ToUTF8(body))));
  } else if (title.empty() || body.empty()) {
    resource = IDR_NOTIFICATION_1LINE_HTML;
    line = title.empty() ? body : title;
    // Strings are div names in the template file.
    line_name = title.empty() ? ASCIIToUTF16("description")
                              : ASCIIToUTF16("title");
    subst.push_back(UTF8ToUTF16(EscapeForHTML(UTF16ToUTF8(line_name))));
    subst.push_back(UTF8ToUTF16(EscapeForHTML(UTF16ToUTF8(line))));
  } else {
    resource = IDR_NOTIFICATION_2LINE_HTML;
    subst.push_back(UTF8ToUTF16(EscapeForHTML(UTF16ToUTF8(title))));
    subst.push_back(UTF8ToUTF16(EscapeForHTML(UTF16ToUTF8(body))));
  }

  const base::StringPiece template_html(
      ResourceBundle::GetSharedInstance().GetRawDataResource(
          resource));

  if (template_html.empty()) {
    NOTREACHED() << "unable to load template. ID: " << resource;
    return string16();
  }

  string16 format_string = ASCIIToUTF16("data:text/html;charset=utf-8,"
                                        + template_html.as_string());
  return ReplaceStringPlaceholders(format_string, subst, NULL);
}

// A task object which calls the renderer to inform the web page that the
// permission request has completed.
class NotificationPermissionCallbackTask : public Task {
 public:
  NotificationPermissionCallbackTask(int process_id, int route_id,
      int request_id)
      : process_id_(process_id),
        route_id_(route_id),
        request_id_(request_id) {
  }

  virtual void Run() {
    DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
    RenderViewHost* host = RenderViewHost::FromID(process_id_, route_id_);
    if (host)
      host->Send(new ViewMsg_PermissionRequestDone(route_id_, request_id_));
  }

 private:
  int process_id_;
  int route_id_;
  int request_id_;
};

// The delegate for the infobar shown when an origin requests notification
// permissions.
class NotificationPermissionInfoBarDelegate : public ConfirmInfoBarDelegate {
 public:
  NotificationPermissionInfoBarDelegate(TabContents* contents,
                                        const GURL& origin,
                                        const std::wstring& display_name,
                                        int process_id,
                                        int route_id,
                                        int callback_context)
      : ConfirmInfoBarDelegate(contents),
        origin_(origin),
        display_name_(display_name),
        profile_(contents->profile()),
        process_id_(process_id),
        route_id_(route_id),
        callback_context_(callback_context),
        action_taken_(false) {
  }

  // Overridden from ConfirmInfoBarDelegate:
  virtual void InfoBarClosed() {
    if (!action_taken_)
      UMA_HISTOGRAM_COUNTS("NotificationPermissionRequest.Ignored", 1);

    ChromeThread::PostTask(
      ChromeThread::IO, FROM_HERE,
      new NotificationPermissionCallbackTask(
          process_id_, route_id_, callback_context_));

    delete this;
  }

  virtual std::wstring GetMessageText() const {
    return l10n_util::GetStringF(IDS_NOTIFICATION_PERMISSIONS, display_name_);
  }

  virtual SkBitmap* GetIcon() const {
    return ResourceBundle::GetSharedInstance().GetBitmapNamed(
       IDR_PRODUCT_ICON_32);
  }

  virtual int GetButtons() const {
    return BUTTON_OK | BUTTON_CANCEL | BUTTON_OK_DEFAULT;
  }

  virtual std::wstring GetButtonLabel(InfoBarButton button) const {
    return button == BUTTON_OK ?
        l10n_util::GetString(IDS_NOTIFICATION_PERMISSION_YES) :
        l10n_util::GetString(IDS_NOTIFICATION_PERMISSION_NO);
  }

  virtual bool Accept() {
    UMA_HISTOGRAM_COUNTS("NotificationPermissionRequest.Allowed", 1);
    profile_->GetDesktopNotificationService()->GrantPermission(origin_);
    action_taken_ = true;
    return true;
  }

  virtual bool Cancel() {
    UMA_HISTOGRAM_COUNTS("NotificationPermissionRequest.Denied", 1);
    profile_->GetDesktopNotificationService()->DenyPermission(origin_);
    action_taken_ = true;
    return true;
  }

 private:
  // The origin we are asking for permissions on.
  GURL origin_;

  // The display name for the origin to be displayed.  Will be different from
  // origin_ for extensions.
  std::wstring display_name_;

  // The Profile that we restore sessions from.
  Profile* profile_;

  // The callback information that tells us how to respond to javascript via
  // the correct RenderView.
  int process_id_;
  int route_id_;
  int callback_context_;

  // Whether the user clicked one of the buttons.
  bool action_taken_;

  DISALLOW_COPY_AND_ASSIGN(NotificationPermissionInfoBarDelegate);
};

DesktopNotificationService::DesktopNotificationService(Profile* profile,
    NotificationUIManager* ui_manager)
    : profile_(profile),
      ui_manager_(ui_manager) {
  InitPrefs();
  StartObserving();
}

DesktopNotificationService::~DesktopNotificationService() {
  StopObserving();
}

// Initialize the cache with the allowed and denied origins, or
// create the preferences if they don't exist yet.
void DesktopNotificationService::InitPrefs() {
  PrefService* prefs = profile_->GetPrefs();
  std::vector<GURL> allowed_origins;
  std::vector<GURL> denied_origins;

  if (!profile_->IsOffTheRecord()) {
    if (!prefs->FindPreference(prefs::kDesktopNotificationAllowedOrigins))
      prefs->RegisterListPref(prefs::kDesktopNotificationAllowedOrigins);
    const ListValue* allowed_sites =
        prefs->GetList(prefs::kDesktopNotificationAllowedOrigins);
    if (allowed_sites)
      NotificationsPrefsCache::ListValueToGurlVector(*allowed_sites,
                                                     &allowed_origins);

    if (!prefs->FindPreference(prefs::kDesktopNotificationDeniedOrigins))
      prefs->RegisterListPref(prefs::kDesktopNotificationDeniedOrigins);
    const ListValue* denied_sites =
        prefs->GetList(prefs::kDesktopNotificationDeniedOrigins);
    if (denied_sites)
      NotificationsPrefsCache::ListValueToGurlVector(*denied_sites,
                                                     &denied_origins);
  }

  prefs_cache_ = new NotificationsPrefsCache();
  prefs_cache_->SetCacheAllowedOrigins(allowed_origins);
  prefs_cache_->SetCacheDeniedOrigins(denied_origins);
  prefs_cache_->set_is_initialized(true);
}

void DesktopNotificationService::StartObserving() {
  if (!profile_->IsOffTheRecord()) {
    PrefService* prefs = profile_->GetPrefs();
    prefs->AddPrefObserver(prefs::kDesktopNotificationAllowedOrigins, this);
    prefs->AddPrefObserver(prefs::kDesktopNotificationDeniedOrigins, this);
  }
}

void DesktopNotificationService::StopObserving() {
  if (!profile_->IsOffTheRecord()) {
    PrefService* prefs = profile_->GetPrefs();
    prefs->RemovePrefObserver(prefs::kDesktopNotificationAllowedOrigins, this);
    prefs->RemovePrefObserver(prefs::kDesktopNotificationDeniedOrigins, this);
  }
}

void DesktopNotificationService::GrantPermission(const GURL& origin) {
  DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
  PersistPermissionChange(origin, true);

  // Schedule a cache update on the IO thread.
  ChromeThread::PostTask(
      ChromeThread::IO, FROM_HERE,
      NewRunnableMethod(
          prefs_cache_.get(), &NotificationsPrefsCache::CacheAllowedOrigin,
          origin));
}

void DesktopNotificationService::DenyPermission(const GURL& origin) {
  DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
  PersistPermissionChange(origin, false);

  // Schedule a cache update on the IO thread.
  ChromeThread::PostTask(
      ChromeThread::IO, FROM_HERE,
      NewRunnableMethod(
          prefs_cache_.get(), &NotificationsPrefsCache::CacheDeniedOrigin,
          origin));
}

void DesktopNotificationService::Observe(NotificationType type,
                                         const NotificationSource& source,
                                         const NotificationDetails& details) {
  DCHECK(NotificationType::PREF_CHANGED == type);
  PrefService* prefs = profile_->GetPrefs();
  std::wstring* name = Details<std::wstring>(details).ptr();

  if (0 == name->compare(prefs::kDesktopNotificationAllowedOrigins)) {
    const ListValue* allowed_sites =
        prefs->GetList(prefs::kDesktopNotificationAllowedOrigins);
    std::vector<GURL> allowed_origins;
    NotificationsPrefsCache::ListValueToGurlVector(*allowed_sites,
                                                   &allowed_origins);
    // Schedule a cache update on the IO thread.
    ChromeThread::PostTask(
        ChromeThread::IO, FROM_HERE,
        NewRunnableMethod(
            prefs_cache_.get(),
            &NotificationsPrefsCache::SetCacheAllowedOrigins,
            allowed_origins));
  } else if (0 == name->compare(prefs::kDesktopNotificationDeniedOrigins)) {
    const ListValue* denied_sites =
        prefs->GetList(prefs::kDesktopNotificationDeniedOrigins);
    std::vector<GURL> denied_origins;
    NotificationsPrefsCache::ListValueToGurlVector(*denied_sites,
                                                   &denied_origins);
    // Schedule a cache update on the IO thread.
    ChromeThread::PostTask(
        ChromeThread::IO, FROM_HERE,
        NewRunnableMethod(
            prefs_cache_.get(),
            &NotificationsPrefsCache::SetCacheDeniedOrigins,
            denied_origins));
  }
}

void DesktopNotificationService::PersistPermissionChange(
    const GURL& origin, bool is_allowed) {
  // Don't persist changes when off the record.
  if (profile_->IsOffTheRecord())
    return;

  PrefService* prefs = profile_->GetPrefs();

  StopObserving();

  bool allowed_changed = false;
  bool denied_changed = false;

  ListValue* allowed_sites =
      prefs->GetMutableList(prefs::kDesktopNotificationAllowedOrigins);
  ListValue* denied_sites =
      prefs->GetMutableList(prefs::kDesktopNotificationDeniedOrigins);
  {
    // value is passed to the preferences list, or deleted.
    StringValue* value = new StringValue(origin.spec());

    // Remove from one list and add to the other.
    if (is_allowed) {
      // Remove from the denied list.
      if (denied_sites->Remove(*value) != -1)
        denied_changed = true;

      // Add to the allowed list.
      if (allowed_sites->AppendIfNotPresent(value))
        allowed_changed = true;
      else
        delete value;
    } else {
      // Remove from the allowed list.
      if (allowed_sites->Remove(*value) != -1)
        allowed_changed = true;

      // Add to the denied list.
      if (denied_sites->AppendIfNotPresent(value))
        denied_changed = true;
      else
        delete value;
    }
  }

  // Persist the pref if anthing changed, but only send updates for the
  // list that changed.
  if (allowed_changed || denied_changed) {
    if (allowed_changed) {
      ScopedPrefUpdate updateAllowed(
          prefs, prefs::kDesktopNotificationAllowedOrigins);
    }
    if (denied_changed) {
      ScopedPrefUpdate updateDenied(
          prefs, prefs::kDesktopNotificationDeniedOrigins);
    }
    prefs->ScheduleSavePersistentPrefs();
  }
  StartObserving();
}

void DesktopNotificationService::RequestPermission(
    const GURL& origin, int process_id, int route_id, int callback_context) {
  DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
  // Show an info bar requesting permission.
  Browser* browser = BrowserList::GetLastActive();
  if (!browser) {
    // Reached during ui tests.
    return;
  }
  TabContents* tab = browser->GetSelectedTabContents();
  if (!tab)
    return;

  std::wstring display_name = DisplayNameForOrigin(origin);

  tab->AddInfoBar(new NotificationPermissionInfoBarDelegate(
      tab, origin, display_name, process_id, route_id, callback_context));
}

void DesktopNotificationService::ShowNotification(
    const Notification& notification) {
  ui_manager_->Add(notification, profile_);
}

bool DesktopNotificationService::CancelDesktopNotification(
    int process_id, int route_id, int notification_id) {
  scoped_refptr<NotificationObjectProxy> proxy(
      new NotificationObjectProxy(process_id, route_id, notification_id,
                                  false));
  Notification notif(GURL(), GURL(), L"", proxy);
  return ui_manager_->Cancel(notif);
}

bool DesktopNotificationService::ShowDesktopNotification(
    const GURL& origin, const GURL& url, int process_id, int route_id,
    DesktopNotificationSource source, int notification_id) {
  DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
  NotificationObjectProxy* proxy =
      new NotificationObjectProxy(process_id, route_id,
                                  notification_id,
                                  source == WorkerNotification);
  Notification notif(origin, url, DisplayNameForOrigin(origin), proxy);
  ShowNotification(notif);
  return true;
}

bool DesktopNotificationService::ShowDesktopNotificationText(
    const GURL& origin, const GURL& icon, const string16& title,
    const string16& text, int process_id, int route_id,
    DesktopNotificationSource source, int notification_id) {
  DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
  NotificationObjectProxy* proxy =
      new NotificationObjectProxy(process_id, route_id,
                                  notification_id,
                                  source == WorkerNotification);
  // "upconvert" the string parameters to a data: URL.
  string16 data_url = CreateDataUrl(icon, title, text);
  Notification notif(
      origin, GURL(data_url), DisplayNameForOrigin(origin), proxy);
  ShowNotification(notif);
  return true;
}

std::wstring DesktopNotificationService::DisplayNameForOrigin(
    const GURL& origin) {
  // If the source is an extension, lookup the display name.
  if (origin.SchemeIs(chrome::kExtensionScheme)) {
    ExtensionsService* ext_service = profile_->GetExtensionsService();
    if (ext_service) {
      Extension* extension = ext_service->GetExtensionByURL(origin);
      if (extension)
        return ASCIIToWide(extension->name());
    }
  }
  return UTF8ToWide(origin.host());
}
<commit_msg>Fix crash when signing in with certain desktop notification settings.<commit_after>// Copyright (c) 2010 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/notifications/desktop_notification_service.h"

#include "app/l10n_util.h"
#include "app/resource_bundle.h"
#include "base/thread.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/child_process_host.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/extensions/extensions_service.h"
#include "chrome/browser/notifications/notification.h"
#include "chrome/browser/notifications/notification_object_proxy.h"
#include "chrome/browser/notifications/notification_ui_manager.h"
#include "chrome/browser/notifications/notifications_prefs_cache.h"
#include "chrome/browser/pref_service.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/renderer_host/render_process_host.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/renderer_host/site_instance.h"
#include "chrome/browser/scoped_pref_update.h"
#include "chrome/browser/tab_contents/infobar_delegate.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/worker_host/worker_process_host.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/render_messages.h"
#include "chrome/common/url_constants.h"
#include "grit/browser_resources.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
#include "net/base/escape.h"
#include "third_party/WebKit/WebKit/chromium/public/WebNotificationPresenter.h"

using WebKit::WebNotificationPresenter;

// static
string16 DesktopNotificationService::CreateDataUrl(
    const GURL& icon_url, const string16& title, const string16& body) {
  int resource;
  string16 line_name;
  string16 line;
  std::vector<string16> subst;
  if (icon_url.is_valid()) {
    resource = IDR_NOTIFICATION_ICON_HTML;
    subst.push_back(UTF8ToUTF16(icon_url.spec()));
    subst.push_back(UTF8ToUTF16(EscapeForHTML(UTF16ToUTF8(title))));
    subst.push_back(UTF8ToUTF16(EscapeForHTML(UTF16ToUTF8(body))));
  } else if (title.empty() || body.empty()) {
    resource = IDR_NOTIFICATION_1LINE_HTML;
    line = title.empty() ? body : title;
    // Strings are div names in the template file.
    line_name = title.empty() ? ASCIIToUTF16("description")
                              : ASCIIToUTF16("title");
    subst.push_back(UTF8ToUTF16(EscapeForHTML(UTF16ToUTF8(line_name))));
    subst.push_back(UTF8ToUTF16(EscapeForHTML(UTF16ToUTF8(line))));
  } else {
    resource = IDR_NOTIFICATION_2LINE_HTML;
    subst.push_back(UTF8ToUTF16(EscapeForHTML(UTF16ToUTF8(title))));
    subst.push_back(UTF8ToUTF16(EscapeForHTML(UTF16ToUTF8(body))));
  }

  const base::StringPiece template_html(
      ResourceBundle::GetSharedInstance().GetRawDataResource(
          resource));

  if (template_html.empty()) {
    NOTREACHED() << "unable to load template. ID: " << resource;
    return string16();
  }

  string16 format_string = ASCIIToUTF16("data:text/html;charset=utf-8,"
                                        + template_html.as_string());
  return ReplaceStringPlaceholders(format_string, subst, NULL);
}

// A task object which calls the renderer to inform the web page that the
// permission request has completed.
class NotificationPermissionCallbackTask : public Task {
 public:
  NotificationPermissionCallbackTask(int process_id, int route_id,
      int request_id)
      : process_id_(process_id),
        route_id_(route_id),
        request_id_(request_id) {
  }

  virtual void Run() {
    DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
    RenderViewHost* host = RenderViewHost::FromID(process_id_, route_id_);
    if (host)
      host->Send(new ViewMsg_PermissionRequestDone(route_id_, request_id_));
  }

 private:
  int process_id_;
  int route_id_;
  int request_id_;
};

// The delegate for the infobar shown when an origin requests notification
// permissions.
class NotificationPermissionInfoBarDelegate : public ConfirmInfoBarDelegate {
 public:
  NotificationPermissionInfoBarDelegate(TabContents* contents,
                                        const GURL& origin,
                                        const std::wstring& display_name,
                                        int process_id,
                                        int route_id,
                                        int callback_context)
      : ConfirmInfoBarDelegate(contents),
        origin_(origin),
        display_name_(display_name),
        profile_(contents->profile()),
        process_id_(process_id),
        route_id_(route_id),
        callback_context_(callback_context),
        action_taken_(false) {
  }

  // Overridden from ConfirmInfoBarDelegate:
  virtual void InfoBarClosed() {
    if (!action_taken_)
      UMA_HISTOGRAM_COUNTS("NotificationPermissionRequest.Ignored", 1);

    ChromeThread::PostTask(
      ChromeThread::IO, FROM_HERE,
      new NotificationPermissionCallbackTask(
          process_id_, route_id_, callback_context_));

    delete this;
  }

  virtual std::wstring GetMessageText() const {
    return l10n_util::GetStringF(IDS_NOTIFICATION_PERMISSIONS, display_name_);
  }

  virtual SkBitmap* GetIcon() const {
    return ResourceBundle::GetSharedInstance().GetBitmapNamed(
       IDR_PRODUCT_ICON_32);
  }

  virtual int GetButtons() const {
    return BUTTON_OK | BUTTON_CANCEL | BUTTON_OK_DEFAULT;
  }

  virtual std::wstring GetButtonLabel(InfoBarButton button) const {
    return button == BUTTON_OK ?
        l10n_util::GetString(IDS_NOTIFICATION_PERMISSION_YES) :
        l10n_util::GetString(IDS_NOTIFICATION_PERMISSION_NO);
  }

  virtual bool Accept() {
    UMA_HISTOGRAM_COUNTS("NotificationPermissionRequest.Allowed", 1);
    profile_->GetDesktopNotificationService()->GrantPermission(origin_);
    action_taken_ = true;
    return true;
  }

  virtual bool Cancel() {
    UMA_HISTOGRAM_COUNTS("NotificationPermissionRequest.Denied", 1);
    profile_->GetDesktopNotificationService()->DenyPermission(origin_);
    action_taken_ = true;
    return true;
  }

 private:
  // The origin we are asking for permissions on.
  GURL origin_;

  // The display name for the origin to be displayed.  Will be different from
  // origin_ for extensions.
  std::wstring display_name_;

  // The Profile that we restore sessions from.
  Profile* profile_;

  // The callback information that tells us how to respond to javascript via
  // the correct RenderView.
  int process_id_;
  int route_id_;
  int callback_context_;

  // Whether the user clicked one of the buttons.
  bool action_taken_;

  DISALLOW_COPY_AND_ASSIGN(NotificationPermissionInfoBarDelegate);
};

DesktopNotificationService::DesktopNotificationService(Profile* profile,
    NotificationUIManager* ui_manager)
    : profile_(profile),
      ui_manager_(ui_manager) {
  InitPrefs();
  StartObserving();
}

DesktopNotificationService::~DesktopNotificationService() {
  StopObserving();
}

// Initialize the cache with the allowed and denied origins, or
// create the preferences if they don't exist yet.
void DesktopNotificationService::InitPrefs() {
  PrefService* prefs = profile_->GetPrefs();
  std::vector<GURL> allowed_origins;
  std::vector<GURL> denied_origins;

  if (!profile_->IsOffTheRecord()) {
    if (!prefs->FindPreference(prefs::kDesktopNotificationAllowedOrigins))
      prefs->RegisterListPref(prefs::kDesktopNotificationAllowedOrigins);
    const ListValue* allowed_sites =
        prefs->GetList(prefs::kDesktopNotificationAllowedOrigins);
    if (allowed_sites)
      NotificationsPrefsCache::ListValueToGurlVector(*allowed_sites,
                                                     &allowed_origins);

    if (!prefs->FindPreference(prefs::kDesktopNotificationDeniedOrigins))
      prefs->RegisterListPref(prefs::kDesktopNotificationDeniedOrigins);
    const ListValue* denied_sites =
        prefs->GetList(prefs::kDesktopNotificationDeniedOrigins);
    if (denied_sites)
      NotificationsPrefsCache::ListValueToGurlVector(*denied_sites,
                                                     &denied_origins);
  }

  prefs_cache_ = new NotificationsPrefsCache();
  prefs_cache_->SetCacheAllowedOrigins(allowed_origins);
  prefs_cache_->SetCacheDeniedOrigins(denied_origins);
  prefs_cache_->set_is_initialized(true);
}

void DesktopNotificationService::StartObserving() {
  if (!profile_->IsOffTheRecord()) {
    PrefService* prefs = profile_->GetPrefs();
    prefs->AddPrefObserver(prefs::kDesktopNotificationAllowedOrigins, this);
    prefs->AddPrefObserver(prefs::kDesktopNotificationDeniedOrigins, this);
  }
}

void DesktopNotificationService::StopObserving() {
  if (!profile_->IsOffTheRecord()) {
    PrefService* prefs = profile_->GetPrefs();
    prefs->RemovePrefObserver(prefs::kDesktopNotificationAllowedOrigins, this);
    prefs->RemovePrefObserver(prefs::kDesktopNotificationDeniedOrigins, this);
  }
}

void DesktopNotificationService::GrantPermission(const GURL& origin) {
  DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
  PersistPermissionChange(origin, true);

  // Schedule a cache update on the IO thread.
  ChromeThread::PostTask(
      ChromeThread::IO, FROM_HERE,
      NewRunnableMethod(
          prefs_cache_.get(), &NotificationsPrefsCache::CacheAllowedOrigin,
          origin));
}

void DesktopNotificationService::DenyPermission(const GURL& origin) {
  DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
  PersistPermissionChange(origin, false);

  // Schedule a cache update on the IO thread.
  ChromeThread::PostTask(
      ChromeThread::IO, FROM_HERE,
      NewRunnableMethod(
          prefs_cache_.get(), &NotificationsPrefsCache::CacheDeniedOrigin,
          origin));
}

void DesktopNotificationService::Observe(NotificationType type,
                                         const NotificationSource& source,
                                         const NotificationDetails& details) {
  DCHECK(NotificationType::PREF_CHANGED == type);
  PrefService* prefs = profile_->GetPrefs();
  std::wstring* name = Details<std::wstring>(details).ptr();

  if (0 == name->compare(prefs::kDesktopNotificationAllowedOrigins)) {
    const ListValue* allowed_sites =
        prefs->GetList(prefs::kDesktopNotificationAllowedOrigins);
    std::vector<GURL> allowed_origins;
    if (allowed_sites) {
      NotificationsPrefsCache::ListValueToGurlVector(*allowed_sites,
                                                     &allowed_origins);
    }
    // Schedule a cache update on the IO thread.
    ChromeThread::PostTask(
        ChromeThread::IO, FROM_HERE,
        NewRunnableMethod(
            prefs_cache_.get(),
            &NotificationsPrefsCache::SetCacheAllowedOrigins,
            allowed_origins));
  } else if (0 == name->compare(prefs::kDesktopNotificationDeniedOrigins)) {
    const ListValue* denied_sites =
        prefs->GetList(prefs::kDesktopNotificationDeniedOrigins);
    std::vector<GURL> denied_origins;
    if (denied_sites) {
      NotificationsPrefsCache::ListValueToGurlVector(*denied_sites,
                                                     &denied_origins);
    }
    // Schedule a cache update on the IO thread.
    ChromeThread::PostTask(
        ChromeThread::IO, FROM_HERE,
        NewRunnableMethod(
            prefs_cache_.get(),
            &NotificationsPrefsCache::SetCacheDeniedOrigins,
            denied_origins));
  }
}

void DesktopNotificationService::PersistPermissionChange(
    const GURL& origin, bool is_allowed) {
  // Don't persist changes when off the record.
  if (profile_->IsOffTheRecord())
    return;

  PrefService* prefs = profile_->GetPrefs();

  StopObserving();

  bool allowed_changed = false;
  bool denied_changed = false;

  ListValue* allowed_sites =
      prefs->GetMutableList(prefs::kDesktopNotificationAllowedOrigins);
  ListValue* denied_sites =
      prefs->GetMutableList(prefs::kDesktopNotificationDeniedOrigins);
  {
    // value is passed to the preferences list, or deleted.
    StringValue* value = new StringValue(origin.spec());

    // Remove from one list and add to the other.
    if (is_allowed) {
      // Remove from the denied list.
      if (denied_sites->Remove(*value) != -1)
        denied_changed = true;

      // Add to the allowed list.
      if (allowed_sites->AppendIfNotPresent(value))
        allowed_changed = true;
      else
        delete value;
    } else {
      // Remove from the allowed list.
      if (allowed_sites->Remove(*value) != -1)
        allowed_changed = true;

      // Add to the denied list.
      if (denied_sites->AppendIfNotPresent(value))
        denied_changed = true;
      else
        delete value;
    }
  }

  // Persist the pref if anthing changed, but only send updates for the
  // list that changed.
  if (allowed_changed || denied_changed) {
    if (allowed_changed) {
      ScopedPrefUpdate updateAllowed(
          prefs, prefs::kDesktopNotificationAllowedOrigins);
    }
    if (denied_changed) {
      ScopedPrefUpdate updateDenied(
          prefs, prefs::kDesktopNotificationDeniedOrigins);
    }
    prefs->ScheduleSavePersistentPrefs();
  }
  StartObserving();
}

void DesktopNotificationService::RequestPermission(
    const GURL& origin, int process_id, int route_id, int callback_context) {
  DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
  // Show an info bar requesting permission.
  Browser* browser = BrowserList::GetLastActive();
  if (!browser) {
    // Reached during ui tests.
    return;
  }
  TabContents* tab = browser->GetSelectedTabContents();
  if (!tab)
    return;

  std::wstring display_name = DisplayNameForOrigin(origin);

  tab->AddInfoBar(new NotificationPermissionInfoBarDelegate(
      tab, origin, display_name, process_id, route_id, callback_context));
}

void DesktopNotificationService::ShowNotification(
    const Notification& notification) {
  ui_manager_->Add(notification, profile_);
}

bool DesktopNotificationService::CancelDesktopNotification(
    int process_id, int route_id, int notification_id) {
  scoped_refptr<NotificationObjectProxy> proxy(
      new NotificationObjectProxy(process_id, route_id, notification_id,
                                  false));
  Notification notif(GURL(), GURL(), L"", proxy);
  return ui_manager_->Cancel(notif);
}

bool DesktopNotificationService::ShowDesktopNotification(
    const GURL& origin, const GURL& url, int process_id, int route_id,
    DesktopNotificationSource source, int notification_id) {
  DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
  NotificationObjectProxy* proxy =
      new NotificationObjectProxy(process_id, route_id,
                                  notification_id,
                                  source == WorkerNotification);
  Notification notif(origin, url, DisplayNameForOrigin(origin), proxy);
  ShowNotification(notif);
  return true;
}

bool DesktopNotificationService::ShowDesktopNotificationText(
    const GURL& origin, const GURL& icon, const string16& title,
    const string16& text, int process_id, int route_id,
    DesktopNotificationSource source, int notification_id) {
  DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
  NotificationObjectProxy* proxy =
      new NotificationObjectProxy(process_id, route_id,
                                  notification_id,
                                  source == WorkerNotification);
  // "upconvert" the string parameters to a data: URL.
  string16 data_url = CreateDataUrl(icon, title, text);
  Notification notif(
      origin, GURL(data_url), DisplayNameForOrigin(origin), proxy);
  ShowNotification(notif);
  return true;
}

std::wstring DesktopNotificationService::DisplayNameForOrigin(
    const GURL& origin) {
  // If the source is an extension, lookup the display name.
  if (origin.SchemeIs(chrome::kExtensionScheme)) {
    ExtensionsService* ext_service = profile_->GetExtensionsService();
    if (ext_service) {
      Extension* extension = ext_service->GetExtensionByURL(origin);
      if (extension)
        return ASCIIToWide(extension->name());
    }
  }
  return UTF8ToWide(origin.host());
}
<|endoftext|>


<commit_before>// Copyright (c) 2012 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/ui/views/ash/caps_lock_handler.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/ui_test_utils.h"

#if defined(OS_CHROMEOS)
#include "chrome/browser/chromeos/input_method/xkeyboard.h"
using namespace chromeos::input_method;
#endif

namespace {

#if defined(OS_CHROMEOS)
class DummyXKeyboard : public XKeyboard {
 public:
  explicit DummyXKeyboard(bool initial_caps_lock_state)
      : caps_lock_is_enabled_(initial_caps_lock_state) {}
  virtual ~DummyXKeyboard() {}

  // Overridden from chrome::input_method::XKeyboard:
  virtual bool SetCurrentKeyboardLayoutByName(
      const std::string& layout_name) OVERRIDE {
    return true;
  }
  virtual bool RemapModifierKeys(const ModifierMap& modifier_map) OVERRIDE {
    return true;
  }
  virtual bool ReapplyCurrentKeyboardLayout() OVERRIDE {
    return true;
  }
  virtual void ReapplyCurrentModifierLockStatus() OVERRIDE {}
  virtual void SetLockedModifiers(
      ModifierLockStatus new_caps_lock_status,
      ModifierLockStatus new_num_lock_status) OVERRIDE {}
  virtual void SetNumLockEnabled(bool enable_num_lock) OVERRIDE {}
  virtual void SetCapsLockEnabled(bool enable_caps_lock) OVERRIDE {
    caps_lock_is_enabled_ = enable_caps_lock;
  }
  virtual bool NumLockIsEnabled() OVERRIDE {
    return true;
  }
  virtual bool CapsLockIsEnabled() OVERRIDE {
    return caps_lock_is_enabled_;
  }
  virtual std::string CreateFullXkbLayoutName(
      const std::string& layout_name,
      const ModifierMap& modifire_map) OVERRIDE {
    return "";
  }
  virtual unsigned int GetNumLockMask() OVERRIDE {
    return 0;
  }
  virtual void GetLockedModifiers(bool* out_caps_lock_enabled,
                                  bool* out_num_lock_enabled) OVERRIDE {}

 private:
  bool caps_lock_is_enabled_;

  DISALLOW_COPY_AND_ASSIGN(DummyXKeyboard);
};

class CapsLockHandlerTest : public InProcessBrowserTest {
 public:
  CapsLockHandlerTest()
      : initial_caps_lock_state_(false),
        xkeyboard_(initial_caps_lock_state_) {
  }
  virtual void SetUp() OVERRIDE {
    handler_.reset(new CapsLockHandler(&xkeyboard_));
    // Force CapsLockHandler::HandleToggleCapsLock() to toggle the lock state.
    handler_->set_is_running_on_chromeos_for_test(true);
  }
  virtual void TearDown() OVERRIDE {
    handler_.reset();
  }

 protected:
  const bool initial_caps_lock_state_;
  DummyXKeyboard xkeyboard_;
  scoped_ptr<CapsLockHandler> handler_;

  DISALLOW_COPY_AND_ASSIGN(CapsLockHandlerTest);
};
#endif

}  // namespace

#if defined(OS_CHROMEOS)
// Check if HandleToggleCapsLock() really changes the lock state.
IN_PROC_BROWSER_TEST_F(CapsLockHandlerTest, TestCapsLock) {
  EXPECT_EQ(initial_caps_lock_state_, handler_->caps_lock_is_on_for_test());
  EXPECT_TRUE(handler_->HandleToggleCapsLock());
  EXPECT_EQ(!initial_caps_lock_state_, xkeyboard_.CapsLockIsEnabled());
  handler_->OnCapsLockChange(!initial_caps_lock_state_);
  EXPECT_EQ(!initial_caps_lock_state_, handler_->caps_lock_is_on_for_test());
  EXPECT_TRUE(handler_->HandleToggleCapsLock());
  handler_->OnCapsLockChange(initial_caps_lock_state_);
  EXPECT_EQ(initial_caps_lock_state_, xkeyboard_.CapsLockIsEnabled());
  EXPECT_EQ(initial_caps_lock_state_, handler_->caps_lock_is_on_for_test());
}
#endif
<commit_msg>cleanup: Use MockXKeyboard in caps_lock_handler_browsertest.cc.<commit_after>// Copyright (c) 2012 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/ui/views/ash/caps_lock_handler.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/ui_test_utils.h"

#if defined(OS_CHROMEOS)
#include "chrome/browser/chromeos/input_method/mock_xkeyboard.h"
using namespace chromeos::input_method;
#endif

namespace {

#if defined(OS_CHROMEOS)
class CapsLockHandlerTest : public InProcessBrowserTest {
 public:
  CapsLockHandlerTest()
      : initial_caps_lock_state_(false) {
  }
  virtual void SetUp() OVERRIDE {
    handler_.reset(new CapsLockHandler(&xkeyboard_));
    // Force CapsLockHandler::HandleToggleCapsLock() to toggle the lock state.
    handler_->set_is_running_on_chromeos_for_test(true);
  }
  virtual void TearDown() OVERRIDE {
    handler_.reset();
  }

 protected:
  const bool initial_caps_lock_state_;
  MockXKeyboard xkeyboard_;
  scoped_ptr<CapsLockHandler> handler_;

  DISALLOW_COPY_AND_ASSIGN(CapsLockHandlerTest);
};
#endif

}  // namespace

#if defined(OS_CHROMEOS)
// Check if HandleToggleCapsLock() really changes the lock state.
IN_PROC_BROWSER_TEST_F(CapsLockHandlerTest, TestCapsLock) {
  EXPECT_EQ(initial_caps_lock_state_, handler_->caps_lock_is_on_for_test());
  EXPECT_TRUE(handler_->HandleToggleCapsLock());
  EXPECT_EQ(!initial_caps_lock_state_, xkeyboard_.CapsLockIsEnabled());
  handler_->OnCapsLockChange(!initial_caps_lock_state_);
  EXPECT_EQ(!initial_caps_lock_state_, handler_->caps_lock_is_on_for_test());
  EXPECT_TRUE(handler_->HandleToggleCapsLock());
  handler_->OnCapsLockChange(initial_caps_lock_state_);
  EXPECT_EQ(initial_caps_lock_state_, xkeyboard_.CapsLockIsEnabled());
  EXPECT_EQ(initial_caps_lock_state_, handler_->caps_lock_is_on_for_test());
}
#endif
<|endoftext|>


<commit_before>// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include <vespa/fastos/fastos.h>
#include <vespa/log/log.h>
LOG_SETUP("attribute_populator_test");
#include <vespa/vespalib/testkit/testapp.h>

#include <vespa/searchcommon/common/schema.h>
#include <vespa/searchcore/proton/attribute/attributemanager.h>
#include <vespa/searchcore/proton/attribute/attribute_populator.h>
#include <vespa/searchcore/proton/test/test.h>
#include <vespa/searchlib/index/docbuilder.h>
#include <vespa/searchlib/index/dummyfileheadercontext.h>
#include <vespa/vespalib/util/stringfmt.h>
#include <vespa/searchcore/proton/common/hw_info.h>
#include <vespa/searchlib/common/foregroundtaskexecutor.h>

using namespace document;
using namespace proton;
using namespace search;
using namespace search::index;

typedef search::attribute::Config AVConfig;
typedef search::attribute::BasicType AVBasicType;

const vespalib::string TEST_DIR = "testdir";
const uint64_t CREATE_SERIAL_NUM = 8u;

Schema
createSchema()
{
    Schema schema;
    schema.addAttributeField(Schema::AttributeField("a1", Schema::DataType::INT32));
    return schema;
}

struct DocContext
{
    Schema _schema;
    DocBuilder _builder;
    DocContext()
        : _schema(createSchema()),
          _builder(_schema)
    {
    }
    Document::UP create(uint32_t id, int64_t fieldValue) {
        vespalib::string docId =
                vespalib::make_string("id:searchdocument:searchdocument::%u", id);
        return _builder.startDocument(docId).
                startAttributeField("a1").addInt(fieldValue).endField().
                endDocument();
    }
};

struct Fixture
{
    test::DirectoryHandler _testDir;
    DummyFileHeaderContext _fileHeader;
    ForegroundTaskExecutor _attributeFieldWriter;
    HwInfo                 _hwInfo;
    AttributeManager::SP _mgr;
    std::unique_ptr<AttributePopulator> _pop;
    DocContext _ctx;
    Fixture()
        : _testDir(TEST_DIR),
          _fileHeader(),
          _attributeFieldWriter(),
          _hwInfo(),
          _mgr(new AttributeManager(TEST_DIR, "test.subdb",
                  TuneFileAttributes(),
                                    _fileHeader, _attributeFieldWriter, _hwInfo)),
          _pop(),
          _ctx()
    {
        _mgr->addAttribute({ "a1", AVConfig(AVBasicType::INT32)},
                CREATE_SERIAL_NUM);
        _pop = std::make_unique<AttributePopulator>(_mgr, 1, "test", CREATE_SERIAL_NUM);
    }
    AttributeGuard::UP getAttr() {
        return _mgr->getAttribute("a1");
    }
};

TEST_F("require that reprocess with document populates attribute", Fixture)
{
    AttributeGuard::UP attr = f.getAttr();
    EXPECT_EQUAL(1u, attr->get()->getNumDocs());

    f._pop->handleExisting(5, *f._ctx.create(0, 33));
    EXPECT_EQUAL(6u, attr->get()->getNumDocs());
    EXPECT_EQUAL(33, attr->get()->getInt(5));
    EXPECT_EQUAL(1u, attr->get()->getStatus().getLastSyncToken());

    f._pop->handleExisting(6, *f._ctx.create(1, 44));
    EXPECT_EQUAL(7u, attr->get()->getNumDocs());
    EXPECT_EQUAL(44, attr->get()->getInt(6));
    EXPECT_EQUAL(2u, attr->get()->getStatus().getLastSyncToken());
    f._pop->done();
    EXPECT_EQUAL(CREATE_SERIAL_NUM, attr->get()->getStatus().getLastSyncToken());
}

TEST_MAIN()
{
    TEST_RUN_ALL();
}
<commit_msg>Remove test dir before starting test to ensure a clean slate.<commit_after>// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include <vespa/fastos/fastos.h>
#include <vespa/log/log.h>
LOG_SETUP("attribute_populator_test");
#include <vespa/vespalib/testkit/testapp.h>

#include <vespa/searchcommon/common/schema.h>
#include <vespa/searchcore/proton/attribute/attributemanager.h>
#include <vespa/searchcore/proton/attribute/attribute_populator.h>
#include <vespa/searchcore/proton/test/test.h>
#include <vespa/searchlib/index/docbuilder.h>
#include <vespa/searchlib/index/dummyfileheadercontext.h>
#include <vespa/vespalib/util/stringfmt.h>
#include <vespa/searchcore/proton/common/hw_info.h>
#include <vespa/searchlib/common/foregroundtaskexecutor.h>

using namespace document;
using namespace proton;
using namespace search;
using namespace search::index;

typedef search::attribute::Config AVConfig;
typedef search::attribute::BasicType AVBasicType;

const vespalib::string TEST_DIR = "testdir";
const uint64_t CREATE_SERIAL_NUM = 8u;

Schema
createSchema()
{
    Schema schema;
    schema.addAttributeField(Schema::AttributeField("a1", Schema::DataType::INT32));
    return schema;
}

struct DocContext
{
    Schema _schema;
    DocBuilder _builder;
    DocContext()
        : _schema(createSchema()),
          _builder(_schema)
    {
    }
    Document::UP create(uint32_t id, int64_t fieldValue) {
        vespalib::string docId =
                vespalib::make_string("id:searchdocument:searchdocument::%u", id);
        return _builder.startDocument(docId).
                startAttributeField("a1").addInt(fieldValue).endField().
                endDocument();
    }
};

struct Fixture
{
    test::DirectoryHandler _testDir;
    DummyFileHeaderContext _fileHeader;
    ForegroundTaskExecutor _attributeFieldWriter;
    HwInfo                 _hwInfo;
    AttributeManager::SP _mgr;
    std::unique_ptr<AttributePopulator> _pop;
    DocContext _ctx;
    Fixture()
        : _testDir(TEST_DIR),
          _fileHeader(),
          _attributeFieldWriter(),
          _hwInfo(),
          _mgr(new AttributeManager(TEST_DIR, "test.subdb",
                  TuneFileAttributes(),
                                    _fileHeader, _attributeFieldWriter, _hwInfo)),
          _pop(),
          _ctx()
    {
        _mgr->addAttribute({ "a1", AVConfig(AVBasicType::INT32)},
                CREATE_SERIAL_NUM);
        _pop = std::make_unique<AttributePopulator>(_mgr, 1, "test", CREATE_SERIAL_NUM);
    }
    AttributeGuard::UP getAttr() {
        return _mgr->getAttribute("a1");
    }
};

TEST_F("require that reprocess with document populates attribute", Fixture)
{
    AttributeGuard::UP attr = f.getAttr();
    EXPECT_EQUAL(1u, attr->get()->getNumDocs());

    f._pop->handleExisting(5, *f._ctx.create(0, 33));
    EXPECT_EQUAL(6u, attr->get()->getNumDocs());
    EXPECT_EQUAL(33, attr->get()->getInt(5));
    EXPECT_EQUAL(1u, attr->get()->getStatus().getLastSyncToken());

    f._pop->handleExisting(6, *f._ctx.create(1, 44));
    EXPECT_EQUAL(7u, attr->get()->getNumDocs());
    EXPECT_EQUAL(44, attr->get()->getInt(6));
    EXPECT_EQUAL(2u, attr->get()->getStatus().getLastSyncToken());
    f._pop->done();
    EXPECT_EQUAL(CREATE_SERIAL_NUM, attr->get()->getStatus().getLastSyncToken());
}

TEST_MAIN()
{
    vespalib::rmdir(TEST_DIR, true);
    TEST_RUN_ALL();
}
<|endoftext|>


<commit_before>/*******************************************************************************
 * c7a/net/net-endpoint.hpp
 *
 * Part of Project c7a.
 *
 * Copyright (C) 2015 Timo Bingmann <tb@panthema.net>
 *
 * This file has no license. Only Chuck Norris can compile it.
 ******************************************************************************/

#pragma once
#ifndef C7A_NET_NET_ENDPOINT_HEADER
#define C7A_NET_NET_ENDPOINT_HEADER

#include <iostream>
#include <sstream>
#include <string>
#include <cstdlib>
#include <vector>

namespace c7a {

namespace net {

//! \addtogroup net Network Communication
//! \{

/*!
 * Identifies a remote worker in a NetGroup, currently contains only its host
 * address. In future, the master/worker coordination classes should use this to
 * build a NetGroup, or rebuild it after a network failure.
 */
class NetEndpoint
{
public:
    //store some kind of endpoint information here
    const std::string hostport;

    explicit NetEndpoint(const std::string& hostport)
        : hostport(hostport) { }

    static std::vector<NetEndpoint> ParseEndpointList(std::string str)
    {
        std::stringstream stream;
        stream << str;
        std::vector<NetEndpoint> endpoints;

        std::string hostport;

        while (stream >> hostport) {
            endpoints.push_back(NetEndpoint(hostport));
        }
        return endpoints;
    }
};

//! \}

} // namespace net

} // namespace c7a

#endif // !C7A_NET_NET_ENDPOINT_HEADER

/******************************************************************************/
<commit_msg>cherry picking the << operator for NetEndpoint<commit_after>/*******************************************************************************
 * c7a/net/net-endpoint.hpp
 *
 * Part of Project c7a.
 *
 * Copyright (C) 2015 Timo Bingmann <tb@panthema.net>
 *
 * This file has no license. Only Chuck Norris can compile it.
 ******************************************************************************/

#pragma once
#ifndef C7A_NET_NET_ENDPOINT_HEADER
#define C7A_NET_NET_ENDPOINT_HEADER

#include <iostream>
#include <sstream>
#include <string>
#include <cstdlib>
#include <vector>

namespace c7a {
namespace net {
//! \addtogroup net Network Communication
//! \{

/*!
 * Identifies a remote worker in a NetGroup, currently contains only its host
 * address. In future, the master/worker coordination classes should use this to
 * build a NetGroup, or rebuild it after a network failure.
 */
class NetEndpoint
{
public:
    //store some kind of endpoint information here
    const std::string hostport;

    explicit NetEndpoint(const std::string& hostport)
        : hostport(hostport) { }

    static std::vector<NetEndpoint> ParseEndpointList(std::string str)
    {
        std::stringstream stream;
        stream << str;
        std::vector<NetEndpoint> endpoints;

        std::string hostport;

        while (stream >> hostport) {
            endpoints.push_back(NetEndpoint(hostport));
        }
        return endpoints;
    }
};

static std::ostream& operator << (std::ostream& os, NetEndpoint const& endpoint)
{
    return os << endpoint.hostport;
}

//! \}
} // namespace net
} // namespace c7a

#endif // !C7A_NET_NET_ENDPOINT_HEADER

/******************************************************************************/
<|endoftext|>


<commit_before>/*
 * Software License Agreement (BSD License)
 *
 *  Copyright (c) 2014 Max-Planck-Institute for Intelligent Systems,
 *                     University of Southern California
 *    Jan Issac (jan.issac@gmail.com)
 *
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above
 *     copyright notice, this list of conditions and the following
 *     disclaimer in the documentation and/or other materials provided
 *     with the distribution.
 *   * Neither the name of Willow Garage, Inc. nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *  POSSIBILITY OF SUCH DAMAGE.
 *
 */

/**
 * @date 05/25/2014
 * @author Jan Issac (jan.issac@gmail.com)
 * Max-Planck-Institute for Intelligent Systems, University of Southern California (USC)
 */

#ifndef STATE_FILTERING_DISTRIBUTION_FEATURES_SAMPLEBALE_HPP
#define STATE_FILTERING_DISTRIBUTION_FEATURES_SAMPLEBALE_HPP

#include <state_filtering/distributions/distribution.hpp>

namespace distributions
{

template <typename ScalarType_, typename VectorType_>
class Sampleable: public Distribution<ScalarType_, VectorType_>
{
public:
    typedef Distribution<ScalarType_, VectorType_>  BaseType;
    typedef typename BaseType::ScalarType           ScalarType;
    typedef typename BaseType::VectorType           VectorType;

public:
    virtual ~Sampleable() { }

    virtual VectorType Sample() = 0;
};

}

#endif
<commit_msg>Added authors<commit_after>/*
 * Software License Agreement (BSD License)
 *
 *  Copyright (c) 2014 Max-Planck-Institute for Intelligent Systems,
 *                     University of Southern California
 *    Jan Issac (jan.issac@gmail.com)
 *
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above
 *     copyright notice, this list of conditions and the following
 *     disclaimer in the documentation and/or other materials provided
 *     with the distribution.
 *   * Neither the name of Willow Garage, Inc. nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *  POSSIBILITY OF SUCH DAMAGE.
 *
 */

/**
 * @date 05/25/2014
 * @author Jan Issac (jan.issac@gmail.com)
 * @author Manuel Wuthrich (manuel.wuthrich@gmail.com)
 * Max-Planck-Institute for Intelligent Systems, University of Southern California (USC)
 */

#ifndef STATE_FILTERING_DISTRIBUTION_FEATURES_SAMPLEBALE_HPP
#define STATE_FILTERING_DISTRIBUTION_FEATURES_SAMPLEBALE_HPP

#include <state_filtering/distributions/distribution.hpp>

namespace distributions
{

template <typename ScalarType_, typename VectorType_>
class Sampleable: public Distribution<ScalarType_, VectorType_>
{
public:
    typedef Distribution<ScalarType_, VectorType_>  BaseType;
    typedef typename BaseType::ScalarType           ScalarType;
    typedef typename BaseType::VectorType           VectorType;

public:
    virtual ~Sampleable() { }

    virtual VectorType Sample() = 0;
};

}

#endif
<|endoftext|>


<commit_before>//
// Copyright (c) 2012 Advanced Micro Devices, Inc. All rights reserved.
//

#include "commandqueue.hpp"
#include "thread/monitor.hpp"
#include "device/device.hpp"
#include "platform/context.hpp"

/*!
 * \file commandQueue.cpp
 * \brief  Definitions for HostQueue object.
 *
 * \author Laurent Morichetti (laurent.morichetti@amd.com)
 * \date   October 2008
 */

namespace amd {

HostQueue::HostQueue(Context& context, Device& device, cl_command_queue_properties properties,
                     uint queueRTCUs, Priority priority)
    : CommandQueue(context, device, properties,
                   device.info().queueProperties_ | CL_QUEUE_COMMAND_INTERCEPT_ENABLE_AMD,
                   queueRTCUs, priority) {
  if (thread_.state() >= Thread::INITIALIZED) {
    ScopedLock sl(queueLock_);
    thread_.start(this);
    queueLock_.wait();
  }
}

bool HostQueue::terminate() {
  if (Os::isThreadAlive(thread_)) {
    // Make sure all the commands are finished on the device.
    finish();

    // Kill the command queue loop.
    thread_.acceptingCommands_ = false;

    // Wake-up the command loop, so it can exit
    flush();

    // FIXME_lmoriche: fix termination handshake
    while (thread_.state() < Thread::FINISHED) {
      Os::yield();
    }
  }

  if (Agent::shouldPostCommandQueueEvents()) {
    Agent::postCommandQueueFree(as_cl(this->asCommandQueue()));
  }

  return true;
}

void HostQueue::finish() {
  // Send a finish to make sure we finished all commands
  Command* command = new Marker(*this, false);
  if (command == NULL) {
    return;
  }

  command->enqueue();
  command->awaitCompletion();
  command->release();
}

void HostQueue::loop(device::VirtualDevice* virtualDevice) {
  cl_int(CL_CALLBACK * commandIntercept)(cl_event, cl_int*) =
      properties().test(CL_QUEUE_COMMAND_INTERCEPT_ENABLE_AMD) ? context().info().commandIntercept_
                                                               : NULL;

  // Notify the caller that the queue is ready to accept commands.
  {
    ScopedLock sl(queueLock_);
    thread_.acceptingCommands_ = true;
    queueLock_.notify();
  }
  // Create a command batch with all the commands present in the queue.
  Command* head = NULL;
  Command* tail = NULL;
  while (true) {
    // Get one command from the queue
    Command* command = queue_.dequeue();
    if (command == NULL) {
      ScopedLock sl(queueLock_);
      while ((command = queue_.dequeue()) == NULL) {
        if (!thread_.acceptingCommands_) {
          return;
        }
        queueLock_.wait();
      }
    }

    command->retain();

    // Process the command's event wait list.
    const Command::EventWaitList& events = command->eventWaitList();
    bool dependencyFailed = false;

    for (const auto& it : events) {
      // Only wait if the command is enqueued into another queue.
      if (it->command().queue() != this) {
        virtualDevice->flush(head, true);
        tail = head = NULL;
        dependencyFailed |= !it->awaitCompletion();
      }
    }

    // Insert the command to the linked list.
    if (NULL == head) {  // if the list is empty
      head = tail = command;
    } else {
      tail->setNext(command);
      tail = command;
    }

    if (dependencyFailed) {
      command->setStatus(CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST);
      continue;
    }

    command->setStatus(CL_SUBMITTED);

    cl_int result;
    if ((commandIntercept != NULL) && commandIntercept(as_cl<Event>(command), &result)) {
      // The command was handled by the callback.
      command->setStatus(CL_RUNNING, command->profilingInfo().submitted_);
      command->setStatus(result);
      continue;
    }

    // Submit to the device queue.
    command->submit(*virtualDevice);

    // if we are in intercept mode or this is a user invisible marker command
    if ((0 == command->type()) || (commandIntercept != NULL)) {
      virtualDevice->flush(head);
      tail = head = NULL;
    }
  }  // while (true) {
}

void HostQueue::append(Command& command) {
  // We retain the command here. It will be released when its status
  // changes to CL_COMPLETE
  command.retain();
  command.setStatus(CL_QUEUED);
  queue_.enqueue(&command);
}

DeviceQueue::~DeviceQueue() {
  delete virtualDevice_;
  ScopedLock lock(context().lock());
  context().removeDeviceQueue(device(), this);
}

bool DeviceQueue::create() {
  static const bool InteropQueue = true;
  const bool defaultDeviceQueue = properties().test(CL_QUEUE_ON_DEVICE_DEFAULT);
  bool result = false;

  virtualDevice_ = device().createVirtualDevice(this);
  if (virtualDevice_ != NULL) {
    result = true;
    context().addDeviceQueue(device(), this, defaultDeviceQueue);
  }

  return result;
}

}  // namespace amd {
<commit_msg>P4 to Git Change 1550567 by lmoriche@lmoriche_opencl_dev2 on 2018/05/04 16:11:50<commit_after>//
// Copyright (c) 2012 Advanced Micro Devices, Inc. All rights reserved.
//

#include "commandqueue.hpp"
#include "thread/monitor.hpp"
#include "device/device.hpp"
#include "platform/context.hpp"

/*!
 * \file commandQueue.cpp
 * \brief  Definitions for HostQueue object.
 *
 * \author Laurent Morichetti (laurent.morichetti@amd.com)
 * \date   October 2008
 */

namespace amd {

HostQueue::HostQueue(Context& context, Device& device, cl_command_queue_properties properties,
                     uint queueRTCUs, Priority priority)
    : CommandQueue(context, device, properties,
                   device.info().queueProperties_ | CL_QUEUE_COMMAND_INTERCEPT_ENABLE_AMD,
                   queueRTCUs, priority) {
  if (thread_.state() >= Thread::INITIALIZED) {
    ScopedLock sl(queueLock_);
    thread_.start(this);
    queueLock_.wait();
  }
}

bool HostQueue::terminate() {
  if (Os::isThreadAlive(thread_)) {
    // Wake-up the command loop, so it can exit
    {
      ScopedLock sl(queueLock_);
      thread_.acceptingCommands_ = false;
      queueLock_.notify();
    }

    // FIXME_lmoriche: fix termination handshake
    while (thread_.state() < Thread::FINISHED) {
      Os::yield();
    }
  }

  if (Agent::shouldPostCommandQueueEvents()) {
    Agent::postCommandQueueFree(as_cl(this->asCommandQueue()));
  }

  return true;
}

void HostQueue::finish() {
  // Send a finish to make sure we finished all commands
  Command* command = new Marker(*this, false);
  if (command == NULL) {
    return;
  }

  command->enqueue();
  command->awaitCompletion();
  command->release();
}

void HostQueue::loop(device::VirtualDevice* virtualDevice) {
  cl_int(CL_CALLBACK * commandIntercept)(cl_event, cl_int*) =
      properties().test(CL_QUEUE_COMMAND_INTERCEPT_ENABLE_AMD) ? context().info().commandIntercept_
                                                               : NULL;

  // Notify the caller that the queue is ready to accept commands.
  {
    ScopedLock sl(queueLock_);
    thread_.acceptingCommands_ = true;
    queueLock_.notify();
  }
  // Create a command batch with all the commands present in the queue.
  Command* head = NULL;
  Command* tail = NULL;
  while (true) {
    // Get one command from the queue
    Command* command = queue_.dequeue();
    if (command == NULL) {
      ScopedLock sl(queueLock_);
      while ((command = queue_.dequeue()) == NULL) {
        if (!thread_.acceptingCommands_) {
          return;
        }
        queueLock_.wait();
      }
    }

    command->retain();

    // Process the command's event wait list.
    const Command::EventWaitList& events = command->eventWaitList();
    bool dependencyFailed = false;

    for (const auto& it : events) {
      // Only wait if the command is enqueued into another queue.
      if (it->command().queue() != this) {
        virtualDevice->flush(head, true);
        tail = head = NULL;
        dependencyFailed |= !it->awaitCompletion();
      }
    }

    // Insert the command to the linked list.
    if (NULL == head) {  // if the list is empty
      head = tail = command;
    } else {
      tail->setNext(command);
      tail = command;
    }

    if (dependencyFailed) {
      command->setStatus(CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST);
      continue;
    }

    command->setStatus(CL_SUBMITTED);

    cl_int result;
    if ((commandIntercept != NULL) && commandIntercept(as_cl<Event>(command), &result)) {
      // The command was handled by the callback.
      command->setStatus(CL_RUNNING, command->profilingInfo().submitted_);
      command->setStatus(result);
      continue;
    }

    // Submit to the device queue.
    command->submit(*virtualDevice);

    // if we are in intercept mode or this is a user invisible marker command
    if ((0 == command->type()) || (commandIntercept != NULL)) {
      virtualDevice->flush(head);
      tail = head = NULL;
    }
  }  // while (true) {
}

void HostQueue::append(Command& command) {
  // We retain the command here. It will be released when its status
  // changes to CL_COMPLETE
  command.retain();
  command.setStatus(CL_QUEUED);
  queue_.enqueue(&command);
}

DeviceQueue::~DeviceQueue() {
  delete virtualDevice_;
  ScopedLock lock(context().lock());
  context().removeDeviceQueue(device(), this);
}

bool DeviceQueue::create() {
  static const bool InteropQueue = true;
  const bool defaultDeviceQueue = properties().test(CL_QUEUE_ON_DEVICE_DEFAULT);
  bool result = false;

  virtualDevice_ = device().createVirtualDevice(this);
  if (virtualDevice_ != NULL) {
    result = true;
    context().addDeviceQueue(device(), this, defaultDeviceQueue);
  }

  return result;
}

}  // namespace amd {
<|endoftext|>


<commit_before>#include <atomic>
#include "cuda/cudamemory.h"
#include "cuda/cudautil.h"

#include <cuda_runtime.h>
#include <device_launch_parameters.h>

namespace idaten {
	static std::atomic<uint32_t> g_heapsize(0);

	CudaMemory::CudaMemory(uint32_t bytes)
	{
		init(bytes);
	}

	CudaMemory::CudaMemory(const void* p, uint32_t bytes)
	{
		init(bytes);
		write(p, bytes);
	}

	CudaMemory::~CudaMemory()
	{
		free();
	}

	void CudaMemory::init(uint32_t bytes)
	{
		if (m_bytes == 0) {
			checkCudaErrors(cudaMalloc((void**)&m_device, bytes));
			m_bytes = bytes;

			g_heapsize += bytes;
		}
	}

	uint32_t CudaMemory::write(const void* p, uint32_t sizeBytes, uint32_t offsetBytes/*= 0*/)
	{
		if (!m_device) {
			init(sizeBytes);
		}

		if (sizeBytes > m_bytes) {
			AT_ASSERT(false);
			return 0;
		}

		uint8_t* dst = (uint8_t*)m_device;

		checkCudaErrors(cudaMemcpyAsync(dst + offsetBytes, p, sizeBytes, cudaMemcpyDefault));

		return sizeBytes;
	}

	uint32_t CudaMemory::read(void* p, uint32_t size)
	{
		if (size == 0) {
			size = m_bytes;
		}

		if (size > m_bytes) {
			AT_ASSERT(false);
			return 0;
		}

		checkCudaErrors(cudaMemcpyAsync(p, m_device, size, cudaMemcpyDeviceToHost));

		return size;
	}

	void CudaMemory::free()
	{
		if (m_device) {
			checkCudaErrors(cudaFree(m_device));
			m_device = nullptr;

			g_heapsize -= m_bytes;
		}
		m_bytes = 0;
	}

	uint32_t CudaMemory::getHeapSize()
	{
		return g_heapsize.load();
	}
}<commit_msg>Modify not to use async to read memory from device.<commit_after>#include <atomic>
#include "cuda/cudamemory.h"
#include "cuda/cudautil.h"

#include <cuda_runtime.h>
#include <device_launch_parameters.h>

namespace idaten {
	static std::atomic<uint32_t> g_heapsize(0);

	CudaMemory::CudaMemory(uint32_t bytes)
	{
		init(bytes);
	}

	CudaMemory::CudaMemory(const void* p, uint32_t bytes)
	{
		init(bytes);
		write(p, bytes);
	}

	CudaMemory::~CudaMemory()
	{
		free();
	}

	void CudaMemory::init(uint32_t bytes)
	{
		if (m_bytes == 0) {
			checkCudaErrors(cudaMalloc((void**)&m_device, bytes));
			m_bytes = bytes;

			g_heapsize += bytes;
		}
	}

	uint32_t CudaMemory::write(const void* p, uint32_t sizeBytes, uint32_t offsetBytes/*= 0*/)
	{
		if (!m_device) {
			init(sizeBytes);
		}

		if (sizeBytes > m_bytes) {
			AT_ASSERT(false);
			return 0;
		}

		uint8_t* dst = (uint8_t*)m_device;

		checkCudaErrors(cudaMemcpyAsync(dst + offsetBytes, p, sizeBytes, cudaMemcpyDefault));

		return sizeBytes;
	}

	uint32_t CudaMemory::read(void* p, uint32_t size)
	{
		if (size == 0) {
			size = m_bytes;
		}

		if (size > m_bytes) {
			AT_ASSERT(false);
			return 0;
		}

		checkCudaErrors(cudaMemcpy(p, m_device, size, cudaMemcpyDeviceToHost));

		return size;
	}

	void CudaMemory::free()
	{
		if (m_device) {
			checkCudaErrors(cudaFree(m_device));
			m_device = nullptr;

			g_heapsize -= m_bytes;
		}
		m_bytes = 0;
	}

	uint32_t CudaMemory::getHeapSize()
	{
		return g_heapsize.load();
	}
}<|endoftext|>


<commit_before>/*

Copyright (c) 2008, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include "test.hpp"
#include "setup_transfer.hpp"
#include "libtorrent/socket.hpp"
#include "libtorrent/io.hpp"
#include <cstring>
#include <boost/bind.hpp>
#include <iostream>

using namespace libtorrent;

int read_message(stream_socket& s, char* buffer)
{
	using namespace libtorrent::detail;
	error_code ec;
	libtorrent::asio::read(s, libtorrent::asio::buffer(buffer, 4)
		, libtorrent::asio::transfer_all(), ec);
	if (ec)
	{
		std::cout << time_now_string() << ": " << ec.message() << std::endl;
		exit(1);
	}
	char* ptr = buffer;
	int length = read_int32(ptr);

	libtorrent::asio::read(s, libtorrent::asio::buffer(buffer, length)
		, libtorrent::asio::transfer_all(), ec);
	if (ec)
	{
		std::cout << time_now_string() << ": " << ec.message() << std::endl;
		exit(1);
	}
	return length;
}

char const* message_name[] = {"choke", "unchoke", "interested", "not_interested"
	, "have", "bitfield", "request", "piece", "cancel", "dht_port", "", "", ""
	, "suggest_piece", "have_all", "have_none", "reject_request", "allowed_fast"};

void send_allow_fast(stream_socket& s, int piece)
{
	std::cout << time_now_string() << " ==> allow fast: " << piece << std::endl;
	using namespace libtorrent::detail;
	char msg[] = "\0\0\0\x05\x11\0\0\0\0";
	char* ptr = msg + 5;
	write_int32(piece, ptr);
	error_code ec;
	libtorrent::asio::write(s, libtorrent::asio::buffer(msg, 9)
		, libtorrent::asio::transfer_all(), ec);
}

void send_suggest_piece(stream_socket& s, int piece)
{
	std::cout << time_now_string() << " ==> suggest piece: " << piece << std::endl;
	using namespace libtorrent::detail;
	char msg[] = "\0\0\0\x05\x0d\0\0\0\0";
	char* ptr = msg + 5;
	write_int32(piece, ptr);
	error_code ec;
	libtorrent::asio::write(s, libtorrent::asio::buffer(msg, 9)
		, libtorrent::asio::transfer_all(), ec);
}

void send_keepalive(stream_socket& s)
{
	std::cout << time_now_string() << " ==> keepalive" << std::endl;
	char msg[] = "\0\0\0\0";
	error_code ec;
	libtorrent::asio::write(s, libtorrent::asio::buffer(msg, 4)
		, libtorrent::asio::transfer_all(), ec);
}

void send_unchoke(stream_socket& s)
{
	std::cout << time_now_string() << " ==> unchoke" << std::endl;
	char msg[] = "\0\0\0\x01\x01";
	error_code ec;
	libtorrent::asio::write(s, libtorrent::asio::buffer(msg, 5)
		, libtorrent::asio::transfer_all(), ec);
}

void do_handshake(stream_socket& s, sha1_hash const& ih, char* buffer)
{
	char handshake[] = "\x13" "BitTorrent protocol\0\0\0\0\0\0\0\x04"
		"                    " // space for info-hash
		"aaaaaaaaaaaaaaaaaaaa" // peer-id
		"\0\0\0\x01\x0e"; // have_all
	std::cout << time_now_string() << " ==> handshake" << std::endl;
	std::cout << time_now_string() << " ==> have_all" << std::endl;
	error_code ec;
	std::memcpy(handshake + 28, ih.begin(), 20);
	libtorrent::asio::write(s, libtorrent::asio::buffer(handshake, sizeof(handshake) - 1)
		, libtorrent::asio::transfer_all(), ec);

	// read handshake
	libtorrent::asio::read(s, libtorrent::asio::buffer(buffer, 68)
		, libtorrent::asio::transfer_all(), ec);
	if (ec)
	{
		std::cout << time_now_string() << ": " << ec.message() << std::endl;
		exit(1);
	}
	std::cout << time_now_string() << " <== handshake" << std::endl;

	TEST_CHECK(buffer[0] == 19);
	TEST_CHECK(std::memcmp(buffer + 1, "BitTorrent protocol", 19) == 0);

	char* extensions = buffer + 20;
	// check for fast extension support
	TEST_CHECK(extensions[7] & 0x4);

#ifndef TORRENT_DISABLE_EXTENSIONS
	// check for extension protocol support
	TEST_CHECK(extensions[5] & 0x10);
#endif

#ifndef TORRENT_DISABLE_DHT
	// check for DHT support
	TEST_CHECK(extensions[7] & 0x1);
#endif

	TEST_CHECK(std::memcmp(buffer + 28, ih.begin(), 20) == 0);
}

// makes sure that pieces that are allowed and then
// rejected aren't requested again
void test_reject_fast()
{
	std::cerr << " === test reject ===" << std::endl;

	boost::intrusive_ptr<torrent_info> t = ::create_torrent();
	sha1_hash ih = t->info_hash();
	session ses1(fingerprint("LT", 0, 1, 0, 0), std::make_pair(48900, 49000), "0.0.0.0", 0);
	error_code ec;
	add_torrent_params p;
	p.ti = t;
	p.save_path = "./tmp1_fast";
	ses1.add_torrent(p, ec);

	test_sleep(2000);

	io_service ios;
	stream_socket s(ios);
	s.connect(tcp::endpoint(address::from_string("127.0.0.1", ec), ses1.listen_port()), ec);

	char recv_buffer[1000];
	do_handshake(s, ih, recv_buffer);

	std::vector<int> allowed_fast;
	allowed_fast.push_back(0);
	allowed_fast.push_back(1);
	allowed_fast.push_back(2);
	allowed_fast.push_back(3);

	std::for_each(allowed_fast.begin(), allowed_fast.end()
		, boost::bind(&send_allow_fast, boost::ref(s), _1));

	while (!allowed_fast.empty())
	{
		read_message(s, recv_buffer);
		int msg = recv_buffer[0];
		if (msg >= 0 && msg < int(sizeof(message_name)/sizeof(message_name[0])))
			std::cerr << time_now_string() << " <== " << message_name[msg] << std::endl;
		else
			std::cerr << time_now_string() << " <== " << msg << std::endl;
		if (recv_buffer[0] != 0x6) continue;

		using namespace libtorrent::detail;
		char* ptr = recv_buffer + 1;
		int piece = read_int32(ptr);

		std::vector<int>::iterator i = std::find(allowed_fast.begin()
			, allowed_fast.end(), piece);
		TEST_CHECK(i != allowed_fast.end());
		if (i != allowed_fast.end())
			allowed_fast.erase(i);
		// send reject request
		recv_buffer[0] = 0x10;
		error_code ec;
		std::cerr << time_now_string() << " ==> reject" << std::endl;
		libtorrent::asio::write(s, libtorrent::asio::buffer("\0\0\0\x0d", 4)
			, libtorrent::asio::transfer_all(), ec);
		libtorrent::asio::write(s, libtorrent::asio::buffer(recv_buffer, 13)
			, libtorrent::asio::transfer_all(), ec);
	}
}

void test_respect_suggest()
{
	std::cerr << " === test suggest ===" << std::endl;
	boost::intrusive_ptr<torrent_info> t = ::create_torrent();
	sha1_hash ih = t->info_hash();
	session ses1(fingerprint("LT", 0, 1, 0, 0), std::make_pair(48900, 49000), "0.0.0.0", 0);

	error_code ec;
	add_torrent_params p;
	p.ti = t;
	p.save_path = "./tmp1_fast";
	ses1.add_torrent(p, ec);

	test_sleep(2000);

	io_service ios;
	stream_socket s(ios);
	s.connect(tcp::endpoint(address::from_string("127.0.0.1", ec), ses1.listen_port()), ec);

	char recv_buffer[1000];
	do_handshake(s, ih, recv_buffer);

	std::vector<int> suggested;
	suggested.push_back(0);
	suggested.push_back(1);
	suggested.push_back(2);
	suggested.push_back(3);

	std::for_each(suggested.begin(), suggested.end()
		, boost::bind(&send_suggest_piece, boost::ref(s), _1));

	send_unchoke(s);

	send_keepalive(s);

	int fail_counter = 100;
	while (!suggested.empty() && fail_counter > 0)
	{
		read_message(s, recv_buffer);
		std::cerr << time_now_string() << " <== ";
		int msg = recv_buffer[0];
		if (msg >= 0 && msg < int(sizeof(message_name)/sizeof(message_name[0])))
			std::cerr << message_name[msg] << std::endl;
		else
			std::cerr << msg << std::endl;
		fail_counter--;
		if (recv_buffer[0] != 0x6) continue;

		using namespace libtorrent::detail;
		char* ptr = recv_buffer + 1;
		int piece = read_int32(ptr);

		std::vector<int>::iterator i = std::find(suggested.begin()
			, suggested.end(), piece);
		TEST_CHECK(i != suggested.end());
		if (i != suggested.end())
			suggested.erase(i);
		// send reject request
		recv_buffer[0] = 0x10;
		error_code ec;
		std::cerr << time_now_string() << " ==> reject" << std::endl;
		libtorrent::asio::write(s, libtorrent::asio::buffer("\0\0\0\x0d", 4)
			, libtorrent::asio::transfer_all(), ec);
		libtorrent::asio::write(s, libtorrent::asio::buffer(recv_buffer, 13)
			, libtorrent::asio::transfer_all(), ec);
	}
	TEST_CHECK(fail_counter > 0);
}

int test_main()
{
	test_reject_fast();
	test_respect_suggest();
	return 0;
}

<commit_msg>improve print-out of fast extension test<commit_after>/*

Copyright (c) 2008, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include "test.hpp"
#include "setup_transfer.hpp"
#include "libtorrent/socket.hpp"
#include "libtorrent/io.hpp"
#include <cstring>
#include <boost/bind.hpp>
#include <iostream>

using namespace libtorrent;

int read_message(stream_socket& s, char* buffer)
{
	using namespace libtorrent::detail;
	error_code ec;
	libtorrent::asio::read(s, libtorrent::asio::buffer(buffer, 4)
		, libtorrent::asio::transfer_all(), ec);
	if (ec)
	{
		std::cout << time_now_string() << ": " << ec.message() << std::endl;
		exit(1);
	}
	char* ptr = buffer;
	int length = read_int32(ptr);

	libtorrent::asio::read(s, libtorrent::asio::buffer(buffer, length)
		, libtorrent::asio::transfer_all(), ec);
	if (ec)
	{
		std::cout << time_now_string() << ": " << ec.message() << std::endl;
		exit(1);
	}
	return length;
}

void print_message(char const* buffer, int len)
{
	char const* message_name[] = {"choke", "unchoke", "interested", "not_interested"
		, "have", "bitfield", "request", "piece", "cancel", "dht_port", "", "", ""
		, "suggest_piece", "have_all", "have_none", "reject_request", "allowed_fast"};

	char message[50];
	char extra[300];
	extra[0] = 0;
	if (len == 0)
	{
		strcpy(message, "keepalive");
	}
	else
	{
		int msg = buffer[0];
		if (msg >= 0 && msg < int(sizeof(message_name)/sizeof(message_name[0])))
			strcpy(message, message_name[msg]);
		else
			snprintf(message, sizeof(message), "unknown[%d]", msg);

		if (msg == 0x6 && len == 13)
		{
			peer_request r;
			const char* ptr = buffer + 1;
			r.piece = detail::read_int32(ptr);
			r.start = detail::read_int32(ptr);
			r.length = detail::read_int32(ptr);
			snprintf(extra, sizeof(extra), "p: %d s: %d l: %d", r.piece, r.start, r.length);
		}
		else if (msg == 0x11 && len == 5)
		{
			const char* ptr = buffer + 1;
			int index = detail::read_int32(ptr);
			snprintf(extra, sizeof(extra), "p: %d", index);
		}
	}

	fprintf(stderr, "%s <== %s %s\n", time_now_string(), message, extra);
}

void send_allow_fast(stream_socket& s, int piece)
{
	std::cout << time_now_string() << " ==> allow fast: " << piece << std::endl;
	using namespace libtorrent::detail;
	char msg[] = "\0\0\0\x05\x11\0\0\0\0";
	char* ptr = msg + 5;
	write_int32(piece, ptr);
	error_code ec;
	libtorrent::asio::write(s, libtorrent::asio::buffer(msg, 9)
		, libtorrent::asio::transfer_all(), ec);
}

void send_suggest_piece(stream_socket& s, int piece)
{
	std::cout << time_now_string() << " ==> suggest piece: " << piece << std::endl;
	using namespace libtorrent::detail;
	char msg[] = "\0\0\0\x05\x0d\0\0\0\0";
	char* ptr = msg + 5;
	write_int32(piece, ptr);
	error_code ec;
	libtorrent::asio::write(s, libtorrent::asio::buffer(msg, 9)
		, libtorrent::asio::transfer_all(), ec);
}

void send_keepalive(stream_socket& s)
{
	std::cout << time_now_string() << " ==> keepalive" << std::endl;
	char msg[] = "\0\0\0\0";
	error_code ec;
	libtorrent::asio::write(s, libtorrent::asio::buffer(msg, 4)
		, libtorrent::asio::transfer_all(), ec);
}

void send_unchoke(stream_socket& s)
{
	std::cout << time_now_string() << " ==> unchoke" << std::endl;
	char msg[] = "\0\0\0\x01\x01";
	error_code ec;
	libtorrent::asio::write(s, libtorrent::asio::buffer(msg, 5)
		, libtorrent::asio::transfer_all(), ec);
}

void do_handshake(stream_socket& s, sha1_hash const& ih, char* buffer)
{
	char handshake[] = "\x13" "BitTorrent protocol\0\0\0\0\0\0\0\x04"
		"                    " // space for info-hash
		"aaaaaaaaaaaaaaaaaaaa" // peer-id
		"\0\0\0\x01\x0e"; // have_all
	std::cout << time_now_string() << " ==> handshake" << std::endl;
	std::cout << time_now_string() << " ==> have_all" << std::endl;
	error_code ec;
	std::memcpy(handshake + 28, ih.begin(), 20);
	libtorrent::asio::write(s, libtorrent::asio::buffer(handshake, sizeof(handshake) - 1)
		, libtorrent::asio::transfer_all(), ec);

	// read handshake
	libtorrent::asio::read(s, libtorrent::asio::buffer(buffer, 68)
		, libtorrent::asio::transfer_all(), ec);
	if (ec)
	{
		std::cout << time_now_string() << ": " << ec.message() << std::endl;
		exit(1);
	}
	std::cout << time_now_string() << " <== handshake" << std::endl;

	TEST_CHECK(buffer[0] == 19);
	TEST_CHECK(std::memcmp(buffer + 1, "BitTorrent protocol", 19) == 0);

	char* extensions = buffer + 20;
	// check for fast extension support
	TEST_CHECK(extensions[7] & 0x4);

#ifndef TORRENT_DISABLE_EXTENSIONS
	// check for extension protocol support
	TEST_CHECK(extensions[5] & 0x10);
#endif

#ifndef TORRENT_DISABLE_DHT
	// check for DHT support
	TEST_CHECK(extensions[7] & 0x1);
#endif

	TEST_CHECK(std::memcmp(buffer + 28, ih.begin(), 20) == 0);
}

// makes sure that pieces that are allowed and then
// rejected aren't requested again
void test_reject_fast()
{
	std::cerr << " === test reject ===" << std::endl;

	boost::intrusive_ptr<torrent_info> t = ::create_torrent();
	sha1_hash ih = t->info_hash();
	session ses1(fingerprint("LT", 0, 1, 0, 0), std::make_pair(48900, 49000), "0.0.0.0", 0);
	error_code ec;
	add_torrent_params p;
	p.ti = t;
	p.save_path = "./tmp1_fast";
	ses1.add_torrent(p, ec);

	test_sleep(2000);

	io_service ios;
	stream_socket s(ios);
	s.connect(tcp::endpoint(address::from_string("127.0.0.1", ec), ses1.listen_port()), ec);

	char recv_buffer[1000];
	do_handshake(s, ih, recv_buffer);

	std::vector<int> allowed_fast;
	allowed_fast.push_back(0);
	allowed_fast.push_back(1);
	allowed_fast.push_back(2);
	allowed_fast.push_back(3);

	std::for_each(allowed_fast.begin(), allowed_fast.end()
		, boost::bind(&send_allow_fast, boost::ref(s), _1));

	while (!allowed_fast.empty())
	{
		int len = read_message(s, recv_buffer);
		print_message(recv_buffer, len);
		int msg = recv_buffer[0];
		if (recv_buffer[0] != 0x6) continue;

		using namespace libtorrent::detail;
		char* ptr = recv_buffer + 1;
		int piece = read_int32(ptr);

		std::vector<int>::iterator i = std::find(allowed_fast.begin()
			, allowed_fast.end(), piece);
		TEST_CHECK(i != allowed_fast.end());
		if (i != allowed_fast.end())
			allowed_fast.erase(i);
		// send reject request
		recv_buffer[0] = 0x10;
		error_code ec;
		std::cerr << time_now_string() << " ==> reject" << std::endl;
		libtorrent::asio::write(s, libtorrent::asio::buffer("\0\0\0\x0d", 4)
			, libtorrent::asio::transfer_all(), ec);
		libtorrent::asio::write(s, libtorrent::asio::buffer(recv_buffer, 13)
			, libtorrent::asio::transfer_all(), ec);
	}
}

void test_respect_suggest()
{
	std::cerr << " === test suggest ===" << std::endl;
	boost::intrusive_ptr<torrent_info> t = ::create_torrent();
	sha1_hash ih = t->info_hash();
	session ses1(fingerprint("LT", 0, 1, 0, 0), std::make_pair(48900, 49000), "0.0.0.0", 0);

	error_code ec;
	add_torrent_params p;
	p.ti = t;
	p.save_path = "./tmp1_fast";
	ses1.add_torrent(p, ec);

	test_sleep(2000);

	io_service ios;
	stream_socket s(ios);
	s.connect(tcp::endpoint(address::from_string("127.0.0.1", ec), ses1.listen_port()), ec);

	char recv_buffer[1000];
	do_handshake(s, ih, recv_buffer);

	std::vector<int> suggested;
	suggested.push_back(0);
	suggested.push_back(1);
	suggested.push_back(2);
	suggested.push_back(3);

	std::for_each(suggested.begin(), suggested.end()
		, boost::bind(&send_suggest_piece, boost::ref(s), _1));

	send_unchoke(s);

	send_keepalive(s);

	int fail_counter = 100;
	while (!suggested.empty() && fail_counter > 0)
	{
		int len = read_message(s, recv_buffer);
		print_message(recv_buffer, len);
		int msg = recv_buffer[0];
		fail_counter--;
		if (recv_buffer[0] != 0x6) continue;

		using namespace libtorrent::detail;
		char* ptr = recv_buffer + 1;
		int piece = read_int32(ptr);

		std::vector<int>::iterator i = std::find(suggested.begin()
			, suggested.end(), piece);
		TEST_CHECK(i != suggested.end());
		if (i != suggested.end())
			suggested.erase(i);
		// send reject request
		recv_buffer[0] = 0x10;
		error_code ec;
		std::cerr << time_now_string() << " ==> reject" << std::endl;
		libtorrent::asio::write(s, libtorrent::asio::buffer("\0\0\0\x0d", 4)
			, libtorrent::asio::transfer_all(), ec);
		libtorrent::asio::write(s, libtorrent::asio::buffer(recv_buffer, 13)
			, libtorrent::asio::transfer_all(), ec);
	}
	TEST_CHECK(fail_counter > 0);
}

int test_main()
{
	test_reject_fast();
	test_respect_suggest();
	return 0;
}

<|endoftext|>