<commit_before>//===- FuzzerMutate.cpp - Mutate a test input -----------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// Mutate a test input.
//===----------------------------------------------------------------------===//

#include <cstring>

#include "FuzzerInternal.h"

#include <algorithm>

namespace fuzzer {

typedef size_t (MutationDispatcher::*Mutator)(uint8_t *Data, size_t Size,
                                              size_t Max);

struct MutationDispatcher::Impl {
  std::vector<Unit> Dictionary;
  std::vector<Mutator> Mutators;
  Impl() {
    Mutators.push_back(&MutationDispatcher::Mutate_EraseByte);
    Mutators.push_back(&MutationDispatcher::Mutate_InsertByte);
    Mutators.push_back(&MutationDispatcher::Mutate_ChangeByte);
    Mutators.push_back(&MutationDispatcher::Mutate_ChangeBit);
    Mutators.push_back(&MutationDispatcher::Mutate_ShuffleBytes);
    Mutators.push_back(&MutationDispatcher::Mutate_ChangeASCIIInteger);
  }
  void AddWordToDictionary(const uint8_t *Word, size_t Size) {
    if (Dictionary.empty()) {
      Mutators.push_back(&MutationDispatcher::Mutate_AddWordFromDictionary);
    }
    Dictionary.push_back(Unit(Word, Word + Size));
  }
};

static char FlipRandomBit(char X, FuzzerRandomBase &Rand) {
  int Bit = Rand(8);
  char Mask = 1 << Bit;
  char R;
  if (X & (1 << Bit))
    R = X & ~Mask;
  else
    R = X | Mask;
  assert(R != X);
  return R;
}

static char RandCh(FuzzerRandomBase &Rand) {
  if (Rand.RandBool()) return Rand(256);
  const char *Special = "!*'();:@&=+$,/?%#[]123ABCxyz-`~.";
  return Special[Rand(sizeof(Special) - 1)];
}

size_t MutationDispatcher::Mutate_ShuffleBytes(uint8_t *Data, size_t Size,
                                               size_t MaxSize) {
  assert(Size);
  size_t ShuffleAmount = Rand(std::min(Size, 8UL)) + 1;  // [1,8] and <= Size.
  size_t ShuffleStart = Rand(Size - ShuffleAmount);
  assert(ShuffleStart + ShuffleAmount <= Size);
  std::random_shuffle(Data + ShuffleStart, Data + ShuffleStart + ShuffleAmount,
                      Rand);
  return Size;
}

size_t MutationDispatcher::Mutate_EraseByte(uint8_t *Data, size_t Size,
                                            size_t MaxSize) {
  assert(Size);
  if (Size == 1) return 0;
  size_t Idx = Rand(Size);
  // Erase Data[Idx].
  memmove(Data + Idx, Data + Idx + 1, Size - Idx - 1);
  return Size - 1;
}

size_t MutationDispatcher::Mutate_InsertByte(uint8_t *Data, size_t Size,
                                             size_t MaxSize) {
  if (Size == MaxSize) return 0;
  size_t Idx = Rand(Size + 1);
  // Insert new value at Data[Idx].
  memmove(Data + Idx + 1, Data + Idx, Size - Idx);
  Data[Idx] = RandCh(Rand);
  return Size + 1;
}

size_t MutationDispatcher::Mutate_ChangeByte(uint8_t *Data, size_t Size,
                                             size_t MaxSize) {
  size_t Idx = Rand(Size);
  Data[Idx] = RandCh(Rand);
  return Size;
}

size_t MutationDispatcher::Mutate_ChangeBit(uint8_t *Data, size_t Size,
                                            size_t MaxSize) {
  size_t Idx = Rand(Size);
  Data[Idx] = FlipRandomBit(Data[Idx], Rand);
  return Size;
}

size_t MutationDispatcher::Mutate_AddWordFromDictionary(uint8_t *Data,
                                                        size_t Size,
                                                        size_t MaxSize) {
  auto &D = MDImpl->Dictionary;
  assert(!D.empty());
  if (D.empty()) return 0;
  const Unit &Word = D[Rand(D.size())];
  if (Size + Word.size() > MaxSize) return 0;
  size_t Idx = Rand(Size + 1);
  memmove(Data + Idx + Word.size(), Data + Idx, Size - Idx);
  memcpy(Data + Idx, Word.data(), Word.size());
  return Size + Word.size();
}

size_t MutationDispatcher::Mutate_ChangeASCIIInteger(uint8_t *Data, size_t Size,
                                                     size_t MaxSize) {
  size_t B = Rand(Size);
  while (B < Size && !isdigit(Data[B])) B++;
  if (B == Size) return 0;
  size_t E = B;
  while (E < Size && isdigit(Data[E])) E++;
  assert(B < E);
  // now we have digits in [B, E).
  // strtol and friends don't accept non-zero-teminated data, parse it manually.
  uint64_t Val = Data[B] - '0';
  for (size_t i = B + 1; i < E; i++)
    Val = Val * 10 + Data[i] - '0';

  // Mutate the integer value.
  switch(Rand(5)) {
    case 0: Val++; break;
    case 1: Val--; break;
    case 2: Val /= 2; break;
    case 3: Val *= 2; break;
    case 4: Val = Rand(Val * Val); break;
    default: assert(0);
  }
  // Just replace the bytes with the new ones, don't bother moving bytes.
  for (size_t i = B; i < E; i++) {
    size_t Idx = E + B - i - 1;
    assert(Idx >= B && Idx < E);
    Data[Idx] = (Val % 10) + '0';
    Val /= 10;
  }
  return Size;
}

// Mutates Data in place, returns new size.
size_t MutationDispatcher::Mutate(uint8_t *Data, size_t Size, size_t MaxSize) {
  assert(MaxSize > 0);
  assert(Size <= MaxSize);
  if (Size == 0) {
    for (size_t i = 0; i < MaxSize; i++)
      Data[i] = RandCh(Rand);
    return MaxSize;
  }
  assert(Size > 0);
  // Some mutations may fail (e.g. can't insert more bytes if Size == MaxSize),
  // in which case they will return 0.
  // Try several times before returning un-mutated data.
  for (int Iter = 0; Iter < 10; Iter++) {
    size_t MutatorIdx = Rand(MDImpl->Mutators.size());
    size_t NewSize =
        (this->*(MDImpl->Mutators[MutatorIdx]))(Data, Size, MaxSize);
    if (NewSize) return NewSize;
  }
  return Size;
}

void MutationDispatcher::AddWordToDictionary(const uint8_t *Word, size_t Size) {
  MDImpl->AddWordToDictionary(Word, Size);
}

MutationDispatcher::MutationDispatcher(FuzzerRandomBase &Rand) : Rand(Rand) {
  MDImpl = new Impl;
}

MutationDispatcher::~MutationDispatcher() { delete MDImpl; }

}  // namespace fuzzer
<commit_msg>[libFuzzer] fix 32-bit build<commit_after>//===- FuzzerMutate.cpp - Mutate a test input -----------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// Mutate a test input.
//===----------------------------------------------------------------------===//

#include <cstring>

#include "FuzzerInternal.h"

#include <algorithm>

namespace fuzzer {

typedef size_t (MutationDispatcher::*Mutator)(uint8_t *Data, size_t Size,
                                              size_t Max);

struct MutationDispatcher::Impl {
  std::vector<Unit> Dictionary;
  std::vector<Mutator> Mutators;
  Impl() {
    Mutators.push_back(&MutationDispatcher::Mutate_EraseByte);
    Mutators.push_back(&MutationDispatcher::Mutate_InsertByte);
    Mutators.push_back(&MutationDispatcher::Mutate_ChangeByte);
    Mutators.push_back(&MutationDispatcher::Mutate_ChangeBit);
    Mutators.push_back(&MutationDispatcher::Mutate_ShuffleBytes);
    Mutators.push_back(&MutationDispatcher::Mutate_ChangeASCIIInteger);
  }
  void AddWordToDictionary(const uint8_t *Word, size_t Size) {
    if (Dictionary.empty()) {
      Mutators.push_back(&MutationDispatcher::Mutate_AddWordFromDictionary);
    }
    Dictionary.push_back(Unit(Word, Word + Size));
  }
};

static char FlipRandomBit(char X, FuzzerRandomBase &Rand) {
  int Bit = Rand(8);
  char Mask = 1 << Bit;
  char R;
  if (X & (1 << Bit))
    R = X & ~Mask;
  else
    R = X | Mask;
  assert(R != X);
  return R;
}

static char RandCh(FuzzerRandomBase &Rand) {
  if (Rand.RandBool()) return Rand(256);
  const char *Special = "!*'();:@&=+$,/?%#[]123ABCxyz-`~.";
  return Special[Rand(sizeof(Special) - 1)];
}

size_t MutationDispatcher::Mutate_ShuffleBytes(uint8_t *Data, size_t Size,
                                               size_t MaxSize) {
  assert(Size);
  size_t ShuffleAmount = Rand(std::min(Size, (size_t)8)) + 1;  // [1,8] and <= Size.
  size_t ShuffleStart = Rand(Size - ShuffleAmount);
  assert(ShuffleStart + ShuffleAmount <= Size);
  std::random_shuffle(Data + ShuffleStart, Data + ShuffleStart + ShuffleAmount,
                      Rand);
  return Size;
}

size_t MutationDispatcher::Mutate_EraseByte(uint8_t *Data, size_t Size,
                                            size_t MaxSize) {
  assert(Size);
  if (Size == 1) return 0;
  size_t Idx = Rand(Size);
  // Erase Data[Idx].
  memmove(Data + Idx, Data + Idx + 1, Size - Idx - 1);
  return Size - 1;
}

size_t MutationDispatcher::Mutate_InsertByte(uint8_t *Data, size_t Size,
                                             size_t MaxSize) {
  if (Size == MaxSize) return 0;
  size_t Idx = Rand(Size + 1);
  // Insert new value at Data[Idx].
  memmove(Data + Idx + 1, Data + Idx, Size - Idx);
  Data[Idx] = RandCh(Rand);
  return Size + 1;
}

size_t MutationDispatcher::Mutate_ChangeByte(uint8_t *Data, size_t Size,
                                             size_t MaxSize) {
  size_t Idx = Rand(Size);
  Data[Idx] = RandCh(Rand);
  return Size;
}

size_t MutationDispatcher::Mutate_ChangeBit(uint8_t *Data, size_t Size,
                                            size_t MaxSize) {
  size_t Idx = Rand(Size);
  Data[Idx] = FlipRandomBit(Data[Idx], Rand);
  return Size;
}

size_t MutationDispatcher::Mutate_AddWordFromDictionary(uint8_t *Data,
                                                        size_t Size,
                                                        size_t MaxSize) {
  auto &D = MDImpl->Dictionary;
  assert(!D.empty());
  if (D.empty()) return 0;
  const Unit &Word = D[Rand(D.size())];
  if (Size + Word.size() > MaxSize) return 0;
  size_t Idx = Rand(Size + 1);
  memmove(Data + Idx + Word.size(), Data + Idx, Size - Idx);
  memcpy(Data + Idx, Word.data(), Word.size());
  return Size + Word.size();
}

size_t MutationDispatcher::Mutate_ChangeASCIIInteger(uint8_t *Data, size_t Size,
                                                     size_t MaxSize) {
  size_t B = Rand(Size);
  while (B < Size && !isdigit(Data[B])) B++;
  if (B == Size) return 0;
  size_t E = B;
  while (E < Size && isdigit(Data[E])) E++;
  assert(B < E);
  // now we have digits in [B, E).
  // strtol and friends don't accept non-zero-teminated data, parse it manually.
  uint64_t Val = Data[B] - '0';
  for (size_t i = B + 1; i < E; i++)
    Val = Val * 10 + Data[i] - '0';

  // Mutate the integer value.
  switch(Rand(5)) {
    case 0: Val++; break;
    case 1: Val--; break;
    case 2: Val /= 2; break;
    case 3: Val *= 2; break;
    case 4: Val = Rand(Val * Val); break;
    default: assert(0);
  }
  // Just replace the bytes with the new ones, don't bother moving bytes.
  for (size_t i = B; i < E; i++) {
    size_t Idx = E + B - i - 1;
    assert(Idx >= B && Idx < E);
    Data[Idx] = (Val % 10) + '0';
    Val /= 10;
  }
  return Size;
}

// Mutates Data in place, returns new size.
size_t MutationDispatcher::Mutate(uint8_t *Data, size_t Size, size_t MaxSize) {
  assert(MaxSize > 0);
  assert(Size <= MaxSize);
  if (Size == 0) {
    for (size_t i = 0; i < MaxSize; i++)
      Data[i] = RandCh(Rand);
    return MaxSize;
  }
  assert(Size > 0);
  // Some mutations may fail (e.g. can't insert more bytes if Size == MaxSize),
  // in which case they will return 0.
  // Try several times before returning un-mutated data.
  for (int Iter = 0; Iter < 10; Iter++) {
    size_t MutatorIdx = Rand(MDImpl->Mutators.size());
    size_t NewSize =
        (this->*(MDImpl->Mutators[MutatorIdx]))(Data, Size, MaxSize);
    if (NewSize) return NewSize;
  }
  return Size;
}

void MutationDispatcher::AddWordToDictionary(const uint8_t *Word, size_t Size) {
  MDImpl->AddWordToDictionary(Word, Size);
}

MutationDispatcher::MutationDispatcher(FuzzerRandomBase &Rand) : Rand(Rand) {
  MDImpl = new Impl;
}

MutationDispatcher::~MutationDispatcher() { delete MDImpl; }

}  // namespace fuzzer
<|endoftext|>


<commit_before>/*
   Copyright 2013 The Trustees of Princeton University
   All Rights Reserved
*/

#include "AG-disk.h"

// server config
struct md_syndicate_conf CONF;

// set of files we're exposing
content_map DATA;

// Metadata service client of the AG
ms_client *mc = NULL;

// Location of local files we're exposing
char *datapath = NULL;

// Length of datapath varaiable
size_t  datapath_len = 0;

// publish_func exit code
int pfunc_exit_code = 0;

// generate a manifest for an existing file, putting it into the gateway context
int gateway_generate_manifest( struct gateway_context* replica_ctx, struct gateway_ctx* ctx, struct md_entry* ent ) {
   errorf("%s", "INFO: gateway_generate_manifest\n");
   // populate a manifest
   Serialization::ManifestMsg* mmsg = new Serialization::ManifestMsg();
   mmsg->set_size( ent->size );
   mmsg->set_file_version( 1 );
   mmsg->set_mtime_sec( ent->mtime_sec );
   mmsg->set_mtime_nsec( 0 );
   mmsg->set_manifest_mtime_sec( ent->mtime_sec );
   mmsg->set_manifest_mtime_nsec( 0 );

   uint64_t num_blocks = ent->size / CONF.blocking_factor;
   if( ent->size % CONF.blocking_factor != 0 )
      num_blocks++;

   Serialization::BlockURLSetMsg *bbmsg = mmsg->add_block_url_set();
   bbmsg->set_start_id( 0 );
   bbmsg->set_end_id( num_blocks );
   bbmsg->set_file_url( string(ent->url) );

   for( uint64_t i = 0; i < num_blocks; i++ ) {
      bbmsg->add_block_versions( 0 );
   }

   // serialize
   string mmsg_str;
   bool src = mmsg->SerializeToString( &mmsg_str );
   if( !src ) {
      // failed
      errorf( "%s", "failed to serialize" );
      delete mmsg;
      return -EINVAL;
   }

   ctx->data_len = mmsg_str.size();
   ctx->data = CALLOC_LIST( char, mmsg_str.size() );
   replica_ctx->last_mod = ent->mtime_sec;
   memcpy( ctx->data, mmsg_str.data(), mmsg_str.size() );

   delete mmsg;

   return 0;
}

// read dataset or manifest
ssize_t get_dataset( struct gateway_context* dat, char* buf, size_t len, void* user_cls ) {
   errorf("%s", "INFO: get_dataset\n");
   ssize_t ret = 0;
   struct gateway_ctx* ctx = (struct gateway_ctx*)user_cls;

   if( ctx->request_type == GATEWAY_REQUEST_TYPE_LOCAL_FILE ) {
      // read from disk
      ssize_t nr = 0;
      size_t num_read = 0;
      while( num_read < len ) {
         nr = read( ctx->fd, buf + num_read, len - num_read );
         if( nr == 0 ) {
            // EOF
            break;
         }
         if( nr < 0 ) {
            // error
            int errsv = -errno;
            errorf( "read(%d) errno = %d\n", ctx->fd, errsv );
            ret = errsv;
         }
         num_read += nr;
      }

      if( ret == 0 )
         ret = num_read;
   }
   else if( ctx->request_type == GATEWAY_REQUEST_TYPE_MANIFEST ) {
      // read from RAM
      memcpy( buf, ctx->data + ctx->data_offset, MIN( len, ctx->data_len - ctx->data_offset ) );
      ctx->data_offset += len;
      ret = (ssize_t)len;
   }
   else {
      // invalid structure
      ret = -EINVAL;
   }

   return ret;
}

// get metadata for a dataset
int metadata_dataset( struct gateway_context* dat, ms::ms_gateway_blockinfo* info, void* usercls ) {
   errorf("%s","INFO: metadata_dataset\n");
   content_map::iterator itr = DATA.find( string(dat->url_path) );
   if( itr == DATA.end() ) {
      // not here
      return -ENOENT;
   }

   struct gateway_ctx* ctx = (struct gateway_ctx*)usercls;
   struct md_entry* ent = itr->second;

   info->set_progress( ms::ms_gateway_blockinfo::COMMITTED );     // ignored, but needs to be filled in
   info->set_blocking_factor( CONF.blocking_factor );

   info->set_file_version( 1 );
   info->set_block_id( ctx->block_id );
   info->set_block_version( 1 );
   info->set_fs_path( string(ctx->file_path) );
   info->set_file_mtime_sec( ent->mtime_sec );
   info->set_file_mtime_nsec( ent->mtime_nsec );
   info->set_write_time( ent->mtime_sec );

   return 0;
}

// interpret an inbound GET request
void* connect_dataset( struct gateway_context* replica_ctx ) {

   errorf("%s", "INFO: connect_dataset\n");
   // is this a request for a file block, or a manifest?
   char* file_path = NULL;
   int64_t file_version = 0;
   uint64_t block_id = 0;
   int64_t block_version = 0;
   struct timespec manifest_timestamp;
   manifest_timestamp.tv_sec = 0;
   manifest_timestamp.tv_nsec = 0;
   bool staging = false;

   int rc = md_HTTP_parse_url_path( (char*)replica_ctx->url_path, &file_path, &file_version, &block_id, &block_version, &manifest_timestamp, &staging );
   if( rc != 0 ) {
      errorf( "failed to parse '%s', rc = %d\n", replica_ctx->url_path, rc );
      free( file_path );
      return NULL;
   }

   if( staging ) {
      errorf("invalid URL path %s\n", replica_ctx->url_path );
      free( file_path );
      return NULL;
   }

   struct gateway_ctx* ctx = CALLOC_LIST( struct gateway_ctx, 1 );

   // is there metadata for this file?
   string fs_path( file_path );
   content_map::iterator itr = DATA.find( fs_path );
   if( itr == DATA.end() ) {
      // no entry; nothing to do
      free( file_path );
      return NULL;
   }

   struct md_entry* ent = DATA[ file_path ];

   // is this a request for a manifest?
   if( manifest_timestamp.tv_sec > 0 ) {
      // request for a manifest
      int rc = gateway_generate_manifest( replica_ctx, ctx, ent );
      if( rc != 0 ) {
         // failed
         errorf( "gateway_generate_manifest rc = %d\n", rc );

         // meaningful error code
         if( rc == -ENOENT )
            replica_ctx->err = -404;
         else if( rc == -EACCES )
            replica_ctx->err = -403;
         else
            replica_ctx->err = -500;

         free( ctx );
         free( file_path );

         return NULL;
      }

      ctx->request_type = GATEWAY_REQUEST_TYPE_MANIFEST;
      ctx->data_offset = 0;
      ctx->block_id = 0;
      ctx->num_read = 0;
      replica_ctx->size = ctx->data_len;
   }
   else {

      // request for local file
      char* fp = md_fullpath( CONF.data_root, GET_PATH( ent->url ), NULL );
      ctx->fd = open( fp, O_RDONLY );
      if( ctx->fd < 0 ) {
         rc = -errno;
         errorf( "open(%s) errno = %d\n", fp, rc );
         free( fp );
         free( ctx );
         free( file_path );
         return NULL;
      }
      else {
         free( fp );

         // set up for reading
         off_t offset = CONF.blocking_factor * block_id;
         rc = lseek( ctx->fd, offset, SEEK_SET );
         if( rc != 0 ) {
            rc = -errno;
            errorf( "lseek errno = %d\n", rc );

            free( ctx );
            free( file_path );
            return NULL;
         }
      }

      ctx->num_read = 0;
      ctx->block_id = block_id;
      ctx->request_type = GATEWAY_REQUEST_TYPE_LOCAL_FILE;
      replica_ctx->size = CONF.blocking_factor;
   }

   ctx->file_path = file_path;
   return ctx;
}

// clean up a transfer
void cleanup_dataset( void* cls ) {

   errorf("%s", "INFO: cleanup_dataset\n");
   struct gateway_ctx* ctx = (struct gateway_ctx*)cls;
   if (ctx) {
      close( ctx->fd );
      if( ctx->data )
        free( ctx->data );

      ctx->data = NULL;
      ctx->file_path = NULL;

      free( ctx );
   }
}

int publish_func (struct gateway_context*, ms_client *client,
	char* dataset ) {
    int flags = FTW_PHYS;
    mc = client;
    datapath = dataset;
    datapath_len = strlen(datapath);
    if ( datapath[datapath_len - 1] == '/')
	   datapath_len--;
    if (nftw(dataset, publish, 20, flags) == -1) {
	return pfunc_exit_code;
    }
    ms_client_destroy(mc);
    return 0;
}

static int publish(const char *fpath, const struct stat *sb,
	int tflag, struct FTW *ftwbuf)
{
    int i = 0;
    struct md_entry* ment = new struct md_entry;
    size_t len = strlen(fpath);
    if ( len < datapath_len ) {
	pfunc_exit_code = -EINVAL;
	return -EINVAL;
    }
    if ( len == datapath_len ) {
	pfunc_exit_code = 0;
	return 0;
    }
    size_t path_len = ( len - datapath_len ) + 1;
    ment->path = (char*)malloc( path_len );
    memset(ment->path, 0, path_len);
    strncpy(ment->path, fpath + datapath_len, path_len);
    ment->url = mc->conf->content_url;
    ment->url_replicas = mc->conf->replica_urls;
    ment->local_path = NULL;
    ment->ctime_sec = sb->st_ctime;
    ment->ctime_nsec = 0;
    ment->mtime_sec = sb->st_mtime;
    ment->mtime_nsec = 0;
    ment->mode = sb->st_mode;
    ment->version = 1;
    ment->max_read_freshness = 360000;
    ment->max_write_freshness = 1;
    ment->volume = mc->conf->volume;
    ment->size = sb->st_size;
    ment->owner = mc->conf->volume_owner;
    switch (tflag) {
	case FTW_D:
	    cout<<"Dir: "<<fpath<<endl;
	    ment->type = MD_ENTRY_DIR;
	    if ( (i = ms_client_mkdir(mc, ment)) < 0 ) {
		cout<<"ms client mkdir "<<i<<endl;
	    }
	    break;
	case FTW_F:
	    cout<<"File: "<<fpath<<endl;
	    ment->type = MD_ENTRY_FILE;
	    if ( (i = ms_client_create(mc, ment)) < 0 ) {
		cout<<"ms client mkdir "<<i<<endl;
	    }
	    break;
	case FTW_SL:
	    cout<<"Symlink: "<<fpath<<endl;
	    break;
	case FTW_DP:
	    cout<<"DP: "<<fpath<<endl;
	    break;
	case FTW_DNR:
	    cout<<"No permissions: "<<fpath<<endl;
	    break;
	default:
	    cout<<"Default "<<fpath<<endl;
    }
    delete ment;
    pfunc_exit_code = 0;
    return 0;
}

int main( int argc, char** argv ) {

   gateway_get_func( get_dataset );
   gateway_connect_func( connect_dataset );
   gateway_cleanup_func( cleanup_dataset );
   gateway_metadata_func( metadata_dataset );
   gateway_publish_func( publish_func );

   int rc = AG_main( argc, argv );

   return rc;
}
<commit_msg>Removed some unwanted cout<commit_after>/*
   Copyright 2013 The Trustees of Princeton University
   All Rights Reserved
*/

#include "AG-disk.h"

// server config
struct md_syndicate_conf CONF;

// set of files we're exposing
content_map DATA;

// Metadata service client of the AG
ms_client *mc = NULL;

// Location of local files we're exposing
char *datapath = NULL;

// Length of datapath varaiable
size_t  datapath_len = 0;

// publish_func exit code
int pfunc_exit_code = 0;

// generate a manifest for an existing file, putting it into the gateway context
int gateway_generate_manifest( struct gateway_context* replica_ctx, struct gateway_ctx* ctx, struct md_entry* ent ) {
   errorf("%s", "INFO: gateway_generate_manifest\n");
   // populate a manifest
   Serialization::ManifestMsg* mmsg = new Serialization::ManifestMsg();
   mmsg->set_size( ent->size );
   mmsg->set_file_version( 1 );
   mmsg->set_mtime_sec( ent->mtime_sec );
   mmsg->set_mtime_nsec( 0 );
   mmsg->set_manifest_mtime_sec( ent->mtime_sec );
   mmsg->set_manifest_mtime_nsec( 0 );

   uint64_t num_blocks = ent->size / CONF.blocking_factor;
   if( ent->size % CONF.blocking_factor != 0 )
      num_blocks++;

   Serialization::BlockURLSetMsg *bbmsg = mmsg->add_block_url_set();
   bbmsg->set_start_id( 0 );
   bbmsg->set_end_id( num_blocks );
   bbmsg->set_file_url( string(ent->url) );

   for( uint64_t i = 0; i < num_blocks; i++ ) {
      bbmsg->add_block_versions( 0 );
   }

   // serialize
   string mmsg_str;
   bool src = mmsg->SerializeToString( &mmsg_str );
   if( !src ) {
      // failed
      errorf( "%s", "failed to serialize" );
      delete mmsg;
      return -EINVAL;
   }

   ctx->data_len = mmsg_str.size();
   ctx->data = CALLOC_LIST( char, mmsg_str.size() );
   replica_ctx->last_mod = ent->mtime_sec;
   memcpy( ctx->data, mmsg_str.data(), mmsg_str.size() );

   delete mmsg;

   return 0;
}

// read dataset or manifest
ssize_t get_dataset( struct gateway_context* dat, char* buf, size_t len, void* user_cls ) {
   errorf("%s", "INFO: get_dataset\n");
   ssize_t ret = 0;
   struct gateway_ctx* ctx = (struct gateway_ctx*)user_cls;

   if( ctx->request_type == GATEWAY_REQUEST_TYPE_LOCAL_FILE ) {
      // read from disk
      ssize_t nr = 0;
      size_t num_read = 0;
      while( num_read < len ) {
         nr = read( ctx->fd, buf + num_read, len - num_read );
         if( nr == 0 ) {
            // EOF
            break;
         }
         if( nr < 0 ) {
            // error
            int errsv = -errno;
            errorf( "read(%d) errno = %d\n", ctx->fd, errsv );
            ret = errsv;
         }
         num_read += nr;
      }

      if( ret == 0 )
         ret = num_read;
   }
   else if( ctx->request_type == GATEWAY_REQUEST_TYPE_MANIFEST ) {
      // read from RAM
      memcpy( buf, ctx->data + ctx->data_offset, MIN( len, ctx->data_len - ctx->data_offset ) );
      ctx->data_offset += len;
      ret = (ssize_t)len;
   }
   else {
      // invalid structure
      ret = -EINVAL;
   }

   return ret;
}

// get metadata for a dataset
int metadata_dataset( struct gateway_context* dat, ms::ms_gateway_blockinfo* info, void* usercls ) {
   errorf("%s","INFO: metadata_dataset\n");
   content_map::iterator itr = DATA.find( string(dat->url_path) );
   if( itr == DATA.end() ) {
      // not here
      return -ENOENT;
   }

   struct gateway_ctx* ctx = (struct gateway_ctx*)usercls;
   struct md_entry* ent = itr->second;

   info->set_progress( ms::ms_gateway_blockinfo::COMMITTED );     // ignored, but needs to be filled in
   info->set_blocking_factor( CONF.blocking_factor );

   info->set_file_version( 1 );
   info->set_block_id( ctx->block_id );
   info->set_block_version( 1 );
   info->set_fs_path( string(ctx->file_path) );
   info->set_file_mtime_sec( ent->mtime_sec );
   info->set_file_mtime_nsec( ent->mtime_nsec );
   info->set_write_time( ent->mtime_sec );

   return 0;
}

// interpret an inbound GET request
void* connect_dataset( struct gateway_context* replica_ctx ) {

   errorf("%s", "INFO: connect_dataset\n");
   // is this a request for a file block, or a manifest?
   char* file_path = NULL;
   int64_t file_version = 0;
   uint64_t block_id = 0;
   int64_t block_version = 0;
   struct timespec manifest_timestamp;
   manifest_timestamp.tv_sec = 0;
   manifest_timestamp.tv_nsec = 0;
   bool staging = false;

   int rc = md_HTTP_parse_url_path( (char*)replica_ctx->url_path, &file_path, &file_version, &block_id, &block_version, &manifest_timestamp, &staging );
   if( rc != 0 ) {
      errorf( "failed to parse '%s', rc = %d\n", replica_ctx->url_path, rc );
      free( file_path );
      return NULL;
   }

   if( staging ) {
      errorf("invalid URL path %s\n", replica_ctx->url_path );
      free( file_path );
      return NULL;
   }

   struct gateway_ctx* ctx = CALLOC_LIST( struct gateway_ctx, 1 );

   // is there metadata for this file?
   string fs_path( file_path );
   content_map::iterator itr = DATA.find( fs_path );
   if( itr == DATA.end() ) {
      // no entry; nothing to do
      free( file_path );
      return NULL;
   }

   struct md_entry* ent = DATA[ file_path ];

   // is this a request for a manifest?
   if( manifest_timestamp.tv_sec > 0 ) {
      // request for a manifest
      int rc = gateway_generate_manifest( replica_ctx, ctx, ent );
      if( rc != 0 ) {
         // failed
         errorf( "gateway_generate_manifest rc = %d\n", rc );

         // meaningful error code
         if( rc == -ENOENT )
            replica_ctx->err = -404;
         else if( rc == -EACCES )
            replica_ctx->err = -403;
         else
            replica_ctx->err = -500;

         free( ctx );
         free( file_path );

         return NULL;
      }

      ctx->request_type = GATEWAY_REQUEST_TYPE_MANIFEST;
      ctx->data_offset = 0;
      ctx->block_id = 0;
      ctx->num_read = 0;
      replica_ctx->size = ctx->data_len;
   }
   else {

      // request for local file
      char* fp = md_fullpath( CONF.data_root, GET_PATH( ent->url ), NULL );
      ctx->fd = open( fp, O_RDONLY );
      if( ctx->fd < 0 ) {
         rc = -errno;
         errorf( "open(%s) errno = %d\n", fp, rc );
         free( fp );
         free( ctx );
         free( file_path );
         return NULL;
      }
      else {
         free( fp );

         // set up for reading
         off_t offset = CONF.blocking_factor * block_id;
         rc = lseek( ctx->fd, offset, SEEK_SET );
         if( rc != 0 ) {
            rc = -errno;
            errorf( "lseek errno = %d\n", rc );

            free( ctx );
            free( file_path );
            return NULL;
         }
      }

      ctx->num_read = 0;
      ctx->block_id = block_id;
      ctx->request_type = GATEWAY_REQUEST_TYPE_LOCAL_FILE;
      replica_ctx->size = CONF.blocking_factor;
   }

   ctx->file_path = file_path;
   return ctx;
}

// clean up a transfer
void cleanup_dataset( void* cls ) {

   errorf("%s", "INFO: cleanup_dataset\n");
   struct gateway_ctx* ctx = (struct gateway_ctx*)cls;
   if (ctx) {
      close( ctx->fd );
      if( ctx->data )
        free( ctx->data );

      ctx->data = NULL;
      ctx->file_path = NULL;

      free( ctx );
   }
}

int publish_func (struct gateway_context*, ms_client *client,
	char* dataset ) {
    int flags = FTW_PHYS;
    mc = client;
    datapath = dataset;
    datapath_len = strlen(datapath);
    if ( datapath[datapath_len - 1] == '/')
	   datapath_len--;
    if (nftw(dataset, publish, 20, flags) == -1) {
	return pfunc_exit_code;
    }
    ms_client_destroy(mc);
    return 0;
}

static int publish(const char *fpath, const struct stat *sb,
	int tflag, struct FTW *ftwbuf)
{
    int i = 0;
    struct md_entry* ment = new struct md_entry;
    size_t len = strlen(fpath);
    if ( len < datapath_len ) {
	pfunc_exit_code = -EINVAL;
	return -EINVAL;
    }
    if ( len == datapath_len ) {
	pfunc_exit_code = 0;
	return 0;
    }
    size_t path_len = ( len - datapath_len ) + 1;
    ment->path = (char*)malloc( path_len );
    memset(ment->path, 0, path_len);
    strncpy(ment->path, fpath + datapath_len, path_len);
    ment->url = mc->conf->content_url;
    ment->url_replicas = mc->conf->replica_urls;
    ment->local_path = NULL;
    ment->ctime_sec = sb->st_ctime;
    ment->ctime_nsec = 0;
    ment->mtime_sec = sb->st_mtime;
    ment->mtime_nsec = 0;
    ment->mode = sb->st_mode;
    ment->version = 1;
    ment->max_read_freshness = 360000;
    ment->max_write_freshness = 1;
    ment->volume = mc->conf->volume;
    ment->size = sb->st_size;
    ment->owner = mc->conf->volume_owner;
    switch (tflag) {
	case FTW_D:
	    ment->type = MD_ENTRY_DIR;
	    if ( (i = ms_client_mkdir(mc, ment)) < 0 ) {
		cout<<"ms client mkdir "<<i<<endl;
	    }
	    break;
	case FTW_F:
	    ment->type = MD_ENTRY_FILE;
	    if ( (i = ms_client_create(mc, ment)) < 0 ) {
		cout<<"ms client mkdir "<<i<<endl;
	    }
	    break;
	case FTW_SL:
	    break;
	case FTW_DP:
	    break;
	case FTW_DNR:
	    break;
	default:
	    break;
    }
    delete ment;
    pfunc_exit_code = 0;
    return 0;
}

int main( int argc, char** argv ) {

   gateway_get_func( get_dataset );
   gateway_connect_func( connect_dataset );
   gateway_cleanup_func( cleanup_dataset );
   gateway_metadata_func( metadata_dataset );
   gateway_publish_func( publish_func );

   int rc = AG_main( argc, argv );

   return rc;
}
<|endoftext|>


<commit_before>/** My first Galois program -*- C++ -*-
 */
#include "Galois/Galois.h"
#include "Galois/Graph/Graph.h"
#include <boost/iterator/counting_iterator.hpp>
#include <iostream>
#include <string>

using namespace std;

//typedef Galois::Graph::FirstGraph<std::string,std::string,true> Graph;

typedef enum{pi,po,nd} node_type;

struct Node {
 string label_type;//a0,b0...
 node_type type;// pi,po,nd
 int fanins;
 bool fanout;
 int level;
 };

typedef Galois::Graph::FirstGraph<Node,int,true> Graph;

int main(int argc, char** argv) {

  /*
   * Subgraph 1 from Fig.2 in "DAG-Aware AIG Rewriting"
   *
   */
  Graph g;
  Node vn1, vn2, vn3, vn4, vn5, vn6, vn7, vn8;
  Graph::GraphNode n1, n2, n3, n4, n5, n6, n7, n8;

  /*
   * Label vertices
   */

  // primary inputs
  vn1.type = pi; vn2.type = pi; vn3.type = pi;
  vn1.level = 0; vn2.level = 0; vn3.level = 0;
  vn1.label_type = "a0"; vn2.label_type = "a1"; vn3.label_type = "a2";

  // intermediate nodes
  vn4.type = nd; vn5.type = nd; vn6.type = nd;
  vn4.level = 1; vn5.level = 1; vn6.level = 2;
  vn4.label_type = "n0"; vn5.label_type = "n1"; vn6.label_type = "n2";

  // primary output
  vn7.type = po; vn7.level = 3; vn7.label_type = "s0";

  /*
   * Create vertices
   */
  n1 = g.createNode(vn1);
  n2 = g.createNode(vn2);
  n3 = g.createNode(vn3);
  n4 = g.createNode(vn4);
  n5 = g.createNode(vn5);
  n6 = g.createNode(vn6);
  n7 = g.createNode(vn7);

  g.addNode(n1);
  g.addNode(n2);
  g.addNode(n3);
  g.addNode(n4);
  g.addNode(n5);
  g.addNode(n6);
  g.addNode(n7);

  /*
   * Create edges
   */
  g.getEdgeData(g.addEdge(n1, n4)) = 1; // a0->n0
  g.getEdgeData(g.addEdge(n4, n1)) = 3; // n0->a0 (back edge)
  g.getEdgeData(g.addEdge(n1, n5)) = 1; // a0->n1
  g.getEdgeData(g.addEdge(n5, n1)) = 3; // n1->a0 (back edge)

  g.getEdgeData(g.addEdge(n2, n4)) = 1; // a1->n0
  g.getEdgeData(g.addEdge(n4, n2)) = 3; // n0->a1 (back edge)

  g.getEdgeData(g.addEdge(n3, n5)) = 1; // a2->n1
  g.getEdgeData(g.addEdge(n5, n3)) = 3; // n1->a2 (back edge)

  g.getEdgeData(g.addEdge(n4, n6)) = 1; // n0->n2
  g.getEdgeData(g.addEdge(n6, n4)) = 3; // n2->n0 (back edge)

  g.getEdgeData(g.addEdge(n5, n6)) = 1; // n1->n2
  g.getEdgeData(g.addEdge(n6, n5)) = 3; // n2->n1 (back edge)

  g.getEdgeData(g.addEdge(n6, n7)) = 1; // n2->s0
  g.getEdgeData(g.addEdge(n7, n6)) = 3; // s0->n2 (back edge)

  // print graph
  for (Graph::iterator ii = g.begin(), ei = g.end(); ii != ei; ++ii) {
    Graph::GraphNode src = *ii;
    cout << "node: " << g.getData(src).label_type;
    cout << endl;
    for (Graph::edge_iterator jj = g.edge_begin(src), ej = g.edge_end(src); jj != ej; ++jj) {
      Graph::GraphNode dst = g.getEdgeDst(jj);
      int e = g.getEdgeData(jj);
      if ( e == 1 )
        cout << "Forward noninverted edge to ";
      else if ( e == 2 )
        cout << "Forward inverted edge to ";
      else
        cout << "Back edge to ";

      cout << g.getData(dst).label_type << endl;
      //cout << "edge weight: " << g.getEdgeData(jj);
      //cout << endl;
    }
    cout << endl;
  }
  cout << endl;

  /*
   *  Algorithm
   */

  for (Graph::iterator ii = g.begin(), ei = g.end(); ++ii) {
    Graph::GraphNode top = **ii; // node we are attempting to build the cut from (top of the pyramid)
    Graph::GraphNode left = NULL, right = NULL, input1 = NULL, input2 = NULL, input3 = NULL, input4 = NULL;
    Graph::GraphNode output = NULL;
    if ( g.getData(src).type != np ) {
      nextcut:
      continue; } // move to the next node if a node is a primary input or output

    for (Graph::edge_iterator jj = g.edge_begin(top), ej = g.edge_end(top); jj != ej; ++jj) {
      // look for the back edges and follow them back to the input nodes to generate our cut
      Graph::GraphNode dst = g.getEdgeDst(jj);
      if ( g.getData(dst).type != nd )
        goto nextcut; // bail out if we find a primary input or output

      int e = g.getEdgeData(jj);
      if ( e == 3 ) {
        if ( left == NULL )
          left = dst;
        else if ( right == NULL )
          right = dst;
        else {
          cerr << "Error: node " << g.getData(top).label_type << " has more than two inputs\n"; exit; }
      }
    }
    if ( left == NULL || right == NULL ) {
      cerr << "Error: node " << g.getData(top).label_type << " does not have two inputs\n"; exit; }

    int left_edge, right_edge;
    // find the edges leading back to the top node and the input edges
    for (Graph::edge_iterator jj = g.edge_begin(left), ej = g.edge_end(left); jj != ej; ++jj) {
      Graph::GraphNode dst = g.getEdgeDst(jj);
      int e = g.getEdgeData(jj);
      if ( dst == top )
        left_edge = e;
      else if ( e == 3 ) {
        if ( input1 == NULL )
          input1 = dst;
        else if ( input2 == NULL )
          input2 = dst;
        else {
          cerr << "Error: node " << g.getData(left).label_type << " has more than two inputs\n"; exit; }
      }
    }

    for (Graph::edge_iterator jj = g.edge_begin(right), ej = g.edge_end(right); jj != ej; ++jj) {
      Graph::GraphNode dst = g.getEdgeDst(jj);
      int e = g.getEdgeData(jj);
      if ( dst == top )
        right_edge = e;
      else if ( e == 3 ) {
        if ( input3 == NULL )
          input1 = dst;
        else if ( input2 == NULL )
          input4 = dst;
        else {
          cerr << "Error: node " << g.getData(left).label_type << " has more than two inputs\n"; exit; }
      }
    }

  return 0;
}

<commit_msg>Now generates cuts<commit_after>/** My first Galois program -*- C++ -*-
 */
#include "Galois/Galois.h"
#include "Galois/Graph/Graph.h"
#include <boost/iterator/counting_iterator.hpp>
#include <iostream>
#include <string>

using namespace std;

//typedef Galois::Graph::FirstGraph<std::string,std::string,true> Graph;

typedef enum{pi,po,nd} node_type;

struct Node {
 string label_type;//a0,b0...
 node_type type;// pi,po,nd
 int fanins;
 bool fanout;
 int level;
 };

typedef Galois::Graph::FirstGraph<Node,int,true> Graph;

int main(int argc, char** argv) {

  /*
   * Subgraph 1 from Fig.2 in "DAG-Aware AIG Rewriting"
   *
   */
  Graph g;
  Node vn1, vn2, vn3, vn4, vn5, vn6, vn7, vn8;
  Graph::GraphNode n1, n2, n3, n4, n5, n6, n7, n8;

  /*
   * Label vertices
   */

  // primary inputs
  vn1.type = pi; vn2.type = pi; vn3.type = pi;
  vn1.level = 0; vn2.level = 0; vn3.level = 0;
  vn1.label_type = "a0"; vn2.label_type = "a1"; vn3.label_type = "a2";

  // intermediate nodes
  vn4.type = nd; vn5.type = nd; vn6.type = nd;
  vn4.level = 1; vn5.level = 1; vn6.level = 2;
  vn4.label_type = "n0"; vn5.label_type = "n1"; vn6.label_type = "n2";

  // primary output
  vn7.type = po; vn7.level = 3; vn7.label_type = "s0";

  /*
   * Create vertices
   */
  n1 = g.createNode(vn1);
  n2 = g.createNode(vn2);
  n3 = g.createNode(vn3);
  n4 = g.createNode(vn4);
  n5 = g.createNode(vn5);
  n6 = g.createNode(vn6);
  n7 = g.createNode(vn7);

  g.addNode(n1);
  g.addNode(n2);
  g.addNode(n3);
  g.addNode(n4);
  g.addNode(n5);
  g.addNode(n6);
  g.addNode(n7);

  /*
   * Create edges
   */
  g.getEdgeData(g.addEdge(n1, n4)) = 1; // a0->n0
  g.getEdgeData(g.addEdge(n4, n1)) = 3; // n0->a0 (back edge)
  g.getEdgeData(g.addEdge(n1, n5)) = 1; // a0->n1
  g.getEdgeData(g.addEdge(n5, n1)) = 3; // n1->a0 (back edge)

  g.getEdgeData(g.addEdge(n2, n4)) = 1; // a1->n0
  g.getEdgeData(g.addEdge(n4, n2)) = 3; // n0->a1 (back edge)

  g.getEdgeData(g.addEdge(n3, n5)) = 1; // a2->n1
  g.getEdgeData(g.addEdge(n5, n3)) = 3; // n1->a2 (back edge)

  g.getEdgeData(g.addEdge(n4, n6)) = 1; // n0->n2
  g.getEdgeData(g.addEdge(n6, n4)) = 3; // n2->n0 (back edge)

  g.getEdgeData(g.addEdge(n5, n6)) = 1; // n1->n2
  g.getEdgeData(g.addEdge(n6, n5)) = 3; // n2->n1 (back edge)

  g.getEdgeData(g.addEdge(n6, n7)) = 1; // n2->s0
  g.getEdgeData(g.addEdge(n7, n6)) = 3; // s0->n2 (back edge)

  // print graph
  for (Graph::iterator ii = g.begin(), ei = g.end(); ii != ei; ++ii) {
    Graph::GraphNode src = *ii;
    cout << "node: " << g.getData(src).label_type;
    cout << endl;
    for (Graph::edge_iterator jj = g.edge_begin(src), ej = g.edge_end(src); jj != ej; ++jj) {
      Graph::GraphNode dst = g.getEdgeDst(jj);
      int e = g.getEdgeData(jj);
      if ( e == 1 )
        cout << "Forward noninverted edge to ";
      else if ( e == 2 )
        cout << "Forward inverted edge to ";
      else
        cout << "Back edge to ";

      cout << g.getData(dst).label_type << endl;
      //cout << "edge weight: " << g.getEdgeData(jj);
      //cout << endl;
    }
    cout << endl;
  }
  cout << endl;

  /*
   *  Algorithm
   */

  cout << "Begin Algorithm:\n";

  for (Graph::iterator ii = g.begin(), ei = g.end(); ii != ei; ++ii) {
    Graph::GraphNode top = *ii; // node we are attempting to build the cut from (top of the pyramid)
    Graph::GraphNode left = NULL, right = NULL, input1 = NULL, input2 = NULL, input3 = NULL, input4 = NULL;
    Graph::GraphNode output = NULL;
    cout << "Checking node " << g.getData(top).label_type << endl;
    if ( g.getData(top).type != nd ) {
      cout << "Node is not nd type\n";
      nextcut:
      cout << "Moving to next node\n\n";
      continue; } // move to the next node if a node is a primary input or output

    cout << "Checking edges for top node\n";
    for (Graph::edge_iterator jj = g.edge_begin(top), ej = g.edge_end(top); jj != ej; ++jj) {
      // look for the back edges and follow them back to the input nodes to generate our cut
      Graph::GraphNode dst = g.getEdgeDst(jj);
      int ew = g.getEdgeData(jj);
      cout << "Found edge of weight " << ew << " to node " << g.getData(dst).label_type << endl;
      if ( ew == 3 ) {
        if ( g.getData(dst).type != nd ) {
          cout << "Left or right node is not nd type\n";
          goto nextcut; }// bail out if we find a primary input or output
        else if ( left == NULL ) {
          left = dst; cout << "left = " << g.getData(left).label_type << endl; }
        else if ( right == NULL ) {
          right = dst; cout << "right = " << g.getData(right).label_type << endl; }
        else {
          cerr << "Error: node " << g.getData(top).label_type << " has more than two inputs\n"; exit; }
      }
      else { // build list of outputs
        }
    }
    if ( left == NULL || right == NULL ) {
      cerr << "Error: node " << g.getData(top).label_type << " does not have two inputs\n"; exit; }

    //cout << "Found nodes " << g.getData(left).label_type << " and " << g.getData(right).label_type << endl;

    int left_edge, right_edge;
    // find the edges leading back to the top node and the input edges
    cout << "Checking edges for left node\n";
    for (Graph::edge_iterator jj = g.edge_begin(left), ej = g.edge_end(left); jj != ej; ++jj) {
      Graph::GraphNode dst = g.getEdgeDst(jj);
      int ew = g.getEdgeData(jj);
      cout << "Found edge of weight " << ew << " to node " << g.getData(dst).label_type << endl;
      if ( dst == top ) {
        left_edge = ew; cout << "left_edge = " << left_edge << endl; }
      else if ( ew == 3 ) {
        if ( input1 == NULL ) {
          input1 = dst; cout << "input1 = " << g.getData(input1).label_type << endl; }
        else if ( input2 == NULL ) {
          input2 = dst; cout << "input2 = " << g.getData(input2).label_type << endl; }
        else {
          cerr << "Error: node " << g.getData(left).label_type << " has more than two inputs\n"; exit; }
      }
      else {
        goto nextcut; }

    }
    cout << "Checking edges for right node\n";
    for (Graph::edge_iterator jj = g.edge_begin(right), ej = g.edge_end(right); jj != ej; ++jj) {
      Graph::GraphNode dst = g.getEdgeDst(jj);
      int ew = g.getEdgeData(jj);
      cout << "Found edge of weight " << ew << " to node " << g.getData(dst).label_type << endl;
      if ( dst == top ) {
        right_edge = ew; cout << "right_edge = " << left_edge << endl; }
      else if ( ew == 3 ) {
        if ( input3 == NULL ) {
          input3 = dst; cout << "input3 = " << g.getData(input3).label_type << endl; }
        else if ( input4 == NULL ) {
          input4 = dst; cout << "input4 = " << g.getData(input4).label_type << endl; }
        else {
          cerr << "Error: node " << g.getData(right).label_type << " has more than two inputs\n"; exit; }
      }
      else {
        goto nextcut; }
    }

    cout << "\nCut:\n";
    cout << "Output(s) = ";
    cout << "Top = " << g.getData(top).label_type << endl;
    cout << "Left = " << g.getData(left).label_type << endl;
    cout << "Right = " << g.getData(left).label_type << endl;
    cout << "Left_edge = " << left_edge << endl;
    cout << "Right_edge = " << right_edge << endl;
    cout << "Input1 = " << g.getData(input1).label_type << endl;
    cout << "Input2 = " << g.getData(input2).label_type << endl;
    cout << "Input3 = " << g.getData(input3).label_type << endl;
    cout << "Input4 = " << g.getData(input4).label_type << endl;
    cout << endl;
  }
  cout << "Done\n";
  return 0;
}

<|endoftext|>


<commit_before>#include "vlc_video_source.h"
#include <cstdio>
#include <cstdlib>
#include <chrono>
#include <thread>

namespace gg
{

VideoSourceVLC::VideoSourceVLC(const std::string path)
    : _vlc_inst(nullptr)
    , _vlc_mp(nullptr)
    , _video_buffer(nullptr)
    , _data_length(0)
    , _cols(0)
    , _rows(0)
    , _sub(nullptr)
    , _path(path)
{
    this->init_vlc();
    this->run_vlc();
}

VideoSourceVLC::~VideoSourceVLC()
{
    stop_vlc();
    release_vlc();
    clear();
}

bool VideoSourceVLC::get_frame_dimensions(int & width, int & height)
{
    ///\todo mutex

    if(this->_cols == 0 || this->_rows == 0)
        return false;

    width = this->_cols;
    height = this->_rows;
    return true;
}

bool VideoSourceVLC::get_frame(VideoFrame_BGRA & frame)
{
    throw VideoSourceError("VLC video source supports only I420 colour space");

    // TODO

    ///\todo mutex

    if (_cols == 0 || _rows == 0 || _video_buffer == nullptr)
        return false;

    // allocate and fill the image
    if (_cols * _rows * 4 == this->_data_length)
        frame = VideoFrame_BGRA(this->_video_buffer, this->_cols, this->_rows);
    else
        throw VideoSourceError("VLC video source does not support padded images");

    return true;
}

bool VideoSourceVLC::get_frame(VideoFrame_I420 & frame)
{
    if (_data_length > 0)
    {
        // TODO manage data?
        frame = VideoFrame_I420(_video_buffer, _data_length, _cols, _rows, false);
        return true;
    }
    else
        return false;

    // TODO #86
}

double VideoSourceVLC::get_frame_rate()
{
    return libvlc_media_player_get_fps(_vlc_mp);
}

void VideoSourceVLC::set_sub_frame(int x, int y, int width, int height)
{
    // TODO mutex?

    if (x >= _full.x and x + width <= _full.x + _full.width and
        y >= _full.y and y + height <= _full.y + _full.height)
    {
        stop_vlc();
        release_vlc();
        set_crop(x, y, width, height);
        init_vlc();
        run_vlc();
    }
}

void VideoSourceVLC::get_full_frame()
{
    // TODO mutex?
    stop_vlc();
    release_vlc();
    init_vlc();
    run_vlc();
}

void VideoSourceVLC::init_vlc()
{
    // VLC pointers
    libvlc_media_t * vlc_media = nullptr;

    // VLC options
    char smem_options[512];

    sprintf(smem_options, "#");
    if (_sub != nullptr)
    {
        unsigned int croptop = _sub->y,
                     cropbottom = _full.height - (_sub->y + _sub->height),
                     cropleft = _sub->x,
                     cropright = _full.width - (_sub->x + _sub->width);
        sprintf(smem_options,
                "%stranscode{vcodec=I420,vfilter=croppadd{",
                smem_options);
        sprintf(smem_options,
                "%scroptop=%u,cropbottom=%u,cropleft=%u,cropright=%u}",
                smem_options,
                croptop, cropbottom, cropleft, cropright);
        sprintf(smem_options, "%s}:", smem_options);
    }
    sprintf(smem_options,
            "%ssmem{video-data=%lld,video-prerender-callback=%lld,video-postrender-callback=%lld}",
            smem_options,
            (long long int)(intptr_t)(void*) this,
            (long long int)(intptr_t)(void*) &VideoSourceVLC::prepareRender,
            (long long int)(intptr_t)(void*) &VideoSourceVLC::handleStream );

    const char * const vlc_args[] = {
        "-I", "dummy", // Don't use any interface
        "--ignore-config", // Don't use VLC's config
        "--file-logging",
        // TODO - what about the options below?
        //"--verbose=2", // Be much more verbose then normal for debugging purpose
        //"--clock-jitter=0",
        //"--file-caching=150",
        "--no-audio",
        "--sout", smem_options // Stream to memory
    };

    // We launch VLC
    _vlc_inst = libvlc_new(sizeof(vlc_args) / sizeof(vlc_args[0]), vlc_args);
    if (_vlc_inst == nullptr)
        throw VideoSourceError("Could not create VLC engine");

    // If path contains a colon (:), it will be treated as a
    // URL. Else, it will be considered as a local path.
    if (_path.find(":") == std::string::npos)
        vlc_media = libvlc_media_new_path(_vlc_inst, _path.c_str());
    else
        vlc_media = libvlc_media_new_location(_vlc_inst, _path.c_str());
    if (vlc_media == nullptr)
        throw VideoSourceError(std::string("Could not open ").append(_path));

    libvlc_media_add_option(vlc_media, ":noaudio");
    libvlc_media_add_option(vlc_media, ":no-video-title-show");

    // Create a media player playing environement
    _vlc_mp = libvlc_media_player_new_from_media(vlc_media);
    if (_vlc_mp == nullptr)
        throw VideoSourceError("Could not create VLC media player");

    // No need to keep the media now
    libvlc_media_release( vlc_media );
}

void VideoSourceVLC::run_vlc()
{
    // play the media_player
    if (libvlc_media_player_play(_vlc_mp) != 0)
        throw VideoSourceError("Could not start VLC media player");

    // empirically determined value that allows for initialisation
    // to succeed before any API functions are called on this object
    std::this_thread::sleep_for(std::chrono::milliseconds(350));

    determine_full();
}

void VideoSourceVLC::stop_vlc()
{
    // stop playing
    libvlc_media_player_stop(_vlc_mp);
}

void VideoSourceVLC::release_vlc()
{
    // free media player
    libvlc_media_player_release(_vlc_mp);

    // free engine
    libvlc_release(_vlc_inst);

    clear();

    reset_crop();
}

void VideoSourceVLC::clear()
{
    // free buffer
    if (_video_buffer != nullptr)
        delete[] _video_buffer;
    _data_length = 0;
    _cols = 0;
    _rows = 0;

    reset_crop();
}

void VideoSourceVLC::determine_full()
{
    unsigned int width, height;
    if (libvlc_video_get_size(_vlc_mp, 0, &width, &height) != 0)
        throw VideoSourceError("Could not get video dimensions");

    _full.x = 0;
    _full.y = 0;
    _full.width = width;
    _full.height = height;
}

void VideoSourceVLC::set_crop(unsigned int x, unsigned int y,
                              unsigned int width, unsigned int height)
{
    if (_sub == nullptr) _sub = new FrameBox;
    _sub->x = x;
    _sub->y = y;
    _sub->width = width;
    _sub->height = height;
}

void VideoSourceVLC::reset_crop()
{
    // free sub-frame
    if (_sub != nullptr)
    {
        delete _sub;
        _sub = nullptr;
    }
}

void VideoSourceVLC::prepareRender(VideoSourceVLC * p_video_data,
                                   uint8_t ** pp_pixel_buffer,
                                   size_t size)
{
    ///\todo create mutex guard
    if (size > p_video_data->_data_length)
    {
        if (p_video_data->_data_length == 0)
            p_video_data->_video_buffer = reinterpret_cast<uint8_t *>(
                        malloc(size * sizeof(uint8_t))
                        );
        else
            p_video_data->_video_buffer = reinterpret_cast<uint8_t *>(
                        realloc(p_video_data->_video_buffer, size * sizeof(uint8_t))
                        );
    }
    p_video_data->_data_length = size;

    *pp_pixel_buffer = p_video_data->_video_buffer;
}

void VideoSourceVLC::handleStream(VideoSourceVLC * p_video_data,
                                  uint8_t * p_pixel_buffer,
                                  size_t cols,
                                  size_t rows,
                                  size_t colour_depth,
                                  size_t size)
{
    // TODO: explain how data should be handled (see #86)
    p_video_data->_cols = cols;
    p_video_data->_rows = rows;
    // TODO: Unlock the mutex
}

}
<commit_msg>Issue #83: revised *_vlc functions to do only VLC related work, and not freeing any resources<commit_after>#include "vlc_video_source.h"
#include <cstdio>
#include <cstdlib>
#include <chrono>
#include <thread>

namespace gg
{

VideoSourceVLC::VideoSourceVLC(const std::string path)
    : _vlc_inst(nullptr)
    , _vlc_mp(nullptr)
    , _video_buffer(nullptr)
    , _data_length(0)
    , _cols(0)
    , _rows(0)
    , _sub(nullptr)
    , _path(path)
{
    init_vlc();
    run_vlc();
    determine_full();
}

VideoSourceVLC::~VideoSourceVLC()
{
    stop_vlc();
    release_vlc();
    clear();
}

bool VideoSourceVLC::get_frame_dimensions(int & width, int & height)
{
    ///\todo mutex

    if(this->_cols == 0 || this->_rows == 0)
        return false;

    width = this->_cols;
    height = this->_rows;
    return true;
}

bool VideoSourceVLC::get_frame(VideoFrame_BGRA & frame)
{
    throw VideoSourceError("VLC video source supports only I420 colour space");

    // TODO

    ///\todo mutex

    if (_cols == 0 || _rows == 0 || _video_buffer == nullptr)
        return false;

    // allocate and fill the image
    if (_cols * _rows * 4 == this->_data_length)
        frame = VideoFrame_BGRA(this->_video_buffer, this->_cols, this->_rows);
    else
        throw VideoSourceError("VLC video source does not support padded images");

    return true;
}

bool VideoSourceVLC::get_frame(VideoFrame_I420 & frame)
{
    if (_data_length > 0)
    {
        // TODO manage data?
        frame = VideoFrame_I420(_video_buffer, _data_length, _cols, _rows, false);
        return true;
    }
    else
        return false;

    // TODO #86
}

double VideoSourceVLC::get_frame_rate()
{
    return libvlc_media_player_get_fps(_vlc_mp);
}

void VideoSourceVLC::set_sub_frame(int x, int y, int width, int height)
{
    // TODO mutex?

    if (x >= _full.x and x + width <= _full.x + _full.width and
        y >= _full.y and y + height <= _full.y + _full.height)
    {
        stop_vlc();
        release_vlc();
        set_crop(x, y, width, height);
        init_vlc();
        run_vlc();
    }
}

void VideoSourceVLC::get_full_frame()
{
    // TODO mutex?
    stop_vlc();
    release_vlc();
    reset_crop();
    init_vlc();
    run_vlc();
}

void VideoSourceVLC::init_vlc()
{
    // VLC pointers
    libvlc_media_t * vlc_media = nullptr;

    // VLC options
    char smem_options[512];

    sprintf(smem_options, "#");
    if (_sub != nullptr)
    {
        unsigned int croptop = _sub->y,
                     cropbottom = _full.height - (_sub->y + _sub->height),
                     cropleft = _sub->x,
                     cropright = _full.width - (_sub->x + _sub->width);
        sprintf(smem_options,
                "%stranscode{vcodec=I420,vfilter=croppadd{",
                smem_options);
        sprintf(smem_options,
                "%scroptop=%u,cropbottom=%u,cropleft=%u,cropright=%u}",
                smem_options,
                croptop, cropbottom, cropleft, cropright);
        sprintf(smem_options, "%s}:", smem_options);
    }
    sprintf(smem_options,
            "%ssmem{video-data=%lld,video-prerender-callback=%lld,video-postrender-callback=%lld}",
            smem_options,
            (long long int)(intptr_t)(void*) this,
            (long long int)(intptr_t)(void*) &VideoSourceVLC::prepareRender,
            (long long int)(intptr_t)(void*) &VideoSourceVLC::handleStream );

    const char * const vlc_args[] = {
        "-I", "dummy", // Don't use any interface
        "--ignore-config", // Don't use VLC's config
        "--file-logging",
        // TODO - what about the options below?
        //"--verbose=2", // Be much more verbose then normal for debugging purpose
        //"--clock-jitter=0",
        //"--file-caching=150",
        "--no-audio",
        "--sout", smem_options // Stream to memory
    };

    // We launch VLC
    _vlc_inst = libvlc_new(sizeof(vlc_args) / sizeof(vlc_args[0]), vlc_args);
    if (_vlc_inst == nullptr)
        throw VideoSourceError("Could not create VLC engine");

    // If path contains a colon (:), it will be treated as a
    // URL. Else, it will be considered as a local path.
    if (_path.find(":") == std::string::npos)
        vlc_media = libvlc_media_new_path(_vlc_inst, _path.c_str());
    else
        vlc_media = libvlc_media_new_location(_vlc_inst, _path.c_str());
    if (vlc_media == nullptr)
        throw VideoSourceError(std::string("Could not open ").append(_path));

    libvlc_media_add_option(vlc_media, ":noaudio");
    libvlc_media_add_option(vlc_media, ":no-video-title-show");

    // Create a media player playing environement
    _vlc_mp = libvlc_media_player_new_from_media(vlc_media);
    if (_vlc_mp == nullptr)
        throw VideoSourceError("Could not create VLC media player");

    // No need to keep the media now
    libvlc_media_release(vlc_media);
}

void VideoSourceVLC::run_vlc()
{
    // play the media_player
    if (libvlc_media_player_play(_vlc_mp) != 0)
        throw VideoSourceError("Could not start VLC media player");

    // empirically determined value that allows for initialisation
    // to succeed before any API functions are called on this object
    std::this_thread::sleep_for(std::chrono::milliseconds(350));
}

void VideoSourceVLC::stop_vlc()
{
    // stop playing
    libvlc_media_player_stop(_vlc_mp);
}

void VideoSourceVLC::release_vlc()
{
    // free media player
    libvlc_media_player_release(_vlc_mp);

    // free engine
    libvlc_release(_vlc_inst);
}

void VideoSourceVLC::clear()
{
    // free buffer
    if (_video_buffer != nullptr)
        delete[] _video_buffer;
    _data_length = 0;
    _cols = 0;
    _rows = 0;

    reset_crop();
}

void VideoSourceVLC::determine_full()
{
    unsigned int width, height;
    if (libvlc_video_get_size(_vlc_mp, 0, &width, &height) != 0)
        throw VideoSourceError("Could not get video dimensions");

    _full.x = 0;
    _full.y = 0;
    _full.width = width;
    _full.height = height;
}

void VideoSourceVLC::set_crop(unsigned int x, unsigned int y,
                              unsigned int width, unsigned int height)
{
    if (_sub == nullptr) _sub = new FrameBox;
    _sub->x = x;
    _sub->y = y;
    _sub->width = width;
    _sub->height = height;
}

void VideoSourceVLC::reset_crop()
{
    // free sub-frame
    if (_sub != nullptr)
    {
        delete _sub;
        _sub = nullptr;
    }
}

void VideoSourceVLC::prepareRender(VideoSourceVLC * p_video_data,
                                   uint8_t ** pp_pixel_buffer,
                                   size_t size)
{
    ///\todo create mutex guard
    if (size > p_video_data->_data_length)
    {
        if (p_video_data->_data_length == 0)
            p_video_data->_video_buffer = reinterpret_cast<uint8_t *>(
                        malloc(size * sizeof(uint8_t))
                        );
        else
            p_video_data->_video_buffer = reinterpret_cast<uint8_t *>(
                        realloc(p_video_data->_video_buffer, size * sizeof(uint8_t))
                        );
    }
    p_video_data->_data_length = size;

    *pp_pixel_buffer = p_video_data->_video_buffer;
}

void VideoSourceVLC::handleStream(VideoSourceVLC * p_video_data,
                                  uint8_t * p_pixel_buffer,
                                  size_t cols,
                                  size_t rows,
                                  size_t colour_depth,
                                  size_t size)
{
    // TODO: explain how data should be handled (see #86)
    p_video_data->_cols = cols;
    p_video_data->_rows = rows;
    // TODO: Unlock the mutex
}

}
<|endoftext|>