// StartProfiling will create a .prof file to analyze p2p app performance func StartProfiling(profile string) { pwd, err := os.Getwd() if err != nil { ptp.Log(ptp.Error, "Getwd() error : %v", err) return } timeStr := "cpu" if profile == "cpu" { fileName := fmt.Sprintf("%s/%s.prof", pwd, timeStr) f, err := os.Create(fileName) if err != nil { ptp.Log(ptp.Error, "Create cpu_prof file failed. %v", err) return } ptp.Log(ptp.Info, "Start cpu profiling to file %s", fileName) pprof.StartCPUProfile(f) } else if profile == "memory" { _, err := os.Create(fmt.Sprintf("%s/%s.p2p_mem_prof", pwd, timeStr)) if err != nil { ptp.Log(ptp.Error, "Create mem_prof file failed. %v", err) return } } }
// Daemon starts P2P daemon func Daemon(port, sFile, profiling string) { StartProfiling(profiling) ptp.InitPlatform() instances = make(map[string]instance) ptp.InitErrors() if !ptp.CheckPermissions() { os.Exit(1) } proc := new(Procedures) rpc.Register(proc) rpc.HandleHTTP() listen, err := net.Listen("tcp", "localhost:"+port) if err != nil { ptp.Log(ptp.Error, "Cannot start RPC listener %v", err) os.Exit(1) } if sFile != "" { saveFile = sFile ptp.Log(ptp.Info, "Restore file provided") // Try to restore from provided file instances, err := loadInstances(saveFile) if err != nil { ptp.Log(ptp.Error, "Failed to load instances: %v", err) } else { ptp.Log(ptp.Info, "%d instances were loaded from file", len(instances)) for _, inst := range instances { resp := new(Response) proc.Run(&inst, resp) } } } ptp.Log(ptp.Info, "Starting RPC Listener on %s port", port) go http.Serve(listen, nil) // Capture SIGINT // This is used for development purposes only, but later we should consider updating // this code to handle signals c := make(chan os.Signal, 1) signal.Notify(c, os.Interrupt) go func() { for sig := range c { fmt.Println("Received signal: ", sig) pprof.StopCPUProfile() os.Exit(0) } }() select {} }
// SetLog modifies specific option func (p *Procedures) SetLog(args *NameValueArg, resp *Response) error { ptp.Log(ptp.Info, "Setting option %s to %s", args.Name, args.Value) resp.ExitCode = 0 if args.Name == "log" { resp.Output = "Logging level has switched to " + args.Value + " level" if args.Value == "DEBUG" { ptp.SetMinLogLevel(ptp.Debug) } else if args.Value == "INFO" { ptp.SetMinLogLevel(ptp.Info) } else if args.Value == "TRACE" { ptp.SetMinLogLevel(ptp.Trace) } else if args.Value == "WARNING" { ptp.SetMinLogLevel(ptp.Warning) } else if args.Value == "ERROR" { ptp.SetMinLogLevel(ptp.Error) } else { resp.ExitCode = 1 resp.Output = "Unknown log level was specified. Supported log levels is:\n" resp.Output = resp.Output + "TRACE\n" resp.Output = resp.Output + "DEBUG\n" resp.Output = resp.Output + "INFO\n" resp.Output = resp.Output + "WARNING\n" resp.Output = resp.Output + "ERROR\n" } } return nil }
// Dial connects to a local RPC server func Dial(port string) *rpc.Client { client, err := rpc.DialHTTP("tcp", "localhost:"+port) if err != nil { ptp.Log(ptp.Error, "Failed to connect to RPC %v", err) os.Exit(1) } return client }
func encodeInstances() ([]byte, error) { var savedInstances []RunArgs instances_mut.Lock() for _, inst := range instances { savedInstances = append(savedInstances, inst.Args) } instances_mut.Unlock() runtime.Gosched() b := bytes.Buffer{} e := gob.NewEncoder(&b) err := e.Encode(savedInstances) if err != nil { ptp.Log(ptp.Error, "Failed to encode instances: %v", err) return []byte(""), err } return b.Bytes(), nil }
// Run starts a P2P instance func (p *Procedures) Run(args *RunArgs, resp *Response) error { resp.ExitCode = 0 resp.Output = "Running new P2P instance for " + args.Hash + "\n" // Validate if interface name is unique if args.Dev != "" { instances_mut.Lock() for _, inst := range instances { if inst.PTP.DeviceName == args.Dev { resp.ExitCode = 1 resp.Output = "Device name is already in use" instances_mut.Unlock() runtime.Gosched() return errors.New(resp.Output) } } instances_mut.Unlock() runtime.Gosched() } var exists bool instances_mut.Lock() _, exists = instances[args.Hash] instances_mut.Unlock() runtime.Gosched() if !exists { resp.Output = resp.Output + "Lookup finished\n" if args.Key != "" { if len(args.Key) < 16 { args.Key += "0000000000000000"[:16-len(args.Key)] } else if len(args.Key) > 16 && len(args.Key) < 24 { args.Key += "000000000000000000000000"[:24-len(args.Key)] } else if len(args.Key) > 24 && len(args.Key) < 32 { args.Key += "00000000000000000000000000000000"[:32-len(args.Key)] } else if len(args.Key) > 32 { args.Key = args.Key[:32] } } var newInst instance newInst.ID = args.Hash newInst.Args = *args ptpInstance := ptp.StartP2PInstance(args.IP, args.Mac, args.Dev, "", args.Hash, args.Dht, args.Keyfile, args.Key, args.TTL, "", args.Fwd, args.Port) if ptpInstance == nil { resp.Output = resp.Output + "Failed to create P2P Instance" resp.ExitCode = 1 return errors.New("Failed to create P2P Instance") } ptp.Log(ptp.Info, "Instance created") newInst.PTP = ptpInstance instances_mut.Lock() instances[args.Hash] = newInst instances_mut.Unlock() runtime.Gosched() go ptpInstance.Run() if saveFile != "" { resp.Output = resp.Output + "Saving instance into file" saveInstances(saveFile) } } else { resp.Output = resp.Output + "Hash already in use\n" } return nil }