func join(x *cli.Context) { defer func() { if r := recover(); r != nil { fatalf("error, likely due to missing server or misspelled anchor: %v", r) } }() c := dial(x) args := x.Args() if len(args) != 2 { fatalf("join needs one anchor argument and one circuit address argument") } // Verify the target circuit address is valid if _, err := n.ParseAddr(args[1]); err != nil { fatalf("argument %q is not a valid circuit address", args[1]) } // w, _ := parseGlob(args[0]) switch u := c.Walk(w).Get().(type) { case client.Server: if err := u.Rejoin(args[1]); err != nil { fatalf("error: %v", err) } default: fatalf("not a server") } }
func (a *Assembler) AssembleServer(joinServer JoinFunc) { go a.scatter("server") go func() { gather := NewGather(a.multicast) for { _, payload := gather.Gather() trace, err := Decode(payload) if err != nil { log.Printf("Unrecognized trace message (%v)", err) continue } joinAddr, err := n.ParseAddr(trace.Addr) if err != nil { log.Printf("Trace origin address not parsing (%v)", err) continue } switch trace.Origin { case "server": joinServer(joinAddr) case "client": joinClient(a.addr, joinAddr) } } }() }
func (s *server) Rejoin(addr string) error { a, err := n.ParseAddr(addr) if err != nil { return err } return s.kin.ReJoin(a) }
// Dial establishes a connection to a circuit server specified by a circuit address. // Circuit addresses are printed to standard output when a server is started with the // "circuit start …" command. // Errors in communication, such as a missing server, or invalid URL format // are reported through panics. func Dial(addr string) *Client { _once.Do(_init) c := &Client{} w, err := n.ParseAddr(addr) if err != nil { panic("circuit address does not parse") } c.y = locus.YLocus{circuit.Dial(w, "locus")} return c }
func server(c *cli.Context) { println("CIRCUIT 2014 gocircuit.org") var err error if c.Bool("docker") { cmd, err := docker.Init() if err != nil { log.Fatalf("cannot use docker: %v", err) } log.Printf("Enabling docker elements, using %s", cmd) } // parse arguments var tcpaddr = parseAddr(c) // server bind address var join n.Addr // join address of another circuit server if c.IsSet("join") { if join, err = n.ParseAddr(c.String("join")); err != nil { log.Fatalf("join address does not parse (%s)", err) } } var multicast = parseDiscover(c) // server instance working directory var varDir string if !c.IsSet("var") { varDir = path.Join(os.TempDir(), fmt.Sprintf("%s-%%W-P%04d", n.Scheme, os.Getpid())) } else { varDir = c.String("var") } // start circuit runtime addr := load(tcpaddr, varDir, readkey(c)) // tissue + locus kin, xkin, rip := tissue.NewKin() xlocus := locus.NewLocus(kin, rip) // joining switch { case join != nil: kin.ReJoin(join) case multicast != nil: log.Printf("Using UDP multicast discovery on address %s", multicast.String()) go assemble.NewAssembler(addr, multicast).AssembleServer( func(joinAddr n.Addr) { kin.ReJoin(joinAddr) }, ) default: log.Println("Singleton server.") } circuit.Listen(tissue.ServiceName, xkin) circuit.Listen(LocusName, xlocus) <-(chan int)(nil) }
// Dial establishes a connection to a circuit server specified by a circuit address. // Circuit addresses are printed to standard output when a server is started with the // "circuit start …" command. // // If authkey is non-nil it is used as a private key and all communications are // secured by HMAC authentication and RC4 symmetric encryption; // otherwise transmissions are in plaintext. // // Errors in communication, such as a missing server, or invalid URL format // are reported through panics. func Dial(addr string, authkey []byte) *Client { _once.Do(func() { _init(authkey) }) c := &Client{} w, err := n.ParseAddr(addr) if err != nil { panic("circuit address does not parse") } c.y = locus.YLocus{circuit.Dial(w, "locus")} return c }
func server(c *cli.Context) { println("CIRCUIT 2014 gocircuit.org") log.Println("Starting circuit server") // parse arguments if !c.IsSet("addr") { log.Fatal("server network address not given; use -addr") } var err error var join n.Addr if c.IsSet("join") { if join, err = n.ParseAddr(c.String("join")); err != nil { log.Fatalf("join address does not parse (%s)", err) } } var mutexDir string if !c.IsSet("mutex") { mutexDir = path.Join(os.TempDir(), fmt.Sprintf("%s-%%W-P%04d", n.Scheme, os.Getpid())) } else { mutexDir = c.String("mutex") } // start circuit runtime load(c.String("addr"), mutexDir) // kinfolk join var xjoin circuit.PermX dontPanic(func() { xjoin = circuit.Dial(join, KinfolkName) }, "join") // locus kin, xkin, kinJoin, kinLeave := kinfolk.NewKin(xjoin) xlocus := locus.NewLocus(kin, kinJoin, kinLeave) circuit.Listen(KinfolkName, xkin) circuit.Listen(LocusName, xlocus) <-(chan int)(nil) }
// The child container can use /var as private scratch space. // The parent's binary directory is mounted under /vol/sup // // PARENT CHILD DESCRIPTION // ––––––––––––––––––––––– ––––––––––––––– –––––––––––––––––––––––––––––––––––––– // n/a /var Private child container scratch space // n/a /circuit Mount point for circuit file system // Binary directory /genus/bin // func (t *Snowflake) NewChamber(name, image string) (chmb *Chamber, err error) { t.Lock() defer t.Unlock() // chmb = &Chamber{ Name: name, Image: image, } // var cmd = []string{ "-d", "true", // Start container in daemon mode "-name", name, // Set container name "-p", strconv.Itoa(t.Config.Port), // Expose container's circuit port to host "-v", "/var", // Create data volume for scratch space "-v", fmt.Sprintf("%s:%s", t.ParentDir, path.Join(t.Config.Genus, "bin")), // Share binary directory of this worker image, // docker image to use for this container // // circuit worker binary and arguments follow // path.Join(t.Config.Genus, "bin", t.ParentBinary), // Re-use the same binary that started this process, by accessing its mount point "-a", fmt.Sprintf(":%d", t.Config.Port), // Set worker port; the bind IP is (later computed) based on default route from `ip -s route` "-j", t.Config.ParentURL, // Join child worker to this worker "-m", "/circuit", // Mount circuit on worker local file system. XXX: Prepare FUSE within image "-xfs", "/", // Share all of local file system (XXX: for now) "-parent", "XXX", // Name of parent worker } // Run container if chmb.ID, _, err = t.dcRun(cmd...); err != nil { return nil, err } chmb.ID = strings.TrimSpace(chmb.ID) // Read child worker URL from its stdout if chmb.URL, _, err = t.dcLogs(chmb.ID); err != nil { defer t.dcKill(chmb.ID) defer t.dcScrub(chmb.ID) return nil, err } // Parse URL into circuit worker address and save it chmb.URL = strings.TrimSpace(chmb.URL) if chmb.Addr, err = n.ParseAddr(chmb.URL); err != nil { defer t.dcKill(chmb.ID) defer t.dcScrub(chmb.ID) return nil, err } // Retrieve external port for container by invoking `docker port CONTAINER PORT` // _, _, err := t.dcport(chmb.ID, strconv.Itoa(t.Config.Port)) // if err != nil { // t.dcKill(chmb.ID) // t.dcScrub(chmb.ID) // return nil, err // } t.chamber[chmb.ID] = chmb go func() { // When container dies, scrub it form snowflake tables defer func() { // Scrubber t.Lock() defer t.Unlock() delete(t.chamber, chmb.ID) }() xx // wait for container to die }() // return chmb, nil }