<commit_before>/*
 * Adplug - Replayer for many OPL2/OPL3 audio file formats.
 * Copyright (C) 1999 - 2003 Simon Peter <dn.tlp@gmx.net>, et al.
 *
 * 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, or (at your option) any later version.
 *
 * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 * adtrack.cpp - Adlib Tracker 1.0 Loader by Simon Peter <dn.tlp@gmx.net>
 *
 * NOTES:
 * The original Adlib Tracker 1.0 is behaving a little different from the
 * official spec: The 'octave' integer from the instrument file is stored
 * "minus 1" from the actual value, underflowing from 0 to 0xffff.
 *
 * I also noticed that my player is playing everything transposed a few tones
 * higher than the original tracker. As far as i can see, my player perfectly
 * follows the official spec, so it "must" be the tracker that does something
 * wrong here...
 */

#include <stdlib.h>
#include <string.h>

#include "adtrack.h"
#include "debug.h"

/*** Public methods ***/

CPlayer *CadtrackLoader::factory(Copl *newopl)
{
  return new CadtrackLoader(newopl);
}

bool CadtrackLoader::load(const std::string &filename, const CFileProvider &fp)
{
  binistream *f = fp.open(filename); if(!f) return false;
  binistream *instf;
  char note[2];
  unsigned short rwp;
  unsigned char chp, octave, pnote = 0;
  int i,j;
  AdTrackInst myinst;

  // file validation
  if(!fp.extension(filename, ".sng") || fp.filesize(f) != 36000)
    { fp.close(f); return false; }

  // check for instruments file
  std::string instfilename(filename, 0, filename.find_last_of('.'));
  instfilename += ".ins";
  AdPlug_LogWrite("CadtrackLoader::load(,\"%s\"): Checking for \"%s\"...\n",
		  filename.c_str(), instfilename.c_str());
  instf = fp.open(instfilename);
  if(!instf || fp.filesize(instf) != 468) { fp.close(f); return false; }

  // give CmodPlayer a hint on what we're up to
  realloc_patterns(1,1000,9); realloc_instruments(9); realloc_order(1);
  init_trackord(); flags = NoKeyOn;
  (*order) = 0; length = 1; restartpos = 0; bpm = 120; initspeed = 3;

  // load instruments from instruments file
  for(i=0;i<9;i++) {
    for(j=0;j<2;j++) {
      myinst.op[j].appampmod = instf->readInt(2);
      myinst.op[j].appvib = instf->readInt(2);
      myinst.op[j].maintsuslvl = instf->readInt(2);
      myinst.op[j].keybscale = instf->readInt(2);
      myinst.op[j].octave = instf->readInt(2);
      myinst.op[j].freqrisevollvldn = instf->readInt(2);
      myinst.op[j].softness = instf->readInt(2);
      myinst.op[j].attack = instf->readInt(2);
      myinst.op[j].decay = instf->readInt(2);
      myinst.op[j].release = instf->readInt(2);
      myinst.op[j].sustain = instf->readInt(2);
      myinst.op[j].feedback = instf->readInt(2);
      myinst.op[j].waveform = instf->readInt(2);
    }
    convert_instrument(i, &myinst);
  }
  fp.close(instf);

  // load file
  for(rwp=0;rwp<1000;rwp++)
    for(chp=0;chp<9;chp++) {
      // read next record
      f->readString(note, 2); octave = f->readInt(1); f->ignore();
      switch(*note) {
      case 'C': if(note[1] == '#') pnote = 2; else pnote = 1; break;
      case 'D': if(note[1] == '#') pnote = 4; else pnote = 3; break;
      case 'E': pnote = 5; break;
      case 'F': if(note[1] == '#') pnote = 7; else pnote = 6; break;
      case 'G': if(note[1] == '#') pnote = 9; else pnote = 8; break;
      case 'A': if(note[1] == '#') pnote = 11; else pnote = 10; break;
      case 'B': pnote = 12; break;
      case '\0':
	if(note[1] == '\0')
	  tracks[chp][rwp].note = 127;
	else {
	  fp.close(f);
	  return false;
	}
	break;
      default: fp.close(f); return false;
      }
      if((*note) != '\0') {
	tracks[chp][rwp].note = pnote + (octave * 12);
	tracks[chp][rwp].inst = chp + 1;
      }
    }

  fp.close(f);
  rewind(0);
  return true;
}

float CadtrackLoader::getrefresh()
{
  return 18.2f;
}

/*** Private methods ***/

void CadtrackLoader::convert_instrument(unsigned int n, AdTrackInst *i)
{
  // Carrier "Amp Mod / Vib / Env Type / KSR / Multiple" register
  inst[n].data[2] = i->op[Carrier].appampmod ? 1 << 7 : 0;
  inst[n].data[2] += i->op[Carrier].appvib ? 1 << 6 : 0;
  inst[n].data[2] += i->op[Carrier].maintsuslvl ? 1 << 5 : 0;
  inst[n].data[2] += i->op[Carrier].keybscale ? 1 << 4 : 0;
  inst[n].data[2] += (i->op[Carrier].octave + 1) & 0xffff; // Bug in original tracker
  // Modulator...
  inst[n].data[1] = i->op[Modulator].appampmod ? 1 << 7 : 0;
  inst[n].data[1] += i->op[Modulator].appvib ? 1 << 6 : 0;
  inst[n].data[1] += i->op[Modulator].maintsuslvl ? 1 << 5 : 0;
  inst[n].data[1] += i->op[Modulator].keybscale ? 1 << 4 : 0;
  inst[n].data[1] += (i->op[Modulator].octave + 1) & 0xffff; // Bug in original tracker

  // Carrier "Key Scaling / Level" register
  inst[n].data[10] = (i->op[Carrier].freqrisevollvldn & 3) << 6;
  inst[n].data[10] += i->op[Carrier].softness & 63;
  // Modulator...
  inst[n].data[9] = (i->op[Modulator].freqrisevollvldn & 3) << 6;
  inst[n].data[9] += i->op[Modulator].softness & 63;

  // Carrier "Attack / Decay" register
  inst[n].data[4] = (i->op[Carrier].attack & 0x0f) << 4;
  inst[n].data[4] += i->op[Carrier].decay & 0x0f;
  // Modulator...
  inst[n].data[3] = (i->op[Modulator].attack & 0x0f) << 4;
  inst[n].data[3] += i->op[Modulator].decay & 0x0f;

  // Carrier "Release / Sustain" register
  inst[n].data[6] = (i->op[Carrier].release & 0x0f) << 4;
  inst[n].data[6] += i->op[Carrier].sustain & 0x0f;
  // Modulator...
  inst[n].data[5] = (i->op[Modulator].release & 0x0f) << 4;
  inst[n].data[5] += i->op[Modulator].sustain & 0x0f;

  // Channel "Feedback / Connection" register
  inst[n].data[0] = (i->op[Carrier].feedback & 7) << 1;

  // Carrier/Modulator "Wave Select" registers
  inst[n].data[8] = i->op[Carrier].waveform & 3;
  inst[n].data[7] = i->op[Modulator].waveform & 3;
}
<commit_msg>adtrack: Close instrument file (fix #25)<commit_after>/*
 * Adplug - Replayer for many OPL2/OPL3 audio file formats.
 * Copyright (C) 1999 - 2003 Simon Peter <dn.tlp@gmx.net>, et al.
 *
 * 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, or (at your option) any later version.
 *
 * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 * adtrack.cpp - Adlib Tracker 1.0 Loader by Simon Peter <dn.tlp@gmx.net>
 *
 * NOTES:
 * The original Adlib Tracker 1.0 is behaving a little different from the
 * official spec: The 'octave' integer from the instrument file is stored
 * "minus 1" from the actual value, underflowing from 0 to 0xffff.
 *
 * I also noticed that my player is playing everything transposed a few tones
 * higher than the original tracker. As far as i can see, my player perfectly
 * follows the official spec, so it "must" be the tracker that does something
 * wrong here...
 */

#include <stdlib.h>
#include <string.h>

#include "adtrack.h"
#include "debug.h"

/*** Public methods ***/

CPlayer *CadtrackLoader::factory(Copl *newopl)
{
  return new CadtrackLoader(newopl);
}

bool CadtrackLoader::load(const std::string &filename, const CFileProvider &fp)
{
  binistream *f = fp.open(filename); if(!f) return false;
  binistream *instf;
  char note[2];
  unsigned short rwp;
  unsigned char chp, octave, pnote = 0;
  int i,j;
  AdTrackInst myinst;

  // file validation
  if(!fp.extension(filename, ".sng") || fp.filesize(f) != 36000)
    { fp.close(f); return false; }

  // check for instruments file
  std::string instfilename(filename, 0, filename.find_last_of('.'));
  instfilename += ".ins";
  AdPlug_LogWrite("CadtrackLoader::load(,\"%s\"): Checking for \"%s\"...\n",
		  filename.c_str(), instfilename.c_str());
  instf = fp.open(instfilename);
  if(!instf || fp.filesize(instf) != 468) { fp.close(instf); fp.close(f); return false; }

  // give CmodPlayer a hint on what we're up to
  realloc_patterns(1,1000,9); realloc_instruments(9); realloc_order(1);
  init_trackord(); flags = NoKeyOn;
  (*order) = 0; length = 1; restartpos = 0; bpm = 120; initspeed = 3;

  // load instruments from instruments file
  for(i=0;i<9;i++) {
    for(j=0;j<2;j++) {
      myinst.op[j].appampmod = instf->readInt(2);
      myinst.op[j].appvib = instf->readInt(2);
      myinst.op[j].maintsuslvl = instf->readInt(2);
      myinst.op[j].keybscale = instf->readInt(2);
      myinst.op[j].octave = instf->readInt(2);
      myinst.op[j].freqrisevollvldn = instf->readInt(2);
      myinst.op[j].softness = instf->readInt(2);
      myinst.op[j].attack = instf->readInt(2);
      myinst.op[j].decay = instf->readInt(2);
      myinst.op[j].release = instf->readInt(2);
      myinst.op[j].sustain = instf->readInt(2);
      myinst.op[j].feedback = instf->readInt(2);
      myinst.op[j].waveform = instf->readInt(2);
    }
    convert_instrument(i, &myinst);
  }
  fp.close(instf);

  // load file
  for(rwp=0;rwp<1000;rwp++)
    for(chp=0;chp<9;chp++) {
      // read next record
      f->readString(note, 2); octave = f->readInt(1); f->ignore();
      switch(*note) {
      case 'C': if(note[1] == '#') pnote = 2; else pnote = 1; break;
      case 'D': if(note[1] == '#') pnote = 4; else pnote = 3; break;
      case 'E': pnote = 5; break;
      case 'F': if(note[1] == '#') pnote = 7; else pnote = 6; break;
      case 'G': if(note[1] == '#') pnote = 9; else pnote = 8; break;
      case 'A': if(note[1] == '#') pnote = 11; else pnote = 10; break;
      case 'B': pnote = 12; break;
      case '\0':
	if(note[1] == '\0')
	  tracks[chp][rwp].note = 127;
	else {
	  fp.close(f);
	  return false;
	}
	break;
      default: fp.close(f); return false;
      }
      if((*note) != '\0') {
	tracks[chp][rwp].note = pnote + (octave * 12);
	tracks[chp][rwp].inst = chp + 1;
      }
    }

  fp.close(f);
  rewind(0);
  return true;
}

float CadtrackLoader::getrefresh()
{
  return 18.2f;
}

/*** Private methods ***/

void CadtrackLoader::convert_instrument(unsigned int n, AdTrackInst *i)
{
  // Carrier "Amp Mod / Vib / Env Type / KSR / Multiple" register
  inst[n].data[2] = i->op[Carrier].appampmod ? 1 << 7 : 0;
  inst[n].data[2] += i->op[Carrier].appvib ? 1 << 6 : 0;
  inst[n].data[2] += i->op[Carrier].maintsuslvl ? 1 << 5 : 0;
  inst[n].data[2] += i->op[Carrier].keybscale ? 1 << 4 : 0;
  inst[n].data[2] += (i->op[Carrier].octave + 1) & 0xffff; // Bug in original tracker
  // Modulator...
  inst[n].data[1] = i->op[Modulator].appampmod ? 1 << 7 : 0;
  inst[n].data[1] += i->op[Modulator].appvib ? 1 << 6 : 0;
  inst[n].data[1] += i->op[Modulator].maintsuslvl ? 1 << 5 : 0;
  inst[n].data[1] += i->op[Modulator].keybscale ? 1 << 4 : 0;
  inst[n].data[1] += (i->op[Modulator].octave + 1) & 0xffff; // Bug in original tracker

  // Carrier "Key Scaling / Level" register
  inst[n].data[10] = (i->op[Carrier].freqrisevollvldn & 3) << 6;
  inst[n].data[10] += i->op[Carrier].softness & 63;
  // Modulator...
  inst[n].data[9] = (i->op[Modulator].freqrisevollvldn & 3) << 6;
  inst[n].data[9] += i->op[Modulator].softness & 63;

  // Carrier "Attack / Decay" register
  inst[n].data[4] = (i->op[Carrier].attack & 0x0f) << 4;
  inst[n].data[4] += i->op[Carrier].decay & 0x0f;
  // Modulator...
  inst[n].data[3] = (i->op[Modulator].attack & 0x0f) << 4;
  inst[n].data[3] += i->op[Modulator].decay & 0x0f;

  // Carrier "Release / Sustain" register
  inst[n].data[6] = (i->op[Carrier].release & 0x0f) << 4;
  inst[n].data[6] += i->op[Carrier].sustain & 0x0f;
  // Modulator...
  inst[n].data[5] = (i->op[Modulator].release & 0x0f) << 4;
  inst[n].data[5] += i->op[Modulator].sustain & 0x0f;

  // Channel "Feedback / Connection" register
  inst[n].data[0] = (i->op[Carrier].feedback & 7) << 1;

  // Carrier/Modulator "Wave Select" registers
  inst[n].data[8] = i->op[Carrier].waveform & 3;
  inst[n].data[7] = i->op[Modulator].waveform & 3;
}
<|endoftext|>


<commit_before>#include <iostream>
#include <dns_sd.h>
#include <ev++.h>

#include "build_version.h"

inline void check_dnsservice_errors(DNSServiceErrorType& e, const std::string& func_name) {
    std::string error(func_name);
    error += ": ";

    switch (e) {
        case kDNSServiceErr_NoError:
            return;
        case kDNSServiceErr_NameConflict:
            error += "Name in use, please choose another";
            break;
        case kDNSServiceErr_Invalid:
            error += "An invalid index or character was passed";
            break;
        case kDNSServiceErr_BadReference:
            error += "Bad reference";
            break;
        case kDNSServiceErr_BadParam:
            error += "Bad parameter value passed to function.";
            break;
        default:
            error += "Unknown error code... ";
            error += std::to_string(e);
    }

    throw std::runtime_error(error.c_str());
}

int main(int argc, char *argv[]) {
    if (2 != argc) {
        std::cerr << argv[0] << " <announce file>" << std::endl;
        std::cerr << "Version: " << VERSION << std::endl;
        return -1;
    }
    return 0;
}
<commit_msg>Grab list of domains to register<commit_after>#include <iostream>
#include <dns_sd.h>
#include <ev++.h>

#include "build_version.h"

inline void check_dnsservice_errors(DNSServiceErrorType& e, const std::string& func_name) {
    std::string error(func_name);
    error += ": ";

    switch (e) {
        case kDNSServiceErr_NoError:
            return;
        case kDNSServiceErr_NameConflict:
            error += "Name in use, please choose another";
            break;
        case kDNSServiceErr_Invalid:
            error += "An invalid index or character was passed";
            break;
        case kDNSServiceErr_BadReference:
            error += "Bad reference";
            break;
        case kDNSServiceErr_BadParam:
            error += "Bad parameter value passed to function.";
            break;
        default:
            error += "Unknown error code... ";
            error += std::to_string(e);
    }

    throw std::runtime_error(error.c_str());
}

int main(int argc, char *argv[]) {
    if (2 != argc) {
        std::cerr << argv[0] << " <announce file>" << std::endl;
        std::cerr << "Version: " << VERSION << std::endl;
        return -1;
    }

    std::vector<std::string> _domains;
    try {
        std::ifstream f(argv[1], std::ios::in | std::ios::binary);

        if (!f.is_open()) {
            std::cerr << "Unable to open file: " << argv[1] << std::endl;
            return -2;
        }

        for (std::string line; std::getline(f, line); /**/) {
            if (line.length() != 0) _domains.push_back(line);
        }
        for (auto &d : _domains) {
            std::cout << "Registering Domain: " << d << std::endl;

        }
    } catch (std::exception const& e) {
        std::cerr << "Caught an exception: " << e.what() << std::endl;
    }
    return 0;
}
<|endoftext|>


<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 "app/l10n_util.h"
#include "app/resource_bundle.h"
#include "base/base_paths.h"
#include "base/command_line.h"
#include "base/logging.h"
#include "base/utf_string_conversions.h"
#include "chrome/app/chrome_command_ids.h"
#include "chrome/browser/background_application_list_model.h"
#include "chrome/browser/background_mode_manager.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/extensions/extensions_service.h"
#include "chrome/browser/metrics/user_metrics.h"
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/status_icons/status_icon.h"
#include "chrome/browser/status_icons/status_tray.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/notification_type.h"
#include "chrome/common/pref_names.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"

void BackgroundModeManager::OnApplicationDataChanged(
    const Extension* extension) {
  UpdateContextMenuEntryIcon(extension);
}

void BackgroundModeManager::OnApplicationListChanged() {
  UpdateStatusTrayIconContextMenu();
}

BackgroundModeManager::BackgroundModeManager(Profile* profile,
                                             CommandLine* command_line)
    : profile_(profile),
      applications_(profile),
      background_app_count_(0),
      context_menu_(NULL),
      context_menu_application_offset_(0),
      in_background_mode_(false),
      keep_alive_for_startup_(false),
      status_tray_(NULL),
      status_icon_(NULL) {
  // If background mode is disabled, just exit - don't listen for any
  // notifications.
  if (!IsBackgroundModeEnabled(command_line))
    return;

  // Keep the browser alive until extensions are done loading - this is needed
  // by the --no-startup-window flag. We want to stay alive until we load
  // extensions, at which point we should either run in background mode (if
  // there are background apps) or exit if there are none.
  if (command_line->HasSwitch(switches::kNoStartupWindow)) {
    keep_alive_for_startup_ = true;
    BrowserList::StartKeepAlive();
  }

  // If the -keep-alive-for-test flag is passed, then always keep chrome running
  // in the background until the user explicitly terminates it, by acting as if
  // we loaded a background app.
  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kKeepAliveForTest))
    OnBackgroundAppLoaded();

  // When an extension is installed, make sure launch on startup is properly
  // set if appropriate. Likewise, turn off launch on startup when the last
  // background app is uninstalled.
  registrar_.Add(this, NotificationType::EXTENSION_INSTALLED,
                 Source<Profile>(profile));
  registrar_.Add(this, NotificationType::EXTENSION_UNINSTALLED,
                 Source<Profile>(profile));
  // Listen for when extensions are loaded/unloaded so we can track the
  // number of background apps.
  registrar_.Add(this, NotificationType::EXTENSION_LOADED,
                 Source<Profile>(profile));
  registrar_.Add(this, NotificationType::EXTENSION_UNLOADED,
                 Source<Profile>(profile));

  // Check for the presence of background apps after all extensions have been
  // loaded, to handle the case where an extension has been manually removed
  // while Chrome was not running.
  registrar_.Add(this, NotificationType::EXTENSIONS_READY,
                 Source<Profile>(profile));

  // Listen for the application shutting down so we can decrement our KeepAlive
  // count.
  registrar_.Add(this, NotificationType::APP_TERMINATING,
                 NotificationService::AllSources());

  applications_.AddObserver(this);
}

BackgroundModeManager::~BackgroundModeManager() {
  applications_.RemoveObserver(this);

  // We're going away, so exit background mode (does nothing if we aren't in
  // background mode currently). This is primarily needed for unit tests,
  // because in an actual running system we'd get an APP_TERMINATING
  // notification before being destroyed.
  EndBackgroundMode();
}

void BackgroundModeManager::Observe(NotificationType type,
                                    const NotificationSource& source,
                                    const NotificationDetails& details) {
  switch (type.value) {
    case NotificationType::EXTENSIONS_READY:
      // Extensions are loaded, so we don't need to manually keep the browser
      // process alive any more when running in no-startup-window mode.
      EndKeepAliveForStartup();

      // On a Mac, we use 'login items' mechanism which has user-facing UI so we
      // don't want to stomp on user choice every time we start and load
      // registered extensions.
#if !defined(OS_MACOSX)
      EnableLaunchOnStartup(background_app_count_ > 0);
#endif
      break;
    case NotificationType::EXTENSION_LOADED:
      if (BackgroundApplicationListModel::IsBackgroundApp(
              *Details<Extension>(details).ptr())) {
        OnBackgroundAppLoaded();
      }
      break;
    case NotificationType::EXTENSION_UNLOADED:
      if (BackgroundApplicationListModel::IsBackgroundApp(
              *Details<Extension>(details).ptr())) {
        OnBackgroundAppUnloaded();
      }
      break;
    case NotificationType::EXTENSION_INSTALLED:
      if (BackgroundApplicationListModel::IsBackgroundApp(
              *Details<Extension>(details).ptr())) {
        OnBackgroundAppInstalled();
      }
      break;
    case NotificationType::EXTENSION_UNINSTALLED:
      if (Extension::HasApiPermission(
            Details<UninstalledExtensionInfo>(details).ptr()->
                extension_api_permissions,
            Extension::kBackgroundPermission)) {
        OnBackgroundAppUninstalled();
      }
      break;
    case NotificationType::APP_TERMINATING:
      // Make sure we aren't still keeping the app alive (only happens if we
      // don't receive an EXTENSIONS_READY notification for some reason).
      EndKeepAliveForStartup();
      // Performing an explicit shutdown, so exit background mode (does nothing
      // if we aren't in background mode currently).
      EndBackgroundMode();
      // Shutting down, so don't listen for any more notifications so we don't
      // try to re-enter/exit background mode again.
      registrar_.RemoveAll();
      break;
    default:
      NOTREACHED();
      break;
  }
}

void BackgroundModeManager::EndKeepAliveForStartup() {
  if (keep_alive_for_startup_) {
    keep_alive_for_startup_ = false;
    // We call this via the message queue to make sure we don't try to end
    // keep-alive (which can shutdown Chrome) before the message loop has
    // started.
    MessageLoop::current()->PostTask(
        FROM_HERE, NewRunnableFunction(BrowserList::EndKeepAlive));
  }
}

void BackgroundModeManager::OnBackgroundAppLoaded() {
  // When a background app loads, increment our count and also enable
  // KeepAlive mode if the preference is set.
  background_app_count_++;
  if (background_app_count_ == 1)
    StartBackgroundMode();
}

void BackgroundModeManager::StartBackgroundMode() {
  // Don't bother putting ourselves in background mode if we're already there.
  if (in_background_mode_)
    return;

  // Mark ourselves as running in background mode.
  in_background_mode_ = true;

  // Put ourselves in KeepAlive mode and create a status tray icon.
  BrowserList::StartKeepAlive();

  // Display a status icon to exit Chrome.
  CreateStatusTrayIcon();
}

void BackgroundModeManager::OnBackgroundAppUnloaded() {
  // When a background app unloads, decrement our count and also end
  // KeepAlive mode if appropriate.
  background_app_count_--;
  DCHECK(background_app_count_ >= 0);
  if (background_app_count_ == 0)
    EndBackgroundMode();
}

void BackgroundModeManager::EndBackgroundMode() {
  if (!in_background_mode_)
    return;
  in_background_mode_ = false;

  // End KeepAlive mode and blow away our status tray icon.
  BrowserList::EndKeepAlive();
  RemoveStatusTrayIcon();
}

void BackgroundModeManager::OnBackgroundAppInstalled() {
  // We're installing a background app. If this is the first background app
  // being installed, make sure we are set to launch on startup.
  if (background_app_count_ == 0)
    EnableLaunchOnStartup(true);
}

void BackgroundModeManager::OnBackgroundAppUninstalled() {
  // When uninstalling a background app, disable launch on startup if
  // we have no more background apps.
  if (background_app_count_ == 0)
    EnableLaunchOnStartup(false);
}

void BackgroundModeManager::CreateStatusTrayIcon() {
  // Only need status icons on windows/linux. ChromeOS doesn't allow exiting
  // Chrome and Mac can use the dock icon instead.
#if !defined(OS_MACOSX) && !defined(OS_CHROMEOS)
  if (!status_tray_)
    status_tray_ = profile_->GetStatusTray();
#endif

  // If the platform doesn't support status icons, or we've already created
  // our status icon, just return.
  if (!status_tray_ || status_icon_)
    return;
  status_icon_ = status_tray_->CreateStatusIcon();
  if (!status_icon_)
    return;

  // Set the image and add ourselves as a click observer on it
  SkBitmap* bitmap = ResourceBundle::GetSharedInstance().GetBitmapNamed(
      IDR_STATUS_TRAY_ICON);
  status_icon_->SetImage(*bitmap);
  status_icon_->SetToolTip(l10n_util::GetStringUTF16(IDS_PRODUCT_NAME));
  UpdateStatusTrayIconContextMenu();
}

void BackgroundModeManager::UpdateContextMenuEntryIcon(
    const Extension* extension) {
  if (!context_menu_)
    return;
  context_menu_->SetIcon(
      context_menu_application_offset_ + applications_.GetPosition(extension),
      *(applications_.GetIcon(extension)));
  status_icon_->SetContextMenu(context_menu_);  // for Update effect
}

void BackgroundModeManager::UpdateStatusTrayIconContextMenu() {
  if (!status_icon_)
    return;

  // Create a context menu item for Chrome.
  menus::SimpleMenuModel* menu = new menus::SimpleMenuModel(this);
  // Add About item
  menu->AddItem(IDC_ABOUT, l10n_util::GetStringFUTF16(IDS_ABOUT,
      l10n_util::GetStringUTF16(IDS_PRODUCT_NAME)));
  menu->AddItem(IDC_OPTIONS, GetPreferencesMenuLabel());
  menu->AddItemWithStringId(IDC_TASK_MANAGER, IDS_TASK_MANAGER);
  menu->AddSeparator();
  int application_position = 0;
  context_menu_application_offset_ = menu->GetItemCount();
  for (ExtensionList::const_iterator cursor = applications_.begin();
       cursor != applications_.end();
       ++cursor, ++application_position) {
    const SkBitmap* icon = applications_.GetIcon(*cursor);
    int sort_position = applications_.GetPosition(*cursor);
    DCHECK(sort_position == application_position);
    const std::string& name = (*cursor)->name();
    menu->AddItem(sort_position, ASCIIToUTF16(name));
    if (icon)
      menu->SetIcon(menu->GetItemCount() - 1, *icon);
  }
  menu->AddSeparator();
  menu->AddItemWithStringId(IDC_EXIT, IDS_EXIT);
  context_menu_ = menu;
  status_icon_->SetContextMenu(menu);
}

bool BackgroundModeManager::IsCommandIdChecked(int command_id) const {
  return false;
}

bool BackgroundModeManager::IsCommandIdEnabled(int command_id) const {
  // For now, we do not support disabled items.
  return true;
}

bool BackgroundModeManager::GetAcceleratorForCommandId(
    int command_id,
    menus::Accelerator* accelerator) {
  // No accelerators for status icon context menus.
  return false;
}

void BackgroundModeManager::RemoveStatusTrayIcon() {
  if (status_icon_)
    status_tray_->RemoveStatusIcon(status_icon_);
  status_icon_ = NULL;
}

void BackgroundModeManager::ExecuteApplication(int item) {
  DCHECK(item >= 0 && item < static_cast<int>(applications_.size()));
  Browser* browser = BrowserList::GetLastActive();
  if (!browser) {
    Browser::OpenEmptyWindow(profile_);
    browser = BrowserList::GetLastActive();
  }
  const Extension* extension = applications_.GetExtension(item);
  browser->OpenApplicationTab(profile_, extension, NULL);
}

void BackgroundModeManager::ExecuteCommand(int item) {
  switch (item) {
    case IDC_ABOUT:
      GetBrowserWindow()->OpenAboutChromeDialog();
      break;
    case IDC_EXIT:
      UserMetrics::RecordAction(UserMetricsAction("Exit"), profile_);
      BrowserList::CloseAllBrowsersAndExit();
      break;
    case IDC_OPTIONS:
      GetBrowserWindow()->OpenOptionsDialog();
      break;
    case IDC_TASK_MANAGER:
      GetBrowserWindow()->OpenTaskManager();
      break;
    default:
      ExecuteApplication(item);
      break;
  }
}

Browser* BackgroundModeManager::GetBrowserWindow() {
  Browser* browser = BrowserList::GetLastActive();
  if (!browser) {
    Browser::OpenEmptyWindow(profile_);
    browser = BrowserList::GetLastActive();
  }
  return browser;
}

// static
bool BackgroundModeManager::IsBackgroundModeEnabled(
    const CommandLine* command_line) {

  // Background mode is disabled if the appropriate flag is passed, or if
  // extensions are disabled.
  bool background_mode_enabled =
      !command_line->HasSwitch(switches::kDisableBackgroundMode) &&
      !command_line->HasSwitch(switches::kDisableExtensions);
#if !defined(OS_WIN)
  // BackgroundMode is enabled by default on windows. On other platforms, it
  // is enabled via about:flags.
  background_mode_enabled = background_mode_enabled &&
      command_line->HasSwitch(switches::kEnableBackgroundMode);
#endif

  return background_mode_enabled;
}

<commit_msg>Avoid inserting a redundant separator in status icon menu.<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 "app/l10n_util.h"
#include "app/resource_bundle.h"
#include "base/base_paths.h"
#include "base/command_line.h"
#include "base/logging.h"
#include "base/utf_string_conversions.h"
#include "chrome/app/chrome_command_ids.h"
#include "chrome/browser/background_application_list_model.h"
#include "chrome/browser/background_mode_manager.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/extensions/extensions_service.h"
#include "chrome/browser/metrics/user_metrics.h"
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/status_icons/status_icon.h"
#include "chrome/browser/status_icons/status_tray.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/notification_type.h"
#include "chrome/common/pref_names.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"

void BackgroundModeManager::OnApplicationDataChanged(
    const Extension* extension) {
  UpdateContextMenuEntryIcon(extension);
}

void BackgroundModeManager::OnApplicationListChanged() {
  UpdateStatusTrayIconContextMenu();
}

BackgroundModeManager::BackgroundModeManager(Profile* profile,
                                             CommandLine* command_line)
    : profile_(profile),
      applications_(profile),
      background_app_count_(0),
      context_menu_(NULL),
      context_menu_application_offset_(0),
      in_background_mode_(false),
      keep_alive_for_startup_(false),
      status_tray_(NULL),
      status_icon_(NULL) {
  // If background mode is disabled, just exit - don't listen for any
  // notifications.
  if (!IsBackgroundModeEnabled(command_line))
    return;

  // Keep the browser alive until extensions are done loading - this is needed
  // by the --no-startup-window flag. We want to stay alive until we load
  // extensions, at which point we should either run in background mode (if
  // there are background apps) or exit if there are none.
  if (command_line->HasSwitch(switches::kNoStartupWindow)) {
    keep_alive_for_startup_ = true;
    BrowserList::StartKeepAlive();
  }

  // If the -keep-alive-for-test flag is passed, then always keep chrome running
  // in the background until the user explicitly terminates it, by acting as if
  // we loaded a background app.
  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kKeepAliveForTest))
    OnBackgroundAppLoaded();

  // When an extension is installed, make sure launch on startup is properly
  // set if appropriate. Likewise, turn off launch on startup when the last
  // background app is uninstalled.
  registrar_.Add(this, NotificationType::EXTENSION_INSTALLED,
                 Source<Profile>(profile));
  registrar_.Add(this, NotificationType::EXTENSION_UNINSTALLED,
                 Source<Profile>(profile));
  // Listen for when extensions are loaded/unloaded so we can track the
  // number of background apps.
  registrar_.Add(this, NotificationType::EXTENSION_LOADED,
                 Source<Profile>(profile));
  registrar_.Add(this, NotificationType::EXTENSION_UNLOADED,
                 Source<Profile>(profile));

  // Check for the presence of background apps after all extensions have been
  // loaded, to handle the case where an extension has been manually removed
  // while Chrome was not running.
  registrar_.Add(this, NotificationType::EXTENSIONS_READY,
                 Source<Profile>(profile));

  // Listen for the application shutting down so we can decrement our KeepAlive
  // count.
  registrar_.Add(this, NotificationType::APP_TERMINATING,
                 NotificationService::AllSources());

  applications_.AddObserver(this);
}

BackgroundModeManager::~BackgroundModeManager() {
  applications_.RemoveObserver(this);

  // We're going away, so exit background mode (does nothing if we aren't in
  // background mode currently). This is primarily needed for unit tests,
  // because in an actual running system we'd get an APP_TERMINATING
  // notification before being destroyed.
  EndBackgroundMode();
}

void BackgroundModeManager::Observe(NotificationType type,
                                    const NotificationSource& source,
                                    const NotificationDetails& details) {
  switch (type.value) {
    case NotificationType::EXTENSIONS_READY:
      // Extensions are loaded, so we don't need to manually keep the browser
      // process alive any more when running in no-startup-window mode.
      EndKeepAliveForStartup();

      // On a Mac, we use 'login items' mechanism which has user-facing UI so we
      // don't want to stomp on user choice every time we start and load
      // registered extensions.
#if !defined(OS_MACOSX)
      EnableLaunchOnStartup(background_app_count_ > 0);
#endif
      break;
    case NotificationType::EXTENSION_LOADED:
      if (BackgroundApplicationListModel::IsBackgroundApp(
              *Details<Extension>(details).ptr())) {
        OnBackgroundAppLoaded();
      }
      break;
    case NotificationType::EXTENSION_UNLOADED:
      if (BackgroundApplicationListModel::IsBackgroundApp(
              *Details<Extension>(details).ptr())) {
        OnBackgroundAppUnloaded();
      }
      break;
    case NotificationType::EXTENSION_INSTALLED:
      if (BackgroundApplicationListModel::IsBackgroundApp(
              *Details<Extension>(details).ptr())) {
        OnBackgroundAppInstalled();
      }
      break;
    case NotificationType::EXTENSION_UNINSTALLED:
      if (Extension::HasApiPermission(
            Details<UninstalledExtensionInfo>(details).ptr()->
                extension_api_permissions,
            Extension::kBackgroundPermission)) {
        OnBackgroundAppUninstalled();
      }
      break;
    case NotificationType::APP_TERMINATING:
      // Make sure we aren't still keeping the app alive (only happens if we
      // don't receive an EXTENSIONS_READY notification for some reason).
      EndKeepAliveForStartup();
      // Performing an explicit shutdown, so exit background mode (does nothing
      // if we aren't in background mode currently).
      EndBackgroundMode();
      // Shutting down, so don't listen for any more notifications so we don't
      // try to re-enter/exit background mode again.
      registrar_.RemoveAll();
      break;
    default:
      NOTREACHED();
      break;
  }
}

void BackgroundModeManager::EndKeepAliveForStartup() {
  if (keep_alive_for_startup_) {
    keep_alive_for_startup_ = false;
    // We call this via the message queue to make sure we don't try to end
    // keep-alive (which can shutdown Chrome) before the message loop has
    // started.
    MessageLoop::current()->PostTask(
        FROM_HERE, NewRunnableFunction(BrowserList::EndKeepAlive));
  }
}

void BackgroundModeManager::OnBackgroundAppLoaded() {
  // When a background app loads, increment our count and also enable
  // KeepAlive mode if the preference is set.
  background_app_count_++;
  if (background_app_count_ == 1)
    StartBackgroundMode();
}

void BackgroundModeManager::StartBackgroundMode() {
  // Don't bother putting ourselves in background mode if we're already there.
  if (in_background_mode_)
    return;

  // Mark ourselves as running in background mode.
  in_background_mode_ = true;

  // Put ourselves in KeepAlive mode and create a status tray icon.
  BrowserList::StartKeepAlive();

  // Display a status icon to exit Chrome.
  CreateStatusTrayIcon();
}

void BackgroundModeManager::OnBackgroundAppUnloaded() {
  // When a background app unloads, decrement our count and also end
  // KeepAlive mode if appropriate.
  background_app_count_--;
  DCHECK(background_app_count_ >= 0);
  if (background_app_count_ == 0)
    EndBackgroundMode();
}

void BackgroundModeManager::EndBackgroundMode() {
  if (!in_background_mode_)
    return;
  in_background_mode_ = false;

  // End KeepAlive mode and blow away our status tray icon.
  BrowserList::EndKeepAlive();
  RemoveStatusTrayIcon();
}

void BackgroundModeManager::OnBackgroundAppInstalled() {
  // We're installing a background app. If this is the first background app
  // being installed, make sure we are set to launch on startup.
  if (background_app_count_ == 0)
    EnableLaunchOnStartup(true);
}

void BackgroundModeManager::OnBackgroundAppUninstalled() {
  // When uninstalling a background app, disable launch on startup if
  // we have no more background apps.
  if (background_app_count_ == 0)
    EnableLaunchOnStartup(false);
}

void BackgroundModeManager::CreateStatusTrayIcon() {
  // Only need status icons on windows/linux. ChromeOS doesn't allow exiting
  // Chrome and Mac can use the dock icon instead.
#if !defined(OS_MACOSX) && !defined(OS_CHROMEOS)
  if (!status_tray_)
    status_tray_ = profile_->GetStatusTray();
#endif

  // If the platform doesn't support status icons, or we've already created
  // our status icon, just return.
  if (!status_tray_ || status_icon_)
    return;
  status_icon_ = status_tray_->CreateStatusIcon();
  if (!status_icon_)
    return;

  // Set the image and add ourselves as a click observer on it
  SkBitmap* bitmap = ResourceBundle::GetSharedInstance().GetBitmapNamed(
      IDR_STATUS_TRAY_ICON);
  status_icon_->SetImage(*bitmap);
  status_icon_->SetToolTip(l10n_util::GetStringUTF16(IDS_PRODUCT_NAME));
  UpdateStatusTrayIconContextMenu();
}

void BackgroundModeManager::UpdateContextMenuEntryIcon(
    const Extension* extension) {
  if (!context_menu_)
    return;
  context_menu_->SetIcon(
      context_menu_application_offset_ + applications_.GetPosition(extension),
      *(applications_.GetIcon(extension)));
  status_icon_->SetContextMenu(context_menu_);  // for Update effect
}

void BackgroundModeManager::UpdateStatusTrayIconContextMenu() {
  if (!status_icon_)
    return;

  // Create a context menu item for Chrome.
  menus::SimpleMenuModel* menu = new menus::SimpleMenuModel(this);
  // Add About item
  menu->AddItem(IDC_ABOUT, l10n_util::GetStringFUTF16(IDS_ABOUT,
      l10n_util::GetStringUTF16(IDS_PRODUCT_NAME)));
  menu->AddItem(IDC_OPTIONS, GetPreferencesMenuLabel());
  menu->AddItemWithStringId(IDC_TASK_MANAGER, IDS_TASK_MANAGER);
  menu->AddSeparator();
  int application_position = 0;
  context_menu_application_offset_ = menu->GetItemCount();
  for (ExtensionList::const_iterator cursor = applications_.begin();
       cursor != applications_.end();
       ++cursor, ++application_position) {
    const SkBitmap* icon = applications_.GetIcon(*cursor);
    int sort_position = applications_.GetPosition(*cursor);
    DCHECK(sort_position == application_position);
    const std::string& name = (*cursor)->name();
    menu->AddItem(sort_position, ASCIIToUTF16(name));
    if (icon)
      menu->SetIcon(menu->GetItemCount() - 1, *icon);
  }
  if (applications_.size() > 0)
    menu->AddSeparator();
  menu->AddItemWithStringId(IDC_EXIT, IDS_EXIT);
  context_menu_ = menu;
  status_icon_->SetContextMenu(menu);
}

bool BackgroundModeManager::IsCommandIdChecked(int command_id) const {
  return false;
}

bool BackgroundModeManager::IsCommandIdEnabled(int command_id) const {
  // For now, we do not support disabled items.
  return true;
}

bool BackgroundModeManager::GetAcceleratorForCommandId(
    int command_id,
    menus::Accelerator* accelerator) {
  // No accelerators for status icon context menus.
  return false;
}

void BackgroundModeManager::RemoveStatusTrayIcon() {
  if (status_icon_)
    status_tray_->RemoveStatusIcon(status_icon_);
  status_icon_ = NULL;
}

void BackgroundModeManager::ExecuteApplication(int item) {
  DCHECK(item >= 0 && item < static_cast<int>(applications_.size()));
  Browser* browser = BrowserList::GetLastActive();
  if (!browser) {
    Browser::OpenEmptyWindow(profile_);
    browser = BrowserList::GetLastActive();
  }
  const Extension* extension = applications_.GetExtension(item);
  browser->OpenApplicationTab(profile_, extension, NULL);
}

void BackgroundModeManager::ExecuteCommand(int item) {
  switch (item) {
    case IDC_ABOUT:
      GetBrowserWindow()->OpenAboutChromeDialog();
      break;
    case IDC_EXIT:
      UserMetrics::RecordAction(UserMetricsAction("Exit"), profile_);
      BrowserList::CloseAllBrowsersAndExit();
      break;
    case IDC_OPTIONS:
      GetBrowserWindow()->OpenOptionsDialog();
      break;
    case IDC_TASK_MANAGER:
      GetBrowserWindow()->OpenTaskManager();
      break;
    default:
      ExecuteApplication(item);
      break;
  }
}

Browser* BackgroundModeManager::GetBrowserWindow() {
  Browser* browser = BrowserList::GetLastActive();
  if (!browser) {
    Browser::OpenEmptyWindow(profile_);
    browser = BrowserList::GetLastActive();
  }
  return browser;
}

// static
bool BackgroundModeManager::IsBackgroundModeEnabled(
    const CommandLine* command_line) {

  // Background mode is disabled if the appropriate flag is passed, or if
  // extensions are disabled.
  bool background_mode_enabled =
      !command_line->HasSwitch(switches::kDisableBackgroundMode) &&
      !command_line->HasSwitch(switches::kDisableExtensions);
#if !defined(OS_WIN)
  // BackgroundMode is enabled by default on windows. On other platforms, it
  // is enabled via about:flags.
  background_mode_enabled = background_mode_enabled &&
      command_line->HasSwitch(switches::kEnableBackgroundMode);
#endif

  return background_mode_enabled;
}

<|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.

// On Linux, when the user tries to launch a second copy of chrome, we check
// for a socket in the user's profile directory.  If the socket file is open we
// send a message to the first chrome browser process with the current
// directory and second process command line flags.  The second process then
// exits.

#include "chrome/browser/process_singleton.h"

#include <errno.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <set>

#include "base/base_paths.h"
#include "base/basictypes.h"
#include "base/command_line.h"
#include "base/eintr_wrapper.h"
#include "base/logging.h"
#include "base/message_loop.h"
#include "base/path_service.h"
#include "base/stl_util-inl.h"
#include "base/string_util.h"
#include "base/time.h"
#include "base/timer.h"
#include "chrome/browser/browser_init.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/profile_manager.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_paths.h"

namespace {

const char kStartToken[] = "START";
const char kTokenDelimiter = '\0';
const int kTimeOutInSeconds = 5;
const int kMaxMessageLength = 32 * 1024;

// Return 0 on success, -1 on failure.
int SetNonBlocking(int fd) {
  int flags = fcntl(fd, F_GETFL, 0);
  if (-1 == flags)
    return flags;
  if (flags & O_NONBLOCK)
    return 0;
  return fcntl(fd, F_SETFL, flags | O_NONBLOCK);
}

}  // namespace

///////////////////////////////////////////////////////////////////////////////
// ProcessSingleton::LinuxWatcher
// A helper class for a Linux specific implementation of the process singleton.
// This class sets up a listener on the singleton socket and handles parsing
// messages that come in on the singleton socket.
class ProcessSingleton::LinuxWatcher
    : public MessageLoopForIO::Watcher,
      public MessageLoop::DestructionObserver,
      public base::RefCountedThreadSafe<ProcessSingleton::LinuxWatcher> {
 public:
  // We expect to only be constructed on the UI thread.
  explicit LinuxWatcher(ProcessSingleton* parent)
      : ui_message_loop_(MessageLoop::current()),
        parent_(parent) {
  }

  virtual ~LinuxWatcher() {
    STLDeleteElements(&readers_);
  }

  // Start listening for connections on the socket.  This method should be
  // called from the IO thread.
  void StartListening(int socket);

  // This method determines if we should use the same process and if we should,
  // opens a new browser tab.  This runs on the UI thread.
  void HandleMessage(std::string current_dir, std::vector<std::string> argv);

  // MessageLoopForIO::Watcher impl.  These run on the IO thread.
  virtual void OnFileCanReadWithoutBlocking(int fd);
  virtual void OnFileCanWriteWithoutBlocking(int fd) {
    // ProcessSingleton only watches for accept (read) events.
    NOTREACHED();
  }

  // MessageLoop::DestructionObserver
  virtual void WillDestroyCurrentMessageLoop() {
    fd_watcher_.StopWatchingFileDescriptor();
  }

 private:
  class SocketReader : public MessageLoopForIO::Watcher {
   public:
    SocketReader(ProcessSingleton::LinuxWatcher* parent,
                 MessageLoop* ui_message_loop,
                 int fd)
        : parent_(parent),
          ui_message_loop_(ui_message_loop),
          fd_(fd),
          bytes_read_(0) {
      // Wait for reads.
      MessageLoopForIO::current()->WatchFileDescriptor(
          fd, true, MessageLoopForIO::WATCH_READ, &fd_reader_, this);
      timer_.Start(base::TimeDelta::FromSeconds(kTimeOutInSeconds),
                   this, &SocketReader::OnTimerExpiry);
    }

    virtual ~SocketReader() {
      int rv = HANDLE_EINTR(close(fd_));
      DCHECK_EQ(0, rv) << "Error closing socket: " << strerror(errno);
    }

    // MessageLoopForIO::Watcher impl.
    virtual void OnFileCanReadWithoutBlocking(int fd);
    virtual void OnFileCanWriteWithoutBlocking(int fd) {
      // SocketReader only watches for accept (read) events.
      NOTREACHED();
    }

   private:
    // If we haven't completed in a reasonable amount of time, give up.
    void OnTimerExpiry() {
      parent_->RemoveSocketReader(this);
      // We're deleted beyond this point.
    }

    MessageLoopForIO::FileDescriptorWatcher fd_reader_;

    // The ProcessSingleton::LinuxWatcher that owns us.
    ProcessSingleton::LinuxWatcher* const parent_;

    // A reference to the UI message loop.
    MessageLoop* const ui_message_loop_;

    // The file descriptor we're reading.
    const int fd_;

    // Store the message in this buffer.
    char buf_[kMaxMessageLength];

    // Tracks the number of bytes we've read in case we're getting partial
    // reads.
    size_t bytes_read_;

    base::OneShotTimer<SocketReader> timer_;

    DISALLOW_COPY_AND_ASSIGN(SocketReader);
  };

  // Removes and deletes the SocketReader.
  void RemoveSocketReader(SocketReader* reader);

  MessageLoopForIO::FileDescriptorWatcher fd_watcher_;

  // A reference to the UI message loop (i.e., the message loop we were
  // constructed on).
  MessageLoop* ui_message_loop_;

  // The ProcessSingleton that owns us.
  ProcessSingleton* const parent_;

  std::set<SocketReader*> readers_;

  DISALLOW_COPY_AND_ASSIGN(LinuxWatcher);
};

void ProcessSingleton::LinuxWatcher::OnFileCanReadWithoutBlocking(int fd) {
  // Accepting incoming client.
  sockaddr_un from;
  socklen_t from_len = sizeof(from);
  int connection_socket = HANDLE_EINTR(accept(
      fd, reinterpret_cast<sockaddr*>(&from), &from_len));
  if (-1 == connection_socket) {
    LOG(ERROR) << "accept() failed: " << strerror(errno);
    return;
  }
  SocketReader* reader = new SocketReader(this,
                                          ui_message_loop_,
                                          connection_socket);
  readers_.insert(reader);
}

void ProcessSingleton::LinuxWatcher::StartListening(int socket) {
  DCHECK(ChromeThread::GetMessageLoop(ChromeThread::IO) ==
         MessageLoop::current());
  // Watch for client connections on this socket.
  MessageLoopForIO* ml = MessageLoopForIO::current();
  ml->AddDestructionObserver(this);
  ml->WatchFileDescriptor(socket, true, MessageLoopForIO::WATCH_READ,
                          &fd_watcher_, this);
}

void ProcessSingleton::LinuxWatcher::HandleMessage(std::string current_dir,
    std::vector<std::string> argv) {
  DCHECK(ui_message_loop_ == MessageLoop::current());
  // Ignore the request if the browser process is already in shutdown path.
  if (!g_browser_process || g_browser_process->IsShuttingDown()) {
    LOG(WARNING) << "Not handling interprocess notification as browser"
                    " is shutting down";
    return;
  }

  // If locked, it means we are not ready to process this message because
  // we are probably in a first run critical phase.
  if (parent_->locked()) {
    DLOG(WARNING) << "Browser is locked";
    return;
  }

  CommandLine parsed_command_line(argv);
  PrefService* prefs = g_browser_process->local_state();
  DCHECK(prefs);

  FilePath user_data_dir;
  PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
  ProfileManager* profile_manager = g_browser_process->profile_manager();
  Profile* profile = profile_manager->GetDefaultProfile(user_data_dir);
  if (!profile) {
    // We should only be able to get here if the profile already exists and
    // has been created.
    NOTREACHED();
    return;
  }

  // TODO(tc): Send an ACK response on success.

  // Run the browser startup sequence again, with the command line of the
  // signalling process.
  FilePath current_dir_file_path(current_dir);
  BrowserInit::ProcessCommandLine(parsed_command_line,
                                  current_dir_file_path.ToWStringHack(),
                                  false, profile, NULL);
}

void ProcessSingleton::LinuxWatcher::RemoveSocketReader(SocketReader* reader) {
  DCHECK(reader);
  readers_.erase(reader);
  delete reader;
}

///////////////////////////////////////////////////////////////////////////////
// ProcessSingleton::LinuxWatcher::SocketReader
//

void ProcessSingleton::LinuxWatcher::SocketReader::OnFileCanReadWithoutBlocking(
    int fd) {
  DCHECK_EQ(fd, fd_);
  while (bytes_read_ < sizeof(buf_)) {
    ssize_t rv = HANDLE_EINTR(
        read(fd, buf_ + bytes_read_, sizeof(buf_) - bytes_read_));
    if (rv < 0) {
      if (errno != EAGAIN && errno != EWOULDBLOCK) {
        LOG(ERROR) << "read() failed: " << strerror(errno);
        rv = HANDLE_EINTR(close(fd));
        DCHECK_EQ(0, rv) << "Error closing socket: " << strerror(errno);
        return;
      } else {
        // It would block, so we just return and continue to watch for the next
        // opportunity to read.
        return;
      }
    } else if (!rv) {
      // No more data to read.  It's time to process the message.
      break;
    } else {
      bytes_read_ += rv;
    }
  }

  // Validate the message.  The shortest message is kStartToken\0x\0x
  const size_t kMinMessageLength = arraysize(kStartToken) + 4;
  if (bytes_read_ < kMinMessageLength) {
    buf_[bytes_read_] = 0;
    LOG(ERROR) << "Invalid socket message (wrong length):" << buf_;
    return;
  }

  std::string str(buf_, bytes_read_);
  std::vector<std::string> tokens;
  SplitString(str, kTokenDelimiter, &tokens);

  if (tokens.size() < 3 || tokens[0] != kStartToken) {
    LOG(ERROR) << "Wrong message format: " << str;
    return;
  }

  std::string current_dir = tokens[1];
  // Remove the first two tokens.  The remaining tokens should be the command
  // line argv array.
  tokens.erase(tokens.begin());
  tokens.erase(tokens.begin());

  // Return to the UI thread to handle opening a new browser tab.
  ui_message_loop_->PostTask(FROM_HERE, NewRunnableMethod(
      parent_,
      &ProcessSingleton::LinuxWatcher::HandleMessage,
      current_dir,
      tokens));
  fd_reader_.StopWatchingFileDescriptor();

  parent_->RemoveSocketReader(this);
  // We are deleted beyond this point.
}

///////////////////////////////////////////////////////////////////////////////
// ProcessSingleton
//
ProcessSingleton::ProcessSingleton(const FilePath& user_data_dir)
    : locked_(false),
      foreground_window_(NULL),
      ALLOW_THIS_IN_INITIALIZER_LIST(watcher_(new LinuxWatcher(this))) {
  socket_path_ = user_data_dir.Append(chrome::kSingletonSocketFilename);
}

ProcessSingleton::~ProcessSingleton() {
}

bool ProcessSingleton::NotifyOtherProcess() {
  int socket;
  sockaddr_un addr;
  SetupSocket(&socket, &addr);

  // Connecting to the socket
  int ret = HANDLE_EINTR(connect(socket,
                                 reinterpret_cast<sockaddr*>(&addr),
                                 sizeof(addr)));
  if (ret < 0)
    return false;  // Tell the caller there's nobody to notify.

  timeval timeout = {20, 0};
  setsockopt(socket, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout));

  // Found another process, prepare our command line
  // format is "START\0<current dir>\0<argv[0]>\0...\0<argv[n]>".
  std::string to_send(kStartToken);
  to_send.push_back(kTokenDelimiter);

  FilePath current_dir;
  if (!PathService::Get(base::DIR_CURRENT, &current_dir))
    return false;
  to_send.append(current_dir.value());

  const std::vector<std::string>& argv =
      CommandLine::ForCurrentProcess()->argv();
  for (std::vector<std::string>::const_iterator it = argv.begin();
      it != argv.end(); ++it) {
    to_send.push_back(kTokenDelimiter);
    to_send.append(*it);
  }

  // Send the message
  int bytes_written = 0;
  const int buf_len = to_send.length();
  do {
    int rv = HANDLE_EINTR(
        write(socket, to_send.data() + bytes_written, buf_len - bytes_written));
    if (rv < 0) {
      if (errno == EAGAIN || errno == EWOULDBLOCK) {
        // The socket shouldn't block, we're sending so little data.  Just give
        // up here, since NotifyOtherProcess() doesn't have an asynchronous api.
        LOG(ERROR) << "ProcessSingleton would block on write(), so it gave up.";
        return false;
      }
      LOG(ERROR) << "write() failed: " << strerror(errno);
      return false;
    }
    bytes_written += rv;
  } while (bytes_written < buf_len);

  int rv = shutdown(socket, SHUT_WR);
  if (rv < 0) {
    LOG(ERROR) << "shutdown() failed: " << strerror(errno);
  } else {
    // TODO(tc): We should wait for an ACK, and if we don't get it in a certain
    // time period, kill the other process.
  }

  rv = HANDLE_EINTR(close(socket));
  DCHECK_EQ(0, rv) << strerror(errno);

  // Assume the other process is handling the request.
  return true;
}

void ProcessSingleton::Create() {
  int sock;
  sockaddr_un addr;
  SetupSocket(&sock, &addr);

  if (unlink(socket_path_.value().c_str()) < 0)
    DCHECK_EQ(errno, ENOENT);

  if (bind(sock, reinterpret_cast<sockaddr*>(&addr), sizeof(addr)) < 0) {
    LOG(ERROR) << "bind() failed: " << strerror(errno);
    LOG(ERROR) << "SingletonSocket failed to create a socket in your home "
                  "directory. This means that running multiple instances of "
                  "the Chrome binary will start multiple browser process "
                  "rather than opening a new window in the existing process.";
    close(sock);
    return;
  }

  if (listen(sock, 5) < 0)
    NOTREACHED() << "listen failed: " << strerror(errno);

  // Normally we would use ChromeThread, but the IO thread hasn't started yet.
  // Using g_browser_process, we start the thread so we can listen on the
  // socket.
  MessageLoop* ml = g_browser_process->io_thread()->message_loop();
  DCHECK(ml);
  ml->PostTask(FROM_HERE, NewRunnableMethod(
    watcher_.get(),
    &ProcessSingleton::LinuxWatcher::StartListening,
    sock));
}

void ProcessSingleton::SetupSocket(int* sock, struct sockaddr_un* addr) {
  *sock = socket(PF_UNIX, SOCK_STREAM, 0);
  if (*sock < 0)
    LOG(FATAL) << "socket() failed: " << strerror(errno);

  int rv = SetNonBlocking(*sock);
  DCHECK_EQ(0, rv) << "Failed to make non-blocking socket.";

  addr->sun_family = AF_UNIX;
  if (socket_path_.value().length() > sizeof(addr->sun_path) - 1)
    LOG(FATAL) << "Socket path too long: " << socket_path_.value();
  base::strlcpy(addr->sun_path, socket_path_.value().c_str(),
                sizeof(addr->sun_path));
}
<commit_msg>linux: set FD_CLOEXEC on the singleton socket<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.

// On Linux, when the user tries to launch a second copy of chrome, we check
// for a socket in the user's profile directory.  If the socket file is open we
// send a message to the first chrome browser process with the current
// directory and second process command line flags.  The second process then
// exits.

#include "chrome/browser/process_singleton.h"

#include <errno.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <set>

#include "base/base_paths.h"
#include "base/basictypes.h"
#include "base/command_line.h"
#include "base/eintr_wrapper.h"
#include "base/logging.h"
#include "base/message_loop.h"
#include "base/path_service.h"
#include "base/stl_util-inl.h"
#include "base/string_util.h"
#include "base/time.h"
#include "base/timer.h"
#include "chrome/browser/browser_init.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/profile_manager.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_paths.h"

namespace {

const char kStartToken[] = "START";
const char kTokenDelimiter = '\0';
const int kTimeOutInSeconds = 5;
const int kMaxMessageLength = 32 * 1024;

// Set a file descriptor to be non-blocking.
// Return 0 on success, -1 on failure.
int SetNonBlocking(int fd) {
  int flags = fcntl(fd, F_GETFL, 0);
  if (-1 == flags)
    return flags;
  if (flags & O_NONBLOCK)
    return 0;
  return fcntl(fd, F_SETFL, flags | O_NONBLOCK);
}

// Set the close-on-exec bit on a file descriptor.
// Returns 0 on success, -1 on failure.
int SetCloseOnExec(int fd) {
  int flags = fcntl(fd, F_GETFD, 0);
  if (-1 == flags)
    return flags;
  if (flags & FD_CLOEXEC)
    return 0;
  return fcntl(fd, F_SETFD, flags | FD_CLOEXEC);
}

}  // namespace

///////////////////////////////////////////////////////////////////////////////
// ProcessSingleton::LinuxWatcher
// A helper class for a Linux specific implementation of the process singleton.
// This class sets up a listener on the singleton socket and handles parsing
// messages that come in on the singleton socket.
class ProcessSingleton::LinuxWatcher
    : public MessageLoopForIO::Watcher,
      public MessageLoop::DestructionObserver,
      public base::RefCountedThreadSafe<ProcessSingleton::LinuxWatcher> {
 public:
  // We expect to only be constructed on the UI thread.
  explicit LinuxWatcher(ProcessSingleton* parent)
      : ui_message_loop_(MessageLoop::current()),
        parent_(parent) {
  }

  virtual ~LinuxWatcher() {
    STLDeleteElements(&readers_);
  }

  // Start listening for connections on the socket.  This method should be
  // called from the IO thread.
  void StartListening(int socket);

  // This method determines if we should use the same process and if we should,
  // opens a new browser tab.  This runs on the UI thread.
  void HandleMessage(std::string current_dir, std::vector<std::string> argv);

  // MessageLoopForIO::Watcher impl.  These run on the IO thread.
  virtual void OnFileCanReadWithoutBlocking(int fd);
  virtual void OnFileCanWriteWithoutBlocking(int fd) {
    // ProcessSingleton only watches for accept (read) events.
    NOTREACHED();
  }

  // MessageLoop::DestructionObserver
  virtual void WillDestroyCurrentMessageLoop() {
    fd_watcher_.StopWatchingFileDescriptor();
  }

 private:
  class SocketReader : public MessageLoopForIO::Watcher {
   public:
    SocketReader(ProcessSingleton::LinuxWatcher* parent,
                 MessageLoop* ui_message_loop,
                 int fd)
        : parent_(parent),
          ui_message_loop_(ui_message_loop),
          fd_(fd),
          bytes_read_(0) {
      // Wait for reads.
      MessageLoopForIO::current()->WatchFileDescriptor(
          fd, true, MessageLoopForIO::WATCH_READ, &fd_reader_, this);
      timer_.Start(base::TimeDelta::FromSeconds(kTimeOutInSeconds),
                   this, &SocketReader::OnTimerExpiry);
    }

    virtual ~SocketReader() {
      int rv = HANDLE_EINTR(close(fd_));
      DCHECK_EQ(0, rv) << "Error closing socket: " << strerror(errno);
    }

    // MessageLoopForIO::Watcher impl.
    virtual void OnFileCanReadWithoutBlocking(int fd);
    virtual void OnFileCanWriteWithoutBlocking(int fd) {
      // SocketReader only watches for accept (read) events.
      NOTREACHED();
    }

   private:
    // If we haven't completed in a reasonable amount of time, give up.
    void OnTimerExpiry() {
      parent_->RemoveSocketReader(this);
      // We're deleted beyond this point.
    }

    MessageLoopForIO::FileDescriptorWatcher fd_reader_;

    // The ProcessSingleton::LinuxWatcher that owns us.
    ProcessSingleton::LinuxWatcher* const parent_;

    // A reference to the UI message loop.
    MessageLoop* const ui_message_loop_;

    // The file descriptor we're reading.
    const int fd_;

    // Store the message in this buffer.
    char buf_[kMaxMessageLength];

    // Tracks the number of bytes we've read in case we're getting partial
    // reads.
    size_t bytes_read_;

    base::OneShotTimer<SocketReader> timer_;

    DISALLOW_COPY_AND_ASSIGN(SocketReader);
  };

  // Removes and deletes the SocketReader.
  void RemoveSocketReader(SocketReader* reader);

  MessageLoopForIO::FileDescriptorWatcher fd_watcher_;

  // A reference to the UI message loop (i.e., the message loop we were
  // constructed on).
  MessageLoop* ui_message_loop_;

  // The ProcessSingleton that owns us.
  ProcessSingleton* const parent_;

  std::set<SocketReader*> readers_;

  DISALLOW_COPY_AND_ASSIGN(LinuxWatcher);
};

void ProcessSingleton::LinuxWatcher::OnFileCanReadWithoutBlocking(int fd) {
  // Accepting incoming client.
  sockaddr_un from;
  socklen_t from_len = sizeof(from);
  int connection_socket = HANDLE_EINTR(accept(
      fd, reinterpret_cast<sockaddr*>(&from), &from_len));
  if (-1 == connection_socket) {
    LOG(ERROR) << "accept() failed: " << strerror(errno);
    return;
  }
  SocketReader* reader = new SocketReader(this,
                                          ui_message_loop_,
                                          connection_socket);
  readers_.insert(reader);
}

void ProcessSingleton::LinuxWatcher::StartListening(int socket) {
  DCHECK(ChromeThread::GetMessageLoop(ChromeThread::IO) ==
         MessageLoop::current());
  // Watch for client connections on this socket.
  MessageLoopForIO* ml = MessageLoopForIO::current();
  ml->AddDestructionObserver(this);
  ml->WatchFileDescriptor(socket, true, MessageLoopForIO::WATCH_READ,
                          &fd_watcher_, this);
}

void ProcessSingleton::LinuxWatcher::HandleMessage(std::string current_dir,
    std::vector<std::string> argv) {
  DCHECK(ui_message_loop_ == MessageLoop::current());
  // Ignore the request if the browser process is already in shutdown path.
  if (!g_browser_process || g_browser_process->IsShuttingDown()) {
    LOG(WARNING) << "Not handling interprocess notification as browser"
                    " is shutting down";
    return;
  }

  // If locked, it means we are not ready to process this message because
  // we are probably in a first run critical phase.
  if (parent_->locked()) {
    DLOG(WARNING) << "Browser is locked";
    return;
  }

  CommandLine parsed_command_line(argv);
  PrefService* prefs = g_browser_process->local_state();
  DCHECK(prefs);

  FilePath user_data_dir;
  PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
  ProfileManager* profile_manager = g_browser_process->profile_manager();
  Profile* profile = profile_manager->GetDefaultProfile(user_data_dir);
  if (!profile) {
    // We should only be able to get here if the profile already exists and
    // has been created.
    NOTREACHED();
    return;
  }

  // TODO(tc): Send an ACK response on success.

  // Run the browser startup sequence again, with the command line of the
  // signalling process.
  FilePath current_dir_file_path(current_dir);
  BrowserInit::ProcessCommandLine(parsed_command_line,
                                  current_dir_file_path.ToWStringHack(),
                                  false, profile, NULL);
}

void ProcessSingleton::LinuxWatcher::RemoveSocketReader(SocketReader* reader) {
  DCHECK(reader);
  readers_.erase(reader);
  delete reader;
}

///////////////////////////////////////////////////////////////////////////////
// ProcessSingleton::LinuxWatcher::SocketReader
//

void ProcessSingleton::LinuxWatcher::SocketReader::OnFileCanReadWithoutBlocking(
    int fd) {
  DCHECK_EQ(fd, fd_);
  while (bytes_read_ < sizeof(buf_)) {
    ssize_t rv = HANDLE_EINTR(
        read(fd, buf_ + bytes_read_, sizeof(buf_) - bytes_read_));
    if (rv < 0) {
      if (errno != EAGAIN && errno != EWOULDBLOCK) {
        LOG(ERROR) << "read() failed: " << strerror(errno);
        rv = HANDLE_EINTR(close(fd));
        DCHECK_EQ(0, rv) << "Error closing socket: " << strerror(errno);
        return;
      } else {
        // It would block, so we just return and continue to watch for the next
        // opportunity to read.
        return;
      }
    } else if (!rv) {
      // No more data to read.  It's time to process the message.
      break;
    } else {
      bytes_read_ += rv;
    }
  }

  // Validate the message.  The shortest message is kStartToken\0x\0x
  const size_t kMinMessageLength = arraysize(kStartToken) + 4;
  if (bytes_read_ < kMinMessageLength) {
    buf_[bytes_read_] = 0;
    LOG(ERROR) << "Invalid socket message (wrong length):" << buf_;
    return;
  }

  std::string str(buf_, bytes_read_);
  std::vector<std::string> tokens;
  SplitString(str, kTokenDelimiter, &tokens);

  if (tokens.size() < 3 || tokens[0] != kStartToken) {
    LOG(ERROR) << "Wrong message format: " << str;
    return;
  }

  std::string current_dir = tokens[1];
  // Remove the first two tokens.  The remaining tokens should be the command
  // line argv array.
  tokens.erase(tokens.begin());
  tokens.erase(tokens.begin());

  // Return to the UI thread to handle opening a new browser tab.
  ui_message_loop_->PostTask(FROM_HERE, NewRunnableMethod(
      parent_,
      &ProcessSingleton::LinuxWatcher::HandleMessage,
      current_dir,
      tokens));
  fd_reader_.StopWatchingFileDescriptor();

  parent_->RemoveSocketReader(this);
  // We are deleted beyond this point.
}

///////////////////////////////////////////////////////////////////////////////
// ProcessSingleton
//
ProcessSingleton::ProcessSingleton(const FilePath& user_data_dir)
    : locked_(false),
      foreground_window_(NULL),
      ALLOW_THIS_IN_INITIALIZER_LIST(watcher_(new LinuxWatcher(this))) {
  socket_path_ = user_data_dir.Append(chrome::kSingletonSocketFilename);
}

ProcessSingleton::~ProcessSingleton() {
}

bool ProcessSingleton::NotifyOtherProcess() {
  int socket;
  sockaddr_un addr;
  SetupSocket(&socket, &addr);

  // Connecting to the socket
  int ret = HANDLE_EINTR(connect(socket,
                                 reinterpret_cast<sockaddr*>(&addr),
                                 sizeof(addr)));
  if (ret < 0)
    return false;  // Tell the caller there's nobody to notify.

  timeval timeout = {20, 0};
  setsockopt(socket, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout));

  // Found another process, prepare our command line
  // format is "START\0<current dir>\0<argv[0]>\0...\0<argv[n]>".
  std::string to_send(kStartToken);
  to_send.push_back(kTokenDelimiter);

  FilePath current_dir;
  if (!PathService::Get(base::DIR_CURRENT, &current_dir))
    return false;
  to_send.append(current_dir.value());

  const std::vector<std::string>& argv =
      CommandLine::ForCurrentProcess()->argv();
  for (std::vector<std::string>::const_iterator it = argv.begin();
      it != argv.end(); ++it) {
    to_send.push_back(kTokenDelimiter);
    to_send.append(*it);
  }

  // Send the message
  int bytes_written = 0;
  const int buf_len = to_send.length();
  do {
    int rv = HANDLE_EINTR(
        write(socket, to_send.data() + bytes_written, buf_len - bytes_written));
    if (rv < 0) {
      if (errno == EAGAIN || errno == EWOULDBLOCK) {
        // The socket shouldn't block, we're sending so little data.  Just give
        // up here, since NotifyOtherProcess() doesn't have an asynchronous api.
        LOG(ERROR) << "ProcessSingleton would block on write(), so it gave up.";
        return false;
      }
      LOG(ERROR) << "write() failed: " << strerror(errno);
      return false;
    }
    bytes_written += rv;
  } while (bytes_written < buf_len);

  int rv = shutdown(socket, SHUT_WR);
  if (rv < 0) {
    LOG(ERROR) << "shutdown() failed: " << strerror(errno);
  } else {
    // TODO(tc): We should wait for an ACK, and if we don't get it in a certain
    // time period, kill the other process.
  }

  rv = HANDLE_EINTR(close(socket));
  DCHECK_EQ(0, rv) << strerror(errno);

  // Assume the other process is handling the request.
  return true;
}

void ProcessSingleton::Create() {
  int sock;
  sockaddr_un addr;
  SetupSocket(&sock, &addr);

  if (unlink(socket_path_.value().c_str()) < 0)
    DCHECK_EQ(errno, ENOENT);

  if (bind(sock, reinterpret_cast<sockaddr*>(&addr), sizeof(addr)) < 0) {
    LOG(ERROR) << "bind() failed: " << strerror(errno);
    LOG(ERROR) << "SingletonSocket failed to create a socket in your home "
                  "directory. This means that running multiple instances of "
                  "the Chrome binary will start multiple browser process "
                  "rather than opening a new window in the existing process.";
    close(sock);
    return;
  }

  if (listen(sock, 5) < 0)
    NOTREACHED() << "listen failed: " << strerror(errno);

  // Normally we would use ChromeThread, but the IO thread hasn't started yet.
  // Using g_browser_process, we start the thread so we can listen on the
  // socket.
  MessageLoop* ml = g_browser_process->io_thread()->message_loop();
  DCHECK(ml);
  ml->PostTask(FROM_HERE, NewRunnableMethod(
    watcher_.get(),
    &ProcessSingleton::LinuxWatcher::StartListening,
    sock));
}

void ProcessSingleton::SetupSocket(int* sock, struct sockaddr_un* addr) {
  *sock = socket(PF_UNIX, SOCK_STREAM, 0);
  if (*sock < 0)
    LOG(FATAL) << "socket() failed: " << strerror(errno);

  int rv = SetNonBlocking(*sock);
  DCHECK_EQ(0, rv) << "Failed to make non-blocking socket.";
  rv = SetCloseOnExec(*sock);
  DCHECK_EQ(0, rv) << "Failed to set CLOEXEC on socket.";

  addr->sun_family = AF_UNIX;
  if (socket_path_.value().length() > sizeof(addr->sun_path) - 1)
    LOG(FATAL) << "Socket path too long: " << socket_path_.value();
  base::strlcpy(addr->sun_path, socket_path_.value().c_str(),
                sizeof(addr->sun_path));
}
<|endoftext|>


<commit_before>//$Id$

#include "RemoteHopsanClient.h"

#include "msgpack.hpp"
#include "Messages.h"
#include "MessageUtilities.h"

#include <iostream>

using namespace std;

// ---------- Help functions start ----------

template <typename T>
void sendClientMessage(zmq::socket_t &rSocket, ClientMessageIdEnumT id, const T &rMessage)
{
    msgpack::v1::sbuffer out_buffer;
    msgpack::pack(out_buffer, id);
    msgpack::pack(out_buffer, rMessage);
    rSocket.send(static_cast<void*>(out_buffer.data()), out_buffer.size());
}

void sendShortClientMessage(zmq::socket_t &rSocket, ClientMessageIdEnumT id)
{
    msgpack::v1::sbuffer out_buffer;
    msgpack::pack(out_buffer, id);
    rSocket.send(static_cast<void*>(out_buffer.data()), out_buffer.size());
}

bool readAckNackServerMessage(zmq::socket_t &rSocket, long timeout, string &rNackReason)
{
    zmq::message_t response;
    if(receiveWithTimeout(rSocket, timeout, response))
    {
        size_t offset=0;
        size_t id = getMessageId(response, offset);
        //cout << "id: " << id << endl;
        if (id == S_Ack)
        {
            return true;
        }
        else if (id == S_NAck)
        {
            rNackReason = unpackMessage<std::string>(response, offset);
        }
        else
        {
            rNackReason = "Got neither Ack nor Nack";
        }
    }
    else
    {
        rNackReason = "Got either timeout or exception in zmq::recv()";
    }
    return false;
}

bool readAckNackServerMessage(zmq::socket_t &rSocket, long timeout)
{
    string dummy;
    return readAckNackServerMessage(rSocket, timeout, dummy);
}

// ---------- Help functions end ----------

bool RemoteHopsanClient::connectToServer(std::string zmqaddres)
{
    if (serverConnected())
    {
        mLastErrorMessage = "You are already connected to a server";
        return false;
    }
    else
    {
        try
        {
            mRSCSocket.connect(zmqaddres.c_str());
            mServerAddress = zmqaddres;
            return true;
        }
        catch (zmq::error_t e)
        {
            mLastErrorMessage =  e.what();
            mServerAddress.clear();
            return false;
        }
    }
}

bool RemoteHopsanClient::connectToServer(string ip, string port)
{
    return connectToServer(makeZMQAddress(ip,port));
}

bool RemoteHopsanClient::serverConnected()
{
    // Note we can not use socket.connected() it only checks if underlying c-socket exist
    return !mServerAddress.empty();
}

bool RemoteHopsanClient::sendGetParamMessage(const string &rName, string &rValue)
{
    CM_GetParam_t msg {rName};
    sendClientMessage<CM_GetParam_t>(mRWCSocket, C_GetParam, msg);

    zmq::message_t response;
    mRWCSocket.recv(&response);
    size_t offset=0;
    size_t id = getMessageId(response, offset);
    if (id == S_GetParam_Reply)
    {
        rValue = unpackMessage<string>(response, offset);
        assert(response.size() == offset);
        return true;
    }
    else
    {
        rValue.clear();
        return false;
    }
}

bool RemoteHopsanClient::sendSetParamMessage(const string &rName, const string &rValue)
{
    CM_SetParam_t msg {rName, rValue};
    sendClientMessage<CM_SetParam_t>(mRWCSocket, C_SetParam, msg);

    string err;
    bool rc = readAckNackServerMessage(mRWCSocket, mReceiveTimeout, err);
    if (!rc)
    {
        cout << err << endl;
    }
    return rc;
}

bool RemoteHopsanClient::sendModelMessage(const std::string &rModel)
{
    sendClientMessage<std::string>(mRWCSocket, C_SendingHmf, rModel);
    string err;
    bool rc = readAckNackServerMessage(mRWCSocket, mReceiveTimeout, err);
    if (!rc)
    {
        cout << err << endl;
    }
    return rc;
}

bool RemoteHopsanClient::sendSimulateMessage(const int nLogsamples, const int logStartTime,
                         const int simStarttime, const int simSteptime, const int simStoptime)
{
    CM_Simulate_t msg;// {nLogsamples, logStartTime, simStarttime, simSteptime, simStoptime};
    sendClientMessage<CM_Simulate_t>(mRWCSocket, C_Simulate, msg);
    string err;
    //! @todo blocking read for now, in the future we need to poll while simulating
    bool rc = readAckNackServerMessage(mRWCSocket, -1, err);
    if (!rc)
    {
        cout << err << endl;
    }
    return rc;
}

bool RemoteHopsanClient::requestStatus(ServerStatusT &rServerStatus)
{
    sendShortClientMessage(mRSCSocket, C_ReqStatus);

    zmq::message_t response;
    if (receiveWithTimeout(mRSCSocket, response))
    {
        //cout << "Response size: " << response.size() << endl;
        size_t offset=0;
        size_t id = getMessageId(response, offset);
        if (id == S_ReqStatus_Reply)
        {
            SM_ServerStatus_t status = unpackMessage<SM_ServerStatus_t>(response, offset);
            rServerStatus = status;
            //cout << "Got status reply" << endl;
            return true;
        }
    }
    return false;
}

bool RemoteHopsanClient::requestSimulationResults(vector<string> *pDataNames, vector<double> *pData)
{
    sendClientMessage<string>(mRWCSocket, C_ReqResults, "*"); // Request all

    zmq::message_t response;
    if (receiveWithTimeout(mRWCSocket, response))
    {
        cout << "Response size: " << response.size() << endl;
        size_t offset=0;
        size_t id = getMessageId(response, offset);
        if (id == S_ReqResults_Reply)
        {
            vector<SM_Variable_Description_t> vars = unpackMessage<vector<SM_Variable_Description_t>>(response,offset);
            cout << "Received: " << vars.size() << " vars" << endl;
            size_t nLogSamples;
            if (!vars.empty())
            {
                nLogSamples = vars[0].data.size();
            }

            pDataNames->reserve(vars.size());
            pData->reserve(nLogSamples*vars.size());

            for (auto &v : vars)
            {
                pDataNames->push_back(v.name);
                cout << v.name << " " << v.alias << " " << v.unit << " Data:";
                for (auto d : v.data)
                {
                    pData->push_back(d);
                    //cout << " " << d;
                }
                cout << endl;
            }

            return true;
        }
        else
        {
            mLastErrorMessage = "Got wrong reply";
        }
    }
    return false;
}

bool RemoteHopsanClient::requestSlot(size_t &rControlPort)
{
    sendShortClientMessage(mRSCSocket, C_ReqSlot);

    zmq::message_t response;
    if (receiveWithTimeout(mRSCSocket, response))
    {
        size_t offset=0;
        size_t id = getMessageId(response, offset);
        if (id == S_ReqSlot_Reply)
        {
            SM_ReqSlot_Reply_t msg = unpackMessage<SM_ReqSlot_Reply_t>(response, offset);
            rControlPort = msg.port;
            assert(response.size() == offset);
            return true;
        }
        else if (id == S_NAck)
        {
            mLastErrorMessage = unpackMessage<string>(response, offset);
        }
        else
        {
            mLastErrorMessage = "Got wrong reply type from server";
        }
    }
    return false;
}

bool RemoteHopsanClient::connectToWorker(std::string zmqaddres)
{
    if (workerConnected())
    {
        mLastErrorMessage = "You are already connected to a worker";
        return false;
    }
    else
    {
        try
        {
            mRWCSocket.connect(zmqaddres.c_str());
            mWorkerAddress = zmqaddres;
            return true;
        }
        catch (zmq::error_t e)
        {
            mLastErrorMessage =  e.what();
            mWorkerAddress.clear();
            return false;
        }
    }
}

bool RemoteHopsanClient::connectToWorker(string ip, string port)
{
    return connectToWorker(makeZMQAddress(ip,port));
}

bool RemoteHopsanClient::workerConnected()
{
    // Note we can not use socket.connected() it only checks if underlying c-socket exist
    return !mWorkerAddress.empty();
}

void RemoteHopsanClient::disconnect()
{
    // Disconnect from Worker
    if (workerConnected())
    {
        sendShortClientMessage(mRWCSocket, C_Bye);
        readAckNackServerMessage(mRWCSocket, 1000); //But we do not care about result
        mRWCSocket.disconnect(mWorkerAddress.c_str());
        mWorkerAddress.clear();
    }

    // Disconnect from Server
    if (serverConnected())
    {
        //! @todo maybe should auto disconnect when we connect to worker
        mRSCSocket.disconnect(mServerAddress.c_str());
        mServerAddress.clear();
    }
}

bool RemoteHopsanClient::requestMessages()
{
    sendShortClientMessage(mRWCSocket, C_ReqMessages);

    zmq::message_t response;
    if (receiveWithTimeout(mRWCSocket, response))
    {
        size_t offset=0;
        size_t id = getMessageId(response, offset);
        if (id == S_ReqMessages_Reply)
        {
            vector<SM_HopsanCoreMessage_t> messages = unpackMessage<vector<SM_HopsanCoreMessage_t>>(response, offset);
            cout << "Received: " << messages.size() << " messages from server" << endl;
            for (size_t m=0; m<messages.size(); ++m)
            {
                cout << messages[m].type << " " << messages[m].tag << " " << messages[m].message << endl;
            }
            return true;
        }
        else
        {
            mLastErrorMessage = "Got wrong reply";
        }
    }
    return false;
}

bool RemoteHopsanClient::requestMessages(std::vector<char> &rTypes, std::vector<string> &rTags, std::vector<string> &rMessages)
{
    sendShortClientMessage(mRWCSocket, C_ReqMessages);

    zmq::message_t response;
    if (receiveWithTimeout(mRWCSocket, response))
    {
        size_t offset=0;
        size_t id = getMessageId(response, offset);
        if (id == S_ReqMessages_Reply)
        {
            vector<SM_HopsanCoreMessage_t> messages = unpackMessage<vector<SM_HopsanCoreMessage_t>>(response, offset);
            //cout << "Received: " << messages.size() << " messages from server" << endl;
            rTypes.resize(messages.size());
            rTags.resize(messages.size());
            rMessages.resize(messages.size());
            for (size_t m=0; m<messages.size(); ++m)
            {
                rTypes[m] =  messages[m].type;
                rTags[m] = messages[m].tag;
                rMessages[m] = messages[m].message;
            }
            return true;
        }
        else
        {
            mLastErrorMessage = "Got wrong reply";
        }
    }
    return false;
}

bool RemoteHopsanClient::requestServerMachines(int nMachines, double maxBenchmarkTime, std::vector<string> &rIps, std::vector<string> &rPorts)
{
    CM_ReqServerMachines_t req;
    req.numMachines = nMachines;
    req.maxBenchmarkTime = maxBenchmarkTime;
    req.numThreads = -1;

    sendClientMessage<CM_ReqServerMachines_t>(mRSCSocket, C_ReqServerMachines, req);

    zmq::message_t response;
    if (receiveWithTimeout(mRSCSocket, response))
    {
        cout << "Response size: " << response.size() << endl;
        size_t offset=0;
        size_t id = getMessageId(response, offset);
        if (id == S_ReqServerMachines_Reply)
        {
            MSM_ReqServerMachines_Reply_t repl = unpackMessage<MSM_ReqServerMachines_Reply_t>(response,offset);
            rIps = repl.ips;
            rPorts = repl.ports;
            return true;
        }
        else
        {
            mLastErrorMessage = "Got wrong reply";
        }
    }
    return false;
}

string RemoteHopsanClient::getLastErrorMessage() const
{
    return mLastErrorMessage;
}

bool RemoteHopsanClient::receiveWithTimeout(zmq::socket_t &rSocket, zmq::message_t &rMessage)
{
    // Create a poll item
    zmq::pollitem_t pollitems[] = {{ rSocket, 0, ZMQ_POLLIN, 0 }};
    try
    {
        // Poll socket for a reply, with timeout
        zmq::poll(&pollitems[0], 1,  mReceiveTimeout);
        // If we have received a message then read message and return true
        if (pollitems[0].revents & ZMQ_POLLIN)
        {
            rSocket.recv(&rMessage);
            return true;
        }
        // Else we reached timeout, return false
        else
        {
            mLastErrorMessage = "Timeout in receive";
        }
    }
    catch(zmq::error_t e)
    {
        mLastErrorMessage = e.what();
    }
    return false;
}

RemoteHopsanClient::RemoteHopsanClient(zmq::context_t &rContext) :
    mRSCSocket(rContext, ZMQ_REQ), mRWCSocket(rContext, ZMQ_REQ)
{
    int linger_ms = 1000;
    mRSCSocket.setsockopt(ZMQ_LINGER, &linger_ms, sizeof(int));
    mRWCSocket.setsockopt(ZMQ_LINGER, &linger_ms, sizeof(int));
}

void RemoteHopsanClient::setReceiveTimeout(long ms)
{
    mReceiveTimeout = ms;
}

long RemoteHopsanClient::getReceiveTimeout() const
{
    return mReceiveTimeout;
}
<commit_msg>replaced blocking receive<commit_after>//$Id$

#include "RemoteHopsanClient.h"

#include "msgpack.hpp"
#include "Messages.h"
#include "MessageUtilities.h"

#include <iostream>

using namespace std;

// ---------- Help functions start ----------

template <typename T>
void sendClientMessage(zmq::socket_t &rSocket, ClientMessageIdEnumT id, const T &rMessage)
{
    msgpack::v1::sbuffer out_buffer;
    msgpack::pack(out_buffer, id);
    msgpack::pack(out_buffer, rMessage);
    try
    {
        rSocket.send(static_cast<void*>(out_buffer.data()), out_buffer.size());
    }
    catch(zmq::error_t e)
    {
        //Ignore
    }
}

void sendShortClientMessage(zmq::socket_t &rSocket, ClientMessageIdEnumT id)
{
    msgpack::v1::sbuffer out_buffer;
    msgpack::pack(out_buffer, id);
    try
    {
        rSocket.send(static_cast<void*>(out_buffer.data()), out_buffer.size());
    }
    catch(zmq::error_t e)
    {
        //Ignore
    }
}

bool readAckNackServerMessage(zmq::socket_t &rSocket, long timeout, string &rNackReason)
{
    zmq::message_t response;
    if(receiveWithTimeout(rSocket, timeout, response))
    {
        size_t offset=0;
        size_t id = getMessageId(response, offset);
        //cout << "id: " << id << endl;
        if (id == S_Ack)
        {
            return true;
        }
        else if (id == S_NAck)
        {
            rNackReason = unpackMessage<std::string>(response, offset);
        }
        else
        {
            rNackReason = "Got neither Ack nor Nack";
        }
    }
    else
    {
        rNackReason = "Got either timeout or exception in zmq::recv()";
    }
    return false;
}

bool readAckNackServerMessage(zmq::socket_t &rSocket, long timeout)
{
    string dummy;
    return readAckNackServerMessage(rSocket, timeout, dummy);
}

// ---------- Help functions end ----------

bool RemoteHopsanClient::connectToServer(std::string zmqaddres)
{
    if (serverConnected())
    {
        mLastErrorMessage = "You are already connected to a server";
        return false;
    }
    else
    {
        try
        {
            mRSCSocket.connect(zmqaddres.c_str());
            mServerAddress = zmqaddres;
            return true;
        }
        catch (zmq::error_t e)
        {
            mLastErrorMessage =  e.what();
            mServerAddress.clear();
            return false;
        }
    }
}

bool RemoteHopsanClient::connectToServer(string ip, string port)
{
    return connectToServer(makeZMQAddress(ip,port));
}

bool RemoteHopsanClient::serverConnected()
{
    // Note we can not use socket.connected() it only checks if underlying c-socket exist
    return !mServerAddress.empty();
}

bool RemoteHopsanClient::sendGetParamMessage(const string &rName, string &rValue)
{
    CM_GetParam_t msg {rName};
    sendClientMessage<CM_GetParam_t>(mRWCSocket, C_GetParam, msg);

    zmq::message_t response;
    if (receiveWithTimeout(mRWCSocket, response))
    {
        size_t offset=0;
        size_t id = getMessageId(response, offset);
        if (id == S_GetParam_Reply)
        {
            rValue = unpackMessage<string>(response, offset);
            assert(response.size() == offset);
            return true;
        }
        else
        {
            rValue.clear();
            return false;
        }
    }
    return false;
}

bool RemoteHopsanClient::sendSetParamMessage(const string &rName, const string &rValue)
{
    CM_SetParam_t msg {rName, rValue};
    sendClientMessage<CM_SetParam_t>(mRWCSocket, C_SetParam, msg);

    string err;
    bool rc = readAckNackServerMessage(mRWCSocket, mReceiveTimeout, err);
    if (!rc)
    {
        cout << err << endl;
    }
    return rc;
}

bool RemoteHopsanClient::sendModelMessage(const std::string &rModel)
{
    sendClientMessage<std::string>(mRWCSocket, C_SendingHmf, rModel);
    string err;
    bool rc = readAckNackServerMessage(mRWCSocket, mReceiveTimeout, err);
    if (!rc)
    {
        cout << err << endl;
    }
    return rc;
}

bool RemoteHopsanClient::sendSimulateMessage(const int nLogsamples, const int logStartTime,
                         const int simStarttime, const int simSteptime, const int simStoptime)
{
    CM_Simulate_t msg;// {nLogsamples, logStartTime, simStarttime, simSteptime, simStoptime};
    sendClientMessage<CM_Simulate_t>(mRWCSocket, C_Simulate, msg);
    string err;
    //! @todo blocking read for now, in the future we need to poll while simulating
    bool rc = readAckNackServerMessage(mRWCSocket, -1, err);
    if (!rc)
    {
        cout << err << endl;
    }
    return rc;
}

bool RemoteHopsanClient::requestStatus(ServerStatusT &rServerStatus)
{
    sendShortClientMessage(mRSCSocket, C_ReqStatus);

    zmq::message_t response;
    if (receiveWithTimeout(mRSCSocket, response))
    {
        //cout << "Response size: " << response.size() << endl;
        size_t offset=0;
        size_t id = getMessageId(response, offset);
        if (id == S_ReqStatus_Reply)
        {
            SM_ServerStatus_t status = unpackMessage<SM_ServerStatus_t>(response, offset);
            rServerStatus = status;
            //cout << "Got status reply" << endl;
            return true;
        }
    }
    return false;
}

bool RemoteHopsanClient::requestSimulationResults(vector<string> *pDataNames, vector<double> *pData)
{
    sendClientMessage<string>(mRWCSocket, C_ReqResults, "*"); // Request all

    zmq::message_t response;
    if (receiveWithTimeout(mRWCSocket, response))
    {
        cout << "Response size: " << response.size() << endl;
        size_t offset=0;
        size_t id = getMessageId(response, offset);
        if (id == S_ReqResults_Reply)
        {
            vector<SM_Variable_Description_t> vars = unpackMessage<vector<SM_Variable_Description_t>>(response,offset);
            cout << "Received: " << vars.size() << " vars" << endl;
            size_t nLogSamples;
            if (!vars.empty())
            {
                nLogSamples = vars[0].data.size();
            }

            pDataNames->reserve(vars.size());
            pData->reserve(nLogSamples*vars.size());

            for (auto &v : vars)
            {
                pDataNames->push_back(v.name);
                cout << v.name << " " << v.alias << " " << v.unit << " Data:";
                for (auto d : v.data)
                {
                    pData->push_back(d);
                    //cout << " " << d;
                }
                cout << endl;
            }

            return true;
        }
        else
        {
            mLastErrorMessage = "Got wrong reply";
        }
    }
    return false;
}

bool RemoteHopsanClient::requestSlot(size_t &rControlPort)
{
    sendShortClientMessage(mRSCSocket, C_ReqSlot);

    zmq::message_t response;
    if (receiveWithTimeout(mRSCSocket, response))
    {
        size_t offset=0;
        size_t id = getMessageId(response, offset);
        if (id == S_ReqSlot_Reply)
        {
            SM_ReqSlot_Reply_t msg = unpackMessage<SM_ReqSlot_Reply_t>(response, offset);
            rControlPort = msg.port;
            assert(response.size() == offset);
            return true;
        }
        else if (id == S_NAck)
        {
            mLastErrorMessage = unpackMessage<string>(response, offset);
        }
        else
        {
            mLastErrorMessage = "Got wrong reply type from server";
        }
    }
    return false;
}

bool RemoteHopsanClient::connectToWorker(std::string zmqaddres)
{
    if (workerConnected())
    {
        mLastErrorMessage = "You are already connected to a worker";
        return false;
    }
    else
    {
        try
        {
            mRWCSocket.connect(zmqaddres.c_str());
            mWorkerAddress = zmqaddres;
            return true;
        }
        catch (zmq::error_t e)
        {
            mLastErrorMessage =  e.what();
            mWorkerAddress.clear();
            return false;
        }
    }
}

bool RemoteHopsanClient::connectToWorker(string ip, string port)
{
    return connectToWorker(makeZMQAddress(ip,port));
}

bool RemoteHopsanClient::workerConnected()
{
    // Note we can not use socket.connected() it only checks if underlying c-socket exist
    return !mWorkerAddress.empty();
}

void RemoteHopsanClient::disconnect()
{
    // Disconnect from Worker
    if (workerConnected())
    {
        sendShortClientMessage(mRWCSocket, C_Bye);
        readAckNackServerMessage(mRWCSocket, 1000); //But we do not care about result
        mRWCSocket.disconnect(mWorkerAddress.c_str());
        mWorkerAddress.clear();
    }

    // Disconnect from Server
    if (serverConnected())
    {
        //! @todo maybe should auto disconnect when we connect to worker
        mRSCSocket.disconnect(mServerAddress.c_str());
        mServerAddress.clear();
    }
}

bool RemoteHopsanClient::requestMessages()
{
    sendShortClientMessage(mRWCSocket, C_ReqMessages);

    zmq::message_t response;
    if (receiveWithTimeout(mRWCSocket, response))
    {
        size_t offset=0;
        size_t id = getMessageId(response, offset);
        if (id == S_ReqMessages_Reply)
        {
            vector<SM_HopsanCoreMessage_t> messages = unpackMessage<vector<SM_HopsanCoreMessage_t>>(response, offset);
            cout << "Received: " << messages.size() << " messages from server" << endl;
            for (size_t m=0; m<messages.size(); ++m)
            {
                cout << messages[m].type << " " << messages[m].tag << " " << messages[m].message << endl;
            }
            return true;
        }
        else
        {
            mLastErrorMessage = "Got wrong reply";
        }
    }
    return false;
}

bool RemoteHopsanClient::requestMessages(std::vector<char> &rTypes, std::vector<string> &rTags, std::vector<string> &rMessages)
{
    sendShortClientMessage(mRWCSocket, C_ReqMessages);

    zmq::message_t response;
    if (receiveWithTimeout(mRWCSocket, response))
    {
        size_t offset=0;
        size_t id = getMessageId(response, offset);
        if (id == S_ReqMessages_Reply)
        {
            vector<SM_HopsanCoreMessage_t> messages = unpackMessage<vector<SM_HopsanCoreMessage_t>>(response, offset);
            //cout << "Received: " << messages.size() << " messages from server" << endl;
            rTypes.resize(messages.size());
            rTags.resize(messages.size());
            rMessages.resize(messages.size());
            for (size_t m=0; m<messages.size(); ++m)
            {
                rTypes[m] =  messages[m].type;
                rTags[m] = messages[m].tag;
                rMessages[m] = messages[m].message;
            }
            return true;
        }
        else
        {
            mLastErrorMessage = "Got wrong reply";
        }
    }
    return false;
}

bool RemoteHopsanClient::requestServerMachines(int nMachines, double maxBenchmarkTime, std::vector<string> &rIps, std::vector<string> &rPorts)
{
    CM_ReqServerMachines_t req;
    req.numMachines = nMachines;
    req.maxBenchmarkTime = maxBenchmarkTime;
    req.numThreads = -1;

    sendClientMessage<CM_ReqServerMachines_t>(mRSCSocket, C_ReqServerMachines, req);

    zmq::message_t response;
    if (receiveWithTimeout(mRSCSocket, response))
    {
        cout << "Response size: " << response.size() << endl;
        size_t offset=0;
        size_t id = getMessageId(response, offset);
        if (id == S_ReqServerMachines_Reply)
        {
            MSM_ReqServerMachines_Reply_t repl = unpackMessage<MSM_ReqServerMachines_Reply_t>(response,offset);
            rIps = repl.ips;
            rPorts = repl.ports;
            return true;
        }
        else
        {
            mLastErrorMessage = "Got wrong reply";
        }
    }
    return false;
}

string RemoteHopsanClient::getLastErrorMessage() const
{
    return mLastErrorMessage;
}

bool RemoteHopsanClient::receiveWithTimeout(zmq::socket_t &rSocket, zmq::message_t &rMessage)
{
    // Create a poll item
    zmq::pollitem_t pollitems[] = {{ rSocket, 0, ZMQ_POLLIN, 0 }};
    try
    {
        // Poll socket for a reply, with timeout
        zmq::poll(&pollitems[0], 1,  mReceiveTimeout);
        // If we have received a message then read message and return true
        if (pollitems[0].revents & ZMQ_POLLIN)
        {
            rSocket.recv(&rMessage);
            return true;
        }
        // Else we reached timeout, return false
        else
        {
            mLastErrorMessage = "Timeout in receive";
        }
    }
    catch(zmq::error_t e)
    {
        mLastErrorMessage = e.what();
    }
    return false;
}

RemoteHopsanClient::RemoteHopsanClient(zmq::context_t &rContext) :
    mRSCSocket(rContext, ZMQ_REQ), mRWCSocket(rContext, ZMQ_REQ)
{
    int linger_ms = 1000;
    mRSCSocket.setsockopt(ZMQ_LINGER, &linger_ms, sizeof(int));
    mRWCSocket.setsockopt(ZMQ_LINGER, &linger_ms, sizeof(int));
}

void RemoteHopsanClient::setReceiveTimeout(long ms)
{
    mReceiveTimeout = ms;
}

long RemoteHopsanClient::getReceiveTimeout() const
{
    return mReceiveTimeout;
}
<|endoftext|>