All Downloads are FREE. Search and download functionalities are using the official Maven repository.

basicp2psim.protocols.peer.flakey Maven / Gradle / Ivy

/* This file is part of 'agarnet'
 *
 * Copyright (c) Facebook, Inc. and its affiliates
 *
 * agarnet is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation; either version 3, or (at your option) any
 * later version.
 * 
 * agarnet 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 General Public License for more details.   
 *
 * You should have received a copy of the GNU General Public License
 * along with agarnet.  If not, see .
 */

package basicp2psim.protocols.peer;

import java.util.Arrays;

import org.fusesource.hawtjni.runtime.*;
import static org.fusesource.hawtjni.runtime.ArgFlag.*;
import static org.fusesource.hawtjni.runtime.MethodFlag.*;

import org.nongnu.multigraph.debug;

import agarnet.protocols.protocol;
import agarnet.protocols.AbstractProtocol;

import basicp2psim.protocols.peer.data.file;

@JniClass
public class flakey extends AbstractProtocol {
 private static final char[] HEX_ARRAY = "0123456789ABCDEF".toCharArray();
 public static String bytesToHex(byte[] bytes) {
     char[] hexChars = new char[bytes.length * 3];
     for (int j = 0; j < bytes.length; j++) {
         int v = bytes[j] & 0xFF;
         hexChars[j * 3] = ' ';
         hexChars[j * 3 + 1] = HEX_ARRAY[v >>> 4];
         hexChars[j * 3 + 2] = HEX_ARRAY[v & 0x0F];
         //System.out.printf ("%2d: %3d %c%c\n", j, v, hexChars[j * 3 + 1], hexChars[j * 3 + 2]);
     }
     return new String(hexChars);
 }

    
  private static final Library LIBRARY = new Library("agarnet", 
                                                     flakey.class);
  private static Callback debug_cb;
  static { 
    LIBRARY.load();
    debug_cb = new Callback (flakey.class, "debug_from_native", 1);
  }
  
  /* HawtJNI Callback is extremely limited on arguments.
   * can only take long arguments.
   * 
   * So use the Callback as a notification method, to then
   * call to a better typed call into native.
   *
   * TODO: Find a better solution, e.g.  just use hand-crafted JNI to
   * produce exactly the callback required, if needs be.  FBJNI maybe has
   * something better.
   */
  static public long debug_from_native (long instance) {
    byte [] msg = new byte[200];
    native_get_debug_msg (instance, msg, msg.length);
    debug.println(new String(msg));
    return 0;
  }

  /* Be nice to gather together the various (byte[], length) parameters
   * below into this struct.
   *
   * However, HawtJNI does not know how to properly copy references to arrays
   * back and forth from native. It uses sizeof(field) for the length, so only
   * supports embedded, fixed size arrays.
   *
   * Be nice to teach HawtJNI how to use an additional 'length' field to deal
   * with array references in structs.
   *
   * Otherwise... hand-coded JNI, or a better JNI generator.
   */
  @JniClass(flags={ClassFlag.STRUCT})
  public static class native_buffer {
    @JniField byte [] data;
    @JniField(cast="size_t") long len;
    @JniField(cast="size_t") long capacity;

    public native_buffer (byte [] data, long capacity) {
      this.data = data;
      this.len = data.length;
      this.capacity = capacity;
    }    
    public native_buffer (byte [] data) {
      this (data, data.length);
    }
  };
 
  /* rename the internal java methods to 'native_...' so it is clear
   * elsewhere where we're calling the native statics */
  @JniMethod(cast="void *", accessor="flakeyproto_new",
             flags={MethodFlag.POINTER_RETURN}) 
  public static final native long native_new (float probability_percent);
  
  @JniMethod(accessor="flakeyproto_down")
  public static native void native_down(
    @JniArg(cast="const void *", flags={ArgFlag.CRITICAL}) long self,
    long to,
    @JniArg(cast="uint8_t *", flags={CRITICAL, NO_OUT}) byte [] buf,
    @JniArg(cast="size_t", flags={CRITICAL, NO_OUT}) long len
  );
  
  @JniMethod(accessor="flakeyproto_up")
  public static native void native_up(
    @JniArg(cast="const void *", flags={ArgFlag.CRITICAL}) long self,
    long from,
    @JniArg(cast="uint8_t *", flags={CRITICAL, NO_OUT}) byte [] buf,
    @JniArg(cast="size_t", flags={CRITICAL, NO_OUT}) long len
  );

  @JniMethod(accessor="flakeyproto_flood")
  public static native void native_flood(
    @JniArg(cast="const void *", flags={ArgFlag.CRITICAL}) long self,
    long from,
    @JniArg(cast="uint8_t *", flags={CRITICAL, NO_OUT}) byte [] buf,
    @JniArg(cast="size_t", flags={CRITICAL, NO_OUT}) long len
  );

  @JniMethod(cast="void *", accessor="flakeyproto_link_add") 
  public static final native long native_link_add (
    @JniArg(cast="void *", flags={ArgFlag.CRITICAL}) long self,
    long neighbour
  );

  @JniMethod(accessor="flakeyproto_link_remove")
  public static final native void native_link_remove (
    @JniArg(cast="const void *", flags={ArgFlag.CRITICAL}) long self,
    long neighbour
  );

  @JniMethod(accessor="flakeyproto_setid")
  public static final native void native_setid (
    @JniArg(cast="void *", flags={ArgFlag.CRITICAL}) long self,
    long id
  );
  

  @JniMethod(accessor="flakeyproto_set_debug")
  public static final native void native_set_debug (
    @JniArg(cast="void *", flags={ArgFlag.CRITICAL}) long self,
    @JniArg(cast="void *", flags={ArgFlag.CRITICAL}) long debug_cb
  );

  @JniMethod(accessor="flakeyproto_get_debug_msg")
  public static final native void native_get_debug_msg (
    @JniArg(cast="void *", flags={CRITICAL}) long self,
    @JniArg(cast="char *", flags={CRITICAL}) byte[] msg,
    @JniArg(cast="size_t") long length
  );

  @JniMethod(accessor="flakeyproto_set_send_notify")
  public static final native void native_set_send_notify (
    @JniArg(cast="void *", flags={ArgFlag.CRITICAL}) long self,
    @JniArg(cast="void *", flags={ArgFlag.CRITICAL}) long send_cb
  );

  @JniMethod(cast="size_t", accessor="flakeyproto_send_out")
  public static final native long native_send_out (
    @JniArg(cast="void *", flags={ArgFlag.CRITICAL}) long self,
    @JniArg(cast="void *", flags={ArgFlag.CRITICAL}) long msgp,
    @JniArg(cast="uint8_t *", flags={CRITICAL}) byte[] msg,
    @JniArg(cast="size_t") long length
  );

  
  private long native_instance;
  private int num_to_seed;
  
  public flakey (float flakeyprob, int num_to_seed) {
    native_instance = native_new (flakeyprob);
    native_set_debug (native_instance, debug_cb.getAddress ());
    this.num_to_seed = num_to_seed;
  }
  
  public flakey (float flakeyprob) {
    this (flakeyprob, 0);
  }
  
  public void up (Long src, byte [] data) {
    file f = null;
    debug.println(selfId + ": java native up, from " 
                       + src 
                       + " len " + data.length
                       + " " + data[0]);
    try {
      f = file.deserialise (data);
    } catch (Exception e) {
      debug.println ("Unhandled message: " + e);
      return;
    }
    debug.printf ("peer %s: got file %s\n", this, f);
    //debug.printf ("peer %s: byte array: %s\n", this, bytesToHex (data));

    native_buffer buf = new native_buffer (data);

    Callback send_cb = new Callback (this, "send_ready", 3);
    native_set_send_notify (native_instance, send_cb.getAddress ());
    native_up (native_instance, src, data, data.length);
    
    try {
      f = file.deserialise (buf.data);
      debug.printf ("peer %s: after buf data file %s\n", this, f);
    } catch (Exception e) {
      debug.println ("Unhandled message: " + e);
      return;
    }
    
    send_cb.dispose ();
  }

  
  //@JniClass(flags={ClassFlag.STRUCT})
  //public static class flakeyproto_msg {
  //  @JniField(cast="size_t") long len;
  //  byte [] data;
  //};
  
  @JniField(flags={FieldFlag.CONSTANT})
  public static int flakeyproto_msg_maxlen;
  
  /* The notification call back that the native instance has something
   * to send.
   *
   * XXX: Crufty dance with notify callback calling back to ntaive, because
   * Callback method is limited in argument types to long.
   * TODO: Find a better solution, e.g. hand-crafted JNI if needs be.
   */
  public long send_ready (long instance, long to, long msgp) {
    native_buffer msg = new native_buffer (new byte [1000]);
    
    debug.printf ("%d: to %d %d\n", selfId, to, msg.len);
    
    /* HACK: use native code to convert the msgp to byte array */
    native_send_out (instance, msgp, msg.data, msg.len);
    
    try {
      file f = file.deserialise (msg.data);
      debug.printf ("peer %s: send out file %s\n", this, f);
    } catch (Exception e) {
      debug.println ("Unhandled message: " + e);
    }

    send (to, msg.data);

    return 0;
  }
  
  public void down (Long dst, byte [] data) {
    debug.println(selfId + ": java native down");
    native_down (native_instance, dst, data, data.length);
  }
  
  private void seed_file () {
    file f = new file (selfId + "/" + num_to_seed, 
                       "blah blah blah".getBytes ());
    debug.printf ("seed %s: seeding %s\n", selfId, f);
    try {
      byte [] data = f.serialise ().clone();
      Callback send_cb = new Callback (this, "send_ready", 3);
      native_set_send_notify (native_instance, send_cb.getAddress ());
      native_flood (native_instance, selfId, data, data.length);
      send_cb.dispose ();
    } catch (Exception e) {
      debug.println ("Unhandled message: " + e);
    }
  }


  @Override
  public void tick () {
    debug.printf ("flakey %s tick %d\n", selfId, ticks);
    
    if (num_to_seed > 0) {
      seed_file ();
      num_to_seed--;
    } 
    super.tick ();
  }
  
  @Override  
  public void link_add (Long neighbour) {
   debug.println(selfId + ": framework native link_add");
   native_instance = native_link_add (native_instance, neighbour);
  }
  
  @Override
  public void link_remove (Long neighbour) {
   debug.println(selfId + ":framework native link_remove");
   native_link_remove (native_instance, neighbour);
  }
  
  public flakey setId (Long id) {
    super.setId (id);
    native_setid (native_instance, id);
    return this;
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy