func TestDoozerGetWithRev(t *testing.T) { var ( l = mustListen() u = mustListenUDP(l.Addr().String()) st = store.New(store.DefaultInitialRev) ) defer l.Close() defer u.Close() go Main("a", "X", "", "", "", nil, u, l, nil, 1e9, 2e9, 3e9, 101, st) cl := dial(l.Addr().String()) rev1, err := cl.Set("/x", store.Missing, []byte{'a'}) assert.Equal(t, nil, err) v, rev, err := cl.Get("/x", &rev1) // Use the snapshot. assert.Equal(t, nil, err) assert.Equal(t, rev1, rev) assert.Equal(t, []byte{'a'}, v) rev2, err := cl.Set("/x", rev, []byte{'b'}) assert.Equal(t, nil, err) v, rev, err = cl.Get("/x", nil) // Read the new value. assert.Equal(t, nil, err) assert.Equal(t, rev2, rev) assert.Equal(t, []byte{'b'}, v) v, rev, err = cl.Get("/x", &rev1) // Read the saved value again. assert.Equal(t, nil, err) assert.Equal(t, rev1, rev) assert.Equal(t, []byte{'a'}, v) }
func TestDoozerGet(t *testing.T) { var ( l = mustListen() u = mustListenUDP(l.Addr().String()) st = store.New(store.DefaultInitialRev) ) defer l.Close() defer u.Close() go Main("a", "X", "", "", "", nil, u, l, nil, 1e9, 2e9, 3e9, 101, st) cl := dial(l.Addr().String()) _, err := cl.Set("/x", store.Missing, []byte{'a'}) assert.Equal(t, nil, err) ents, rev, err := cl.Get("/x", nil) assert.Equal(t, nil, err) assert.NotEqual(t, store.Dir, rev) assert.Equal(t, []byte{'a'}, ents) //cl.Set("/test/a", store.Missing, []byte{'1'}) //cl.Set("/test/b", store.Missing, []byte{'2'}) //cl.Set("/test/c", store.Missing, []byte{'3'}) //ents, rev, err = cl.Get("/test", 0) //sort.SortStrings(ents) //assert.Equal(t, store.Dir, rev) //assert.Equal(t, nil, err) //assert.Equal(t, []string{"a", "b", "c"}, ents) }
func TestDoozerGetdirOffsetLimit(t *testing.T) { var ( l = mustListen() u = mustListenUDP(l.Addr().String()) st = store.New(store.DefaultInitialRev) ) defer l.Close() defer u.Close() go Main("a", "X", "", "", "", nil, u, l, nil, 1e9, 2e9, 3e9, 101, st) cl := dial(l.Addr().String()) cl.Set("/test/a", store.Clobber, []byte("1")) cl.Set("/test/b", store.Clobber, []byte("2")) cl.Set("/test/c", store.Clobber, []byte("3")) cl.Set("/test/d", store.Clobber, []byte("4")) rev, err := cl.Rev() if err != nil { panic(err) } names, err := cl.Getdir("/test", rev, 1, 2) assert.Equal(t, nil, err) assert.Equal(t, []string{"b", "c"}, names) }
func TestDoozerWaitWithRev(t *testing.T) { var ( l = mustListen() u = mustListenUDP(l.Addr().String()) st = store.New(store.DefaultInitialRev) ) defer l.Close() defer u.Close() go Main("a", "X", "", "", "", nil, u, l, nil, 1e9, 2e9, 3e9, 101, st) cl := dial(l.Addr().String()) // Create some history cl.Set("/test/foo", store.Clobber, []byte("bar")) cl.Set("/test/fun", store.Clobber, []byte("house")) ev, err := cl.Wait("/test/**", 1) assert.Equal(t, nil, err) assert.Equal(t, "/test/foo", ev.Path) assert.Equal(t, []byte("bar"), ev.Body) assert.T(t, ev.IsSet()) rev := ev.Rev + 1 ev, err = cl.Wait("/test/**", rev) assert.Equal(t, nil, err) assert.Equal(t, "/test/fun", ev.Path) assert.Equal(t, []byte("house"), ev.Body) assert.T(t, ev.IsSet()) }
func TestDoozerStat(t *testing.T) { var ( l = mustListen() u = mustListenUDP(l.Addr().String()) st = store.New(store.DefaultInitialRev) ) defer l.Close() defer u.Close() go Main("a", "X", "", "", "", nil, u, l, nil, 1e9, 2e9, 3e9, 101, st) cl := dial(l.Addr().String()) cl.Set("/test/foo", store.Clobber, []byte("bar")) setRev, _ := cl.Set("/test/fun", store.Clobber, []byte("house")) ln, rev, err := cl.Stat("/test", nil) assert.Equal(t, nil, err) assert.Equal(t, store.Dir, rev) assert.Equal(t, int(2), ln) ln, rev, err = cl.Stat("/test/fun", nil) assert.Equal(t, nil, err) assert.Equal(t, setRev, rev) assert.Equal(t, int(5), ln) }
func TestManagerPacketProcessing(t *testing.T) { st := store.New(store.DefaultInitialRev) defer close(st.Ops) in := make(chan Packet) out := make(chan Packet, 100) var m Manager m.run = make(map[int64]*run) m.Alpha = 1 m.Store = st m.In = in m.Out = out m.Ops = st.Ops st.Ops <- store.Op{1, store.MustEncodeSet(node+"/a/addr", "1.2.3.4:5", 0)} st.Ops <- store.Op{2, store.MustEncodeSet("/ctl/cal/0", "a", 0)} m.event(<-mustWait(st, 2)) addr, _ := net.ResolveUDPAddr("udp", "127.0.0.1:9999") recvPacket(&m.packet, Packet{ Addr: addr, Msg: Msg{Seqn: proto.Int64(2), Cmd: learn, Value: []byte("foo")}, }) m.pump() assert.Equal(t, 0, m.packet.Len()) }
func TestDoozerWaitSimple(t *testing.T) { var ( l = mustListen() st = store.New(store.DefaultInitialRev) ) defer l.Close() go Main("a", "X", nil, l, nil, st, 1e6) cl := dial(l.Addr().String()) var rev int64 = 1 cl.Set("/test/foo", store.Clobber, []byte("bar")) ev, err := cl.Wait("/test/**", rev) assert.Equal(t, nil, err) assert.Equal(t, "/test/foo", ev.Path) assert.Equal(t, []byte("bar"), ev.Body) assert.T(t, ev.IsSet()) rev = ev.Rev + 1 cl.Set("/test/fun", store.Clobber, []byte("house")) ev, err = cl.Wait("/test/**", rev) assert.Equal(t, nil, err) assert.Equal(t, "/test/fun", ev.Path) assert.Equal(t, []byte("house"), ev.Body) assert.T(t, ev.IsSet()) rev = ev.Rev + 1 cl.Del("/test/foo", store.Clobber) ev, err = cl.Wait("/test/**", rev) assert.Equal(t, nil, err) assert.Equal(t, "/test/foo", ev.Path) assert.T(t, ev.IsDel()) }
func TestManagerFilterPropSeqn(t *testing.T) { ps := make(chan int64, 100) st := store.New(store.DefaultInitialRev) defer close(st.Ops) m := &Manager{ DefRev: 2, Alpha: 1, Self: "b", PSeqn: ps, Store: st, } go m.Run() st.Ops <- store.Op{1, store.MustEncodeSet("/ctl/cal/0", "a", 0)} st.Ops <- store.Op{2, store.MustEncodeSet("/ctl/cal/1", "b", 0)} st.Ops <- store.Op{3, store.Nop} st.Ops <- store.Op{4, store.Nop} assert.Equal(t, int64(3), <-ps) assert.Equal(t, int64(5), <-ps) st.Ops <- store.Op{5, store.Nop} st.Ops <- store.Op{6, store.Nop} assert.Equal(t, int64(7), <-ps) }
func TestManagerEvent(t *testing.T) { const alpha = 2 runs := make(map[int64]*run) st := store.New(store.DefaultInitialRev) defer close(st.Ops) st.Ops <- store.Op{ Seqn: 1, Mut: store.MustEncodeSet(node+"/a/addr", "1.2.3.4:5", 0), } st.Ops <- store.Op{ Seqn: 2, Mut: store.MustEncodeSet(cal+"/1", "a", 0), } ch, err := st.Wait(store.Any, 2) if err != nil { panic(err) } x, _ := net.ResolveUDPAddr("udp", "1.2.3.4:5") pseqn := make(chan int64, 1) m := &Manager{ Alpha: alpha, Self: "a", PSeqn: pseqn, Ops: st.Ops, Out: make(chan Packet), run: runs, } m.event(<-ch) exp := &run{ self: "a", seqn: 2 + alpha, cals: []string{"a"}, addr: []*net.UDPAddr{x}, ops: st.Ops, out: m.Out, bound: initialWaitBound, } exp.c = coordinator{ crnd: 1, size: 1, quor: exp.quorum(), } exp.l = learner{ round: 1, size: 1, quorum: int64(exp.quorum()), votes: map[string]int64{}, voted: []bool{false}, } assert.Equal(t, 1, len(runs)) assert.Equal(t, exp, runs[exp.seqn]) assert.Equal(t, exp.seqn, <-pseqn) assert.Equal(t, exp.seqn+1, m.next) }
func TestConsensusOne(t *testing.T) { self := "test" const alpha = 1 st := store.New(store.DefaultInitialRev) st.Ops <- store.Op{1, store.MustEncodeSet("/ctl/node/"+self+"/addr", "1.2.3.4:5", 0)} st.Ops <- store.Op{2, store.MustEncodeSet("/ctl/cal/1", self, 0)} <-st.Seqns in := make(chan Packet) out := make(chan Packet) seqns := make(chan int64, alpha) props := make(chan *Prop) m := &Manager{ Self: self, DefRev: 2, Alpha: alpha, In: in, Out: out, Ops: st.Ops, PSeqn: seqns, Props: props, TFill: 10e9, Store: st, Ticker: time.Tick(10e6), } go m.Run() go func() { for o := range out { in <- o } }() n := <-seqns w, err := st.Wait(store.Any, n) if err != nil { panic(err) } props <- &Prop{n, []byte("foo")} e := <-w exp := store.Event{ Seqn: 3, Path: "/ctl/err", Body: "bad mutation", Rev: 3, Mut: "foo", Err: errors.New("bad mutation"), } e.Getter = nil assert.Equal(t, exp, e) }
func TestGetCalsPartial(t *testing.T) { st := store.New(store.DefaultInitialRev) defer close(st.Ops) st.Ops <- store.Op{Seqn: 1, Mut: store.MustEncodeSet(cal+"/1", "a", 0)} st.Ops <- store.Op{Seqn: 2, Mut: store.MustEncodeSet(cal+"/2", "", 0)} st.Ops <- store.Op{Seqn: 3, Mut: store.MustEncodeSet(cal+"/3", "", 0)} <-st.Seqns assert.Equal(t, []string{"a"}, getCals(st)) }
func TestDoozerNop(t *testing.T) { var ( l = mustListen() st = store.New(store.DefaultInitialRev) ) defer l.Close() go Main("a", "X", nil, l, nil, st, 1e6) cl := dial(l.Addr().String()) err := cl.Nop() assert.Equal(t, nil, err) }
func TestGetAddrs(t *testing.T) { st := store.New(store.DefaultInitialRev) defer close(st.Ops) st.Ops <- store.Op{1, store.MustEncodeSet(node+"/1/addr", "1.2.3.4:5", 0)} st.Ops <- store.Op{2, store.MustEncodeSet(node+"/2/addr", "2.3.4.5:6", 0)} st.Ops <- store.Op{3, store.MustEncodeSet(node+"/3/addr", "3.4.5.6:7", 0)} <-st.Seqns x, _ := net.ResolveUDPAddr("udp", "1.2.3.4:5") y, _ := net.ResolveUDPAddr("udp", "2.3.4.5:6") z, _ := net.ResolveUDPAddr("udp", "3.4.5.6:7") addrs := getAddrs(st, []string{"1", "2", "3"}) assert.Equal(t, []*net.UDPAddr{x, y, z}, addrs) }
func TestManagerPumpDropsOldPackets(t *testing.T) { st := store.New(store.DefaultInitialRev) defer close(st.Ops) x, _ := net.ResolveUDPAddr("udp", "1.2.3.4:5") st.Ops <- store.Op{1, store.MustEncodeSet(node+"/a/addr", "1.2.3.4:5", 0)} st.Ops <- store.Op{2, store.MustEncodeSet("/ctl/cal/0", "a", 0)} var m Manager m.run = make(map[int64]*run) m.event(<-mustWait(st, 2)) m.pump() recvPacket(&m.packet, Packet{x, Msg{Seqn: proto.Int64(1)}}) m.pump() assert.Equal(t, 0, m.Stats.WaitPackets) }
func TestMemberSimple(t *testing.T) { st := store.New(store.DefaultInitialRev) defer close(st.Ops) fp := &test.FakeProposer{Store: st} c := make(chan string) go Clean(c, fp.Store, fp) fp.Propose([]byte(store.MustEncodeSet("/ctl/node/a/x", "a", store.Missing))) fp.Propose([]byte(store.MustEncodeSet("/ctl/node/a/y", "b", store.Missing))) fp.Propose([]byte(store.MustEncodeSet("/ctl/node/a/addr", "1.2.3.4", store.Missing))) fp.Propose([]byte(store.MustEncodeSet("/ctl/cal/0", "a", store.Missing))) calCh, err := fp.Wait(store.MustCompileGlob("/ctl/cal/0"), 1+<-fp.Seqns) if err != nil { panic(err) } nodeCh, err := fp.Wait(store.MustCompileGlob("/ctl/node/a/?"), 1+<-fp.Seqns) if err != nil { panic(err) } // indicate that this peer is inactive go func() { c <- "1.2.3.4" }() ev := <-calCh assert.T(t, ev.IsSet()) assert.Equal(t, "", ev.Body) cs := []int{} ev = <-nodeCh assert.T(t, ev.IsDel()) cs = append(cs, int(ev.Path[len(ev.Path)-1])) nodeCh, err = fp.Wait(store.MustCompileGlob("/ctl/node/a/?"), ev.Seqn+1) if err != nil { panic(err) } ev = <-nodeCh assert.T(t, ev.IsDel()) cs = append(cs, int(ev.Path[len(ev.Path)-1])) sort.Ints(cs) assert.Equal(t, []int{'x', 'y'}, cs) }
func TestDoozerGet(t *testing.T) { var ( l = mustListen() st = store.New(store.DefaultInitialRev) ) defer l.Close() go Main("a", "X", nil, l, nil, st, 1e6) cl := dial(l.Addr().String()) _, err := cl.Set("/x", store.Missing, []byte{'a'}) assert.Equal(t, nil, err) ents, rev, err := cl.Get("/x", nil) assert.Equal(t, nil, err) assert.NotEqual(t, store.Dir, rev) assert.Equal(t, []byte{'a'}, ents) }
func TestDoozerSet(t *testing.T) { var ( l = mustListen() st = store.New(store.DefaultInitialRev) ) defer l.Close() go Main("a", "X", nil, l, nil, st, 1e6) cl := dial(l.Addr().String()) for i := byte(0); i < 10; i++ { _, err := cl.Set("/x", store.Clobber, []byte{'0' + i}) assert.Equal(t, nil, err) } _, err := cl.Set("/x", 0, []byte{'X'}) assert.Equal(t, &doozer.Error{doozer.ErrOldRev, ""}, err) }
func TestDelRun(t *testing.T) { const alpha = 2 runs := make(map[int64]*run) st := store.New(store.DefaultInitialRev) defer close(st.Ops) st.Ops <- store.Op{1, store.MustEncodeSet(node+"/a/addr", "x", 0)} st.Ops <- store.Op{2, store.MustEncodeSet(cal+"/1", "a", 0)} st.Ops <- store.Op{3, store.Nop} st.Ops <- store.Op{4, store.Nop} c2, err := st.Wait(store.Any, 2) if err != nil { panic(err) } c3, err := st.Wait(store.Any, 3) if err != nil { panic(err) } c4, err := st.Wait(store.Any, 4) if err != nil { panic(err) } pseqn := make(chan int64, 100) m := &Manager{ Alpha: alpha, Self: "a", PSeqn: pseqn, Ops: st.Ops, Out: make(chan Packet), run: runs, } m.event(<-c2) assert.Equal(t, 1, len(m.run)) m.event(<-c3) assert.Equal(t, 2, len(m.run)) m.event(<-c4) assert.Equal(t, 2, len(m.run)) }
func TestDoozerGetdirMissing(t *testing.T) { var ( l = mustListen() st = store.New(store.DefaultInitialRev) ) defer l.Close() go Main("a", "X", nil, l, nil, st, 1e6) cl := dial(l.Addr().String()) rev, err := cl.Rev() if err != nil { panic(err) } names, err := cl.Getdir("/not/here", rev, 0, -1) assert.Equal(t, &doozer.Error{doozer.ErrNoEnt, ""}, err) assert.Equal(t, []string(nil), names) }
func TestManagerTickQueue(t *testing.T) { st := store.New(store.DefaultInitialRev) defer close(st.Ops) st.Ops <- store.Op{1, store.MustEncodeSet(node+"/a/addr", "1.2.3.4:5", 0)} st.Ops <- store.Op{2, store.MustEncodeSet("/ctl/cal/0", "a", 0)} var m Manager m.run = make(map[int64]*run) m.Alpha = 1 m.Store = st m.Out = make(chan Packet, 100) m.event(<-mustWait(st, 2)) // get it to tick for seqn 3 recvPacket(&m.packet, Packet{Msg: Msg{Seqn: proto.Int64(3), Cmd: propose}}) m.pump() assert.Equal(t, 1, m.tick.Len()) m.doTick(time.Now().UnixNano() + initialWaitBound*2) assert.Equal(t, int64(1), m.Stats.TotalTicks) }
func TestGcClean(t *testing.T) { st := store.New(store.DefaultInitialRev) defer close(st.Ops) ticker := make(chan time.Time) defer close(ticker) go Clean(st, 3, ticker) st.Ops <- store.Op{1, store.Nop} st.Ops <- store.Op{2, store.Nop} st.Ops <- store.Op{3, store.Nop} st.Ops <- store.Op{4, store.Nop} _, err := st.Wait(store.Any, 1) assert.Equal(t, nil, err) ticker <- time.Unix(0, 1) ticker <- time.Unix(0, 1) // Extra tick to ensure the last st.Clean has completed _, err = st.Wait(store.Any, 1) assert.Equal(t, store.ErrTooLate, err) }
func TestServerNoAccess(t *testing.T) { b := make(bchan, 2) c := &conn{ c: b, canWrite: true, st: store.New(store.DefaultInitialRev), } tx := &txn{ c: c, req: Request{Tag: proto.Int32(1)}, } for i, op := range ops { if i != int32(Request_ACCESS) { op(tx) var exp Response_Err = Response_OTHER assert.Equal(t, 4, len(<-b), Request_Verb_name[i]) assert.Equal(t, &exp, mustUnmarshal(<-b).ErrCode, Request_Verb_name[i]) } } }
func TestDoozerGetdirOnFile(t *testing.T) { var ( l = mustListen() st = store.New(store.DefaultInitialRev) ) defer l.Close() go Main("a", "X", nil, l, nil, st, 1e6) cl := dial(l.Addr().String()) cl.Set("/test/a", store.Clobber, []byte("1")) rev, err := cl.Rev() if err != nil { panic(err) } names, err := cl.Getdir("/test/a", rev, 0, -1) assert.Equal(t, &doozer.Error{doozer.ErrNotDir, ""}, err) assert.Equal(t, []string(nil), names) }
func TestServerRo(t *testing.T) { b := make(bchan, 2) c := &conn{ c: b, canWrite: true, st: store.New(store.DefaultInitialRev), } tx := &txn{ c: c, req: Request{Tag: proto.Int32(1)}, } wops := []int32{int32(Request_DEL), int32(Request_NOP), int32(Request_SET)} for _, i := range wops { op := ops[i] op(tx) var exp Response_Err = Response_OTHER assert.Equal(t, 4, len(<-b), Request_Verb_name[i]) assert.Equal(t, &exp, mustUnmarshal(<-b).ErrCode, Request_Verb_name[i]) } }
func TestDoozerGetdirOnDir(t *testing.T) { var ( l = mustListen() st = store.New(store.DefaultInitialRev) ) defer l.Close() go Main("a", "X", nil, l, nil, st, 1e6) cl := dial(l.Addr().String()) cl.Set("/test/a", store.Clobber, []byte("1")) cl.Set("/test/b", store.Clobber, []byte("2")) cl.Set("/test/c", store.Clobber, []byte("3")) rev, err := cl.Rev() if err != nil { panic(err) } got, err := cl.Getdir("/test", rev, 0, -1) assert.Equal(t, nil, err) assert.Equal(t, []string{"a", "b", "c"}, got) }
func TestConsensusTwo(t *testing.T) { a := "a" b := "b" x, _ := net.ResolveUDPAddr("udp", "1.2.3.4:5") xs := "1.2.3.4:5" y, _ := net.ResolveUDPAddr("udp", "2.3.4.5:6") ys := "2.3.4.5:6" const alpha = 1 st := store.New(store.DefaultInitialRev) st.Ops <- store.Op{1, store.Nop} st.Ops <- store.Op{2, store.MustEncodeSet("/ctl/node/a/addr", xs, 0)} st.Ops <- store.Op{3, store.MustEncodeSet("/ctl/cal/1", a, 0)} st.Ops <- store.Op{4, store.MustEncodeSet("/ctl/node/b/addr", ys, 0)} st.Ops <- store.Op{5, store.MustEncodeSet("/ctl/cal/2", b, 0)} ain := make(chan Packet) aout := make(chan Packet) aseqns := make(chan int64, alpha) aprops := make(chan *Prop) am := &Manager{ Self: a, DefRev: 5, Alpha: alpha, In: ain, Out: aout, Ops: st.Ops, PSeqn: aseqns, Props: aprops, TFill: 10e9, Store: st, Ticker: time.Tick(10e6), } go am.Run() bin := make(chan Packet) bout := make(chan Packet) bseqns := make(chan int64, alpha) bprops := make(chan *Prop) bm := &Manager{ Self: b, DefRev: 5, Alpha: alpha, In: bin, Out: bout, Ops: st.Ops, PSeqn: bseqns, Props: bprops, TFill: 10e9, Store: st, Ticker: time.Tick(10e6), } go bm.Run() go func() { for o := range aout { if o.Addr.Port == x.Port && o.Addr.IP.Equal(x.IP) { go func(o Packet) { ain <- o }(o) } else { o.Addr = x go func(o Packet) { bin <- o }(o) } } }() go func() { for o := range bout { if o.Addr.Port == y.Port && o.Addr.IP.Equal(y.IP) { go func(o Packet) { bin <- o }(o) } else { o.Addr = y go func(o Packet) { ain <- o }(o) } } }() n := <-aseqns assert.Equal(t, int64(6), n) w, err := st.Wait(store.Any, n) if err != nil { panic(err) } aprops <- &Prop{n, []byte("foo")} e := <-w exp := store.Event{ Seqn: 6, Path: "/ctl/err", Body: "bad mutation", Rev: 6, Mut: "foo", Err: errors.New("bad mutation"), } e.Getter = nil assert.Equal(t, exp, e) }
func main() { *buri = os.Getenv("DOOZER_BOOT_URI") flag.Usage = Usage flag.Parse() if *showVersion { fmt.Println("doozerd", peer.Version) return } if *laddr == "" { fmt.Fprintln(os.Stderr, "require a listen address") flag.Usage() os.Exit(1) } log.SetPrefix("DOOZER ") log.SetFlags(log.Ldate | log.Lmicroseconds | log.Lshortfile) tsock, err := net.Listen("tcp", *laddr) if err != nil { panic(err) } if *certFile != "" || *keyFile != "" { tsock = tlsWrap(tsock, *certFile, *keyFile) } uaddr, err := net.ResolveUDPAddr("udp", *laddr) if err != nil { panic(err) } usock, err := net.ListenUDP("udp", uaddr) if err != nil { panic(err) } var wsock net.Listener if *waddr == "" { wa, err := net.ResolveTCPAddr("tcp", *laddr) if err != nil { panic(err) } wa.Port = defWebPort *waddr = wa.String() } if b, err := strconv.ParseBool(*waddr); err != nil && !b { wsock, err = net.Listen("tcp", *waddr) if err != nil { panic(err) } } id := randId() var cl *doozer.Conn switch { case len(aaddrs) > 0 && *buri != "": cl = attach(*name, aaddrs) if cl == nil { cl = boot(*name, id, *laddr, *buri) } case len(aaddrs) > 0: cl = attach(*name, aaddrs) if cl == nil { panic("failed to attach") } case *buri != "": cl = boot(*name, id, *laddr, *buri) } st := store.New(*rev) if *soloMode { solo.Main( *name, id, cl, tsock, wsock, st, *hi, ) } else { peer.Main( *name, id, *buri, rwsk, rosk, cl, usock, tsock, wsock, ns(*pi), ns(*fd), ns(*kt), *hi, st, ) } panic("main exit") }