예제 #1
0
파일: bson_test.go 프로젝트: gs412/mgo
func (s *S) TestUnmarshalAllItemsWithPtrSetter(c *C) {
	for _, item := range allItems {
		for i := 0; i != 2; i++ {
			var field *setterType
			if i == 0 {
				obj := &ptrSetterDoc{}
				err := bson.Unmarshal([]byte(wrapInDoc(item.data)), obj)
				c.Assert(err, IsNil)
				field = obj.Field
			} else {
				obj := &valSetterDoc{}
				err := bson.Unmarshal([]byte(wrapInDoc(item.data)), obj)
				c.Assert(err, IsNil)
				field = &obj.Field
			}
			if item.data == "" {
				// Nothing to unmarshal. Should be untouched.
				if i == 0 {
					c.Assert(field, IsNil)
				} else {
					c.Assert(field.received, IsNil)
				}
			} else {
				expected := item.obj.(bson.M)["_"]
				c.Assert(field, NotNil, Commentf("Pointer not initialized (%#v)", expected))
				c.Assert(field.received, DeepEquals, expected)
			}
		}
	}
}
예제 #2
0
파일: bson_test.go 프로젝트: gs412/mgo
func (s *S) TestUnmarshalMapDocumentTooShort(c *C) {
	for _, data := range corruptedData {
		err := bson.Unmarshal([]byte(data), bson.M{})
		c.Assert(err, ErrorMatches, "Document is corrupted")

		err = bson.Unmarshal([]byte(data), &struct{}{})
		c.Assert(err, ErrorMatches, "Document is corrupted")
	}
}
예제 #3
0
func (d *Decoder) Decode(pv interface{}) (err error) {
	var lbuf [4]byte
	n, err := d.r.Read(lbuf[:])
	if n == 0 {
		err = io.EOF
		return
	}
	if n != 4 {
		err = errors.New(fmt.Sprintf("Corrupted BSON stream: could only read %d", n))
		return
	}
	if err != nil {
		return
	}

	length := (int(lbuf[0]) << 0) |
		(int(lbuf[1]) << 8) |
		(int(lbuf[2]) << 16) |
		(int(lbuf[3]) << 24)

	buf := make([]byte, length)
	copy(buf[0:4], lbuf[:])
	_, err = d.r.Read(buf[4:])
	if err != nil {
		return
	}

	err = bson.Unmarshal(buf, pv)

	return
}
예제 #4
0
파일: bson_test.go 프로젝트: gs412/mgo
func (s *S) TestUnmarshalZeroesMap(c *C) {
	data, err := bson.Marshal(bson.M{"b": 2})
	c.Assert(err, IsNil)
	m := bson.M{"a": 1}
	err = bson.Unmarshal(data, &m)
	c.Assert(err, IsNil)
	c.Assert(m, DeepEquals, bson.M{"b": 2})
}
예제 #5
0
파일: bson_test.go 프로젝트: gs412/mgo
func (s *S) TestUnmarshalNilInStruct(c *C) {
	// Nil is the default value, so we need to ensure it's indeed being set.
	b := byte(1)
	v := &struct{ Ptr *byte }{&b}
	err := bson.Unmarshal([]byte(wrapInDoc("\x0Aptr\x00")), v)
	c.Assert(err, IsNil)
	c.Assert(v, DeepEquals, &struct{ Ptr *byte }{nil})
}
예제 #6
0
파일: bson_test.go 프로젝트: gs412/mgo
func (s *S) TestUnmarshalSampleItems(c *C) {
	for i, item := range sampleItems {
		value := bson.M{}
		err := bson.Unmarshal([]byte(item.data), value)
		c.Assert(err, IsNil)
		c.Assert(value, DeepEquals, item.obj, Commentf("Failed on item %d", i))
	}
}
예제 #7
0
파일: bson_test.go 프로젝트: gs412/mgo
func (s *S) TestMarshalShortWithGetter(c *C) {
	obj := typeWithIntGetter{42}
	data, err := bson.Marshal(obj)
	c.Assert(err, IsNil)
	m := bson.M{}
	err = bson.Unmarshal(data, m)
	c.Assert(m["v"], Equals, 42)
}
예제 #8
0
파일: gridfs.go 프로젝트: hfeeki/mgo
// GetMeta unmarshals the optional "metadata" field associated with the
// file into the result parameter. The meaning of keys under that field
// is user-defined. For example:
//
//     result := struct{ INode int }{}
//     err = file.GetMeta(&result)
//     if err != nil {
//         panic(err.String())
//     }
//     fmt.Printf("inode: %d\n", result.INode)
//
func (file *GridFile) GetMeta(result interface{}) (err error) {
	file.m.Lock()
	if file.doc.Metadata != nil {
		err = bson.Unmarshal(file.doc.Metadata.Data, result)
	}
	file.m.Unlock()
	return
}
예제 #9
0
파일: bson_test.go 프로젝트: gs412/mgo
func (s *S) TestUnmarshalAllItems(c *C) {
	for i, item := range allItems {
		value := bson.M{}
		err := bson.Unmarshal([]byte(wrapInDoc(item.data)), value)
		c.Assert(err, IsNil)
		c.Assert(value, DeepEquals, item.obj, Commentf("Failed on item %d: %#v", i, item))
	}
}
예제 #10
0
파일: bson_test.go 프로젝트: gs412/mgo
func (s *S) TestUnmarshalZeroesStruct(c *C) {
	data, err := bson.Marshal(bson.M{"b": 2})
	c.Assert(err, IsNil)
	type T struct{ A, B int }
	v := T{A: 1}
	err = bson.Unmarshal(data, &v)
	c.Assert(err, IsNil)
	c.Assert(v.A, Equals, 0)
	c.Assert(v.B, Equals, 2)
}
예제 #11
0
파일: bson_test.go 프로젝트: gs412/mgo
func (s *S) TestUnmarshalNonNilInterface(c *C) {
	data, err := bson.Marshal(bson.M{"b": 2})
	c.Assert(err, IsNil)
	m := bson.M{"a": 1}
	var i interface{}
	i = m
	err = bson.Unmarshal(data, &i)
	c.Assert(err, IsNil)
	c.Assert(i, DeepEquals, bson.M{"b": 2})
	c.Assert(m, DeepEquals, bson.M{"a": 1})
}
예제 #12
0
파일: flusher.go 프로젝트: gs412/mgo
func objToDoc(obj interface{}) (d bson.D, err error) {
	data, err := bson.Marshal(obj)
	if err != nil {
		return nil, err
	}
	err = bson.Unmarshal(data, &d)
	if err != nil {
		return nil, err
	}
	return d, err
}
예제 #13
0
파일: bson_test.go 프로젝트: gs412/mgo
func testCrossPair(c *C, dump interface{}, load interface{}) {
	c.Logf("Dump: %#v", dump)
	c.Logf("Load: %#v", load)
	zero := makeZeroDoc(load)
	data, err := bson.Marshal(dump)
	c.Assert(err, IsNil)
	c.Logf("Dumped: %#v", string(data))
	err = bson.Unmarshal(data, zero)
	c.Assert(err, IsNil)
	c.Logf("Loaded: %#v", zero)
	c.Assert(zero, DeepEquals, load)
}
예제 #14
0
파일: bson_test.go 프로젝트: gs412/mgo
func BenchmarkUnmarhsalStruct(b *testing.B) {
	v := BenchT{A: "A", D: "D", E: "E"}
	data, err := bson.Marshal(&v)
	if err != nil {
		panic(err)
	}
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		err = bson.Unmarshal(data, &v)
	}
	if err != nil {
		panic(err)
	}
}
예제 #15
0
파일: bson_test.go 프로젝트: gs412/mgo
func BenchmarkUnmarhsalMap(b *testing.B) {
	m := bson.M{"a": "a", "d": "d", "e": "e"}
	data, err := bson.Marshal(&m)
	if err != nil {
		panic(err)
	}
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		err = bson.Unmarshal(data, &m)
	}
	if err != nil {
		panic(err)
	}
}
예제 #16
0
파일: bson_test.go 프로젝트: gs412/mgo
func (s *S) TestUnmarshalSetterSetZero(c *C) {
	setterResult["foo"] = bson.SetZero
	defer delete(setterResult, "field")

	data, err := bson.Marshal(bson.M{"field": "foo"})
	c.Assert(err, IsNil)

	m := map[string]*setterType{}
	err = bson.Unmarshal([]byte(data), m)
	c.Assert(err, IsNil)

	value, ok := m["field"]
	c.Assert(ok, Equals, true)
	c.Assert(value, IsNil)
}
예제 #17
0
파일: bson_test.go 프로젝트: gs412/mgo
func (s *S) TestUnmarshalErrorItems(c *C) {
	for _, item := range unmarshalErrorItems {
		data := []byte(wrapInDoc(item.data))
		var value interface{}
		switch reflect.ValueOf(item.obj).Kind() {
		case reflect.Map, reflect.Ptr:
			value = makeZeroDoc(item.obj)
		case reflect.Invalid:
			value = bson.M{}
		default:
			value = item.obj
		}
		err := bson.Unmarshal(data, value)
		c.Assert(err, ErrorMatches, item.error)
	}
}
예제 #18
0
func TestServiceRPCBasic(t *testing.T) {
	var addr net.Addr

	config := &skynet.ServiceConfig{}
	service := CreateService(EchoRPC{}, config)
	service.ClientInfo = make(map[string]ClientInfo, 1)

	addr = &net.TCPAddr{
		IP:   net.ParseIP("127.0.0.1"),
		Port: 123,
	}

	service.ClientInfo["123"] = ClientInfo{
		Address: addr,
	}

	srpc := NewServiceRPC(service)

	in := M{"Hi": "there"}
	out := &M{}

	sin := skynet.ServiceRPCIn{
		RequestInfo: &skynet.RequestInfo{
			RequestID:         "id",
			OriginAddress:     addr.String(),
			ConnectionAddress: addr.String(),
		},
		Method:   "Foo",
		ClientID: "123",
	}

	sin.In, _ = bson.Marshal(in)

	sout := skynet.ServiceRPCOut{}

	err := srpc.Forward(sin, &sout)
	if err != nil {
		t.Error(err)
	}

	bson.Unmarshal(sout.Out, out)

	if v, ok := (*out)["Hi"].(string); !ok || v != "there" {
		t.Error(fmt.Sprintf("Expected %v, got %v", in, *out))
	}
}
예제 #19
0
파일: bson_test.go 프로젝트: gs412/mgo
func (s *S) TestUnmarshalSetterErrors(c *C) {
	boom := errors.New("BOOM")
	setterResult["2"] = boom
	defer delete(setterResult, "2")

	m := map[string]*setterType{}
	data := wrapInDoc("\x02abc\x00\x02\x00\x00\x001\x00" +
		"\x02def\x00\x02\x00\x00\x002\x00" +
		"\x02ghi\x00\x02\x00\x00\x003\x00")
	err := bson.Unmarshal([]byte(data), m)
	c.Assert(err, Equals, boom)
	c.Assert(m["abc"], NotNil)
	c.Assert(m["def"], IsNil)
	c.Assert(m["ghi"], IsNil)

	c.Assert(m["abc"].received, Equals, "1")
}
예제 #20
0
파일: auth.go 프로젝트: hfeeki/mgo
func (socket *mongoSocket) resetNonce() {
	debugf("Socket %p to %s: requesting a new nonce", socket, socket.addr)
	op := &queryOp{}
	op.query = &getNonceCmd{GetNonce: 1}
	op.collection = "admin.$cmd"
	op.limit = -1
	op.replyFunc = func(err error, reply *replyOp, docNum int, docData []byte) {
		if err != nil {
			socket.kill(errors.New("getNonce: "+err.Error()), true)
			return
		}
		result := &getNonceResult{}
		err = bson.Unmarshal(docData, &result)
		if err != nil {
			socket.kill(errors.New("Failed to unmarshal nonce: "+err.Error()), true)
			return
		}
		debugf("Socket %p to %s: nonce unmarshalled: %#v", socket, socket.addr, result)
		if result.Code == 13390 {
			// mongos doesn't yet support auth (see http://j.mp/mongos-auth)
			result.Nonce = "mongos"
		} else if result.Nonce == "" {
			var msg string
			if result.Err != "" {
				msg = fmt.Sprintf("Got an empty nonce: %s (%d)", result.Err, result.Code)
			} else {
				msg = "Got an empty nonce"
			}
			socket.kill(errors.New(msg), true)
			return
		}
		socket.Lock()
		if socket.cachedNonce != "" {
			socket.Unlock()
			panic("resetNonce: nonce already cached")
		}
		socket.cachedNonce = result.Nonce
		socket.gotNonce.Signal()
		socket.Unlock()
	}
	err := socket.Query(op)
	if err != nil {
		socket.kill(errors.New("resetNonce: "+err.Error()), true)
	}
}
예제 #21
0
파일: bson_test.go 프로젝트: gs412/mgo
func (s *S) TestUnmarshalSetterOmits(c *C) {
	setterResult["2"] = &bson.TypeError{}
	setterResult["4"] = &bson.TypeError{}
	defer func() {
		delete(setterResult, "2")
		delete(setterResult, "4")
	}()

	m := map[string]*setterType{}
	data := wrapInDoc("\x02abc\x00\x02\x00\x00\x001\x00" +
		"\x02def\x00\x02\x00\x00\x002\x00" +
		"\x02ghi\x00\x02\x00\x00\x003\x00" +
		"\x02jkl\x00\x02\x00\x00\x004\x00")
	err := bson.Unmarshal([]byte(data), m)
	c.Assert(err, IsNil)
	c.Assert(m["abc"], NotNil)
	c.Assert(m["def"], IsNil)
	c.Assert(m["ghi"], NotNil)
	c.Assert(m["jkl"], IsNil)

	c.Assert(m["abc"].received, Equals, "1")
	c.Assert(m["ghi"].received, Equals, "3")
}
예제 #22
0
// ServiceRPC.Forward is the entry point for RPC calls. It wraps actual RPC calls
// and provides a slot for the RequestInfo. The parameters to the actual RPC
// calls are transmitted in a []byte, and are then marshalled/unmarshalled on
// either end.
func (srpc *ServiceRPC) Forward(in skynet.ServiceRPCIn, out *skynet.ServiceRPCOut) (err error) {
	srpc.service.activeRequests.Add(1)
	defer srpc.service.activeRequests.Done()

	srpc.service.Delegate.MethodCalled(in.Method)

	clientInfo, ok := srpc.service.getClientInfo(in.ClientID)
	if !ok {
		err = errors.New("did not provide the ClientID")
		return
	}

	in.RequestInfo.ConnectionAddress = clientInfo.Address.String()
	if in.RequestInfo.OriginAddress == "" || !srpc.service.IsTrusted(clientInfo.Address) {
		in.RequestInfo.OriginAddress = in.RequestInfo.ConnectionAddress
	}

	mc := MethodCall{
		MethodName:  in.Method,
		RequestInfo: in.RequestInfo,
	}

	if srpc.service.Log != nil {
		srpc.service.Log.Trace(fmt.Sprintf("%+v", mc))
	}

	m, ok := srpc.methods[in.Method]
	if !ok {
		err = errors.New(fmt.Sprintf("No such method %q", in.Method))
		return
	}

	inValuePtr := reflect.New(m.Type().In(2))

	err = bson.Unmarshal(in.In, inValuePtr.Interface())
	if err != nil {
		return
	}

	// Allocate the out parameter of the RPC call.
	outType := m.Type().In(3)
	var outValue reflect.Value

	switch outType.Kind() {
	case reflect.Ptr:
		outValue = reflect.New(m.Type().In(3).Elem())
	case reflect.Map:
		outValue = reflect.MakeMap(outType)
	default:
		panic("illegal out param type")
	}

	srpc.service.Stats.LastRequest = time.Now().Format("2006-01-02T15:04:05Z-0700")

	startTime := time.Now().UnixNano()

	params := []reflect.Value{
		reflect.ValueOf(srpc.service.Delegate),
		reflect.ValueOf(in.RequestInfo),
		inValuePtr.Elem(),
		outValue,
	}

	returns := m.Call(params)

	duration := time.Now().UnixNano() - startTime

	// Update stats
	atomic.AddInt64(&srpc.service.Stats.RequestsServed, 1)
	atomic.AddInt64((*int64)(&srpc.service.Stats.TotalDuration), int64(duration)) // ns

	srpc.service.Stats.AverageResponseTime = srpc.service.Stats.TotalDuration / time.Duration(srpc.service.Stats.RequestsServed)

	mcp := MethodCompletion{
		MethodName:  in.Method,
		RequestInfo: in.RequestInfo,
		Duration:    duration,
	}

	if srpc.service.Log != nil {
		srpc.service.Log.Trace(fmt.Sprintf("%+v", mcp))
	}

	out.Out, err = bson.Marshal(outValue.Interface())
	if err != nil {
		return
	}

	erri := returns[0].Interface()
	var rerr error
	if erri != nil {
		rerr, _ := erri.(error)
		out.ErrString = rerr.Error()
	}
	srpc.service.Delegate.MethodCompleted(in.Method, duration, rerr)

	return
}
예제 #23
0
func (c *ServiceClient) send(retry, giveup time.Duration, ri *skynet.RequestInfo, fn string, in interface{}, out interface{}) (err error) {
	if ri == nil {
		ri = &skynet.RequestInfo{
			RequestID: skynet.UUID(),
		}
	}

	attempts := make(chan sendAttempt)

	var ticker <-chan time.Time
	if retry > 0 {
		ticker = time.NewTicker(retry).C
	}

	var timeout <-chan time.Time
	if giveup > 0 {
		timeout = time.NewTimer(giveup).C
	}

	doneSignal := make(chan bool)
	attemptCount := 1

	defer func() {
		go func() {
			for i := 0; i < attemptCount; i++ {
				doneSignal <- true
			}
		}()
	}()

	go c.attemptSend(doneSignal, attempts, ri, fn, in)

	for {
		select {
		case <-ticker:
			attemptCount++
			ri.RetryCount++

			go c.attemptSend(doneSignal, attempts, ri, fn, in)
		case <-timeout:
			if err == nil {
				err = ErrRequestTimeout
			}
			// otherwise use the last error reported from an attempt
			return
		case attempt := <-attempts:
			err = attempt.err
			if err != nil {
				if _, ok := err.(serviceError); !ok {
					// error during transmition, abort this attempt
					if giveup == 0 {
						return
					}
					continue
				}
			}

			unmarshallerr := bson.Unmarshal(attempt.result, out)
			if unmarshallerr != nil {
				err = unmarshallerr
			}
			return
		}
	}

	return
}
예제 #24
0
파일: bson_test.go 프로젝트: gs412/mgo
func testUnmarshal(c *C, data string, obj interface{}) {
	zero := makeZeroDoc(obj)
	err := bson.Unmarshal([]byte(data), zero)
	c.Assert(err, IsNil)
	c.Assert(zero, DeepEquals, obj)
}
예제 #25
0
파일: bson_test.go 프로젝트: gs412/mgo
func (s *S) TestUnmarshalWholeDocumentWithSetter(c *C) {
	obj := &setterType{}
	err := bson.Unmarshal([]byte(sampleItems[0].data), obj)
	c.Assert(err, IsNil)
	c.Assert(obj.received, DeepEquals, bson.M{"hello": "world"})
}
예제 #26
0
파일: auth.go 프로젝트: hfeeki/mgo
func (socket *mongoSocket) Login(db string, user string, pass string) error {
	socket.Lock()
	for _, a := range socket.auth {
		if a.db == db && a.user == user && a.pass == pass {
			debugf("Socket %p to %s: login: db=%q user=%q (already logged in)", socket, socket.addr, db, user)
			socket.Unlock()
			return nil
		}
	}
	if auth, found := socket.dropLogout(db, user, pass); found {
		debugf("Socket %p to %s: login: db=%q user=%q (cached)", socket, socket.addr, db, user)
		socket.auth = append(socket.auth, auth)
		socket.Unlock()
		return nil
	}
	socket.Unlock()

	debugf("Socket %p to %s: login: db=%q user=%q", socket, socket.addr, db, user)

	// Note that this only works properly because this function is
	// synchronous, which means the nonce won't get reset while we're
	// using it and any other login requests will block waiting for a
	// new nonce provided in the defer call below.
	nonce, err := socket.getNonce()
	if err != nil {
		return err
	}
	defer socket.resetNonce()

	psum := md5.New()
	psum.Write([]byte(user + ":mongo:" + pass))

	ksum := md5.New()
	ksum.Write([]byte(nonce + user))
	ksum.Write([]byte(hex.EncodeToString(psum.Sum(nil))))

	key := hex.EncodeToString(ksum.Sum(nil))

	cmd := authCmd{Authenticate: 1, User: user, Nonce: nonce, Key: key}

	var mutex sync.Mutex
	var replyErr error
	mutex.Lock()

	op := queryOp{}
	op.query = &cmd
	op.collection = db + ".$cmd"
	op.limit = -1
	op.replyFunc = func(err error, reply *replyOp, docNum int, docData []byte) {
		defer mutex.Unlock()

		if err != nil {
			replyErr = err
			return
		}

		// Must handle this within the read loop for the socket, so
		// that concurrent login requests are properly ordered.
		result := &authResult{}
		err = bson.Unmarshal(docData, result)
		if err != nil {
			replyErr = err
			return
		}
		if !result.Ok {
			replyErr = errors.New(result.ErrMsg)
		}

		socket.Lock()
		socket.dropAuth(db)
		socket.auth = append(socket.auth, authInfo{db, user, pass})
		socket.Unlock()
	}

	err = socket.Query(&op)
	if err != nil {
		return err
	}
	mutex.Lock() // Wait.
	if replyErr != nil {
		debugf("Socket %p to %s: login error: %s", socket, socket.addr, replyErr)
	} else {
		debugf("Socket %p to %s: login successful", socket, socket.addr)
	}
	return replyErr
}
예제 #27
0
파일: socket.go 프로젝트: hfeeki/mgo
// Estimated minimum cost per socket: 1 goroutine + memory for the largest
// document ever seen.
func (socket *mongoSocket) readLoop() {
	p := make([]byte, 36) // 16 from header + 20 from OP_REPLY fixed fields
	s := make([]byte, 4)
	conn := socket.conn // No locking, conn never changes.
	for {
		// XXX Handle timeouts, , etc
		err := fill(conn, p)
		if err != nil {
			socket.kill(err, true)
			return
		}

		totalLen := getInt32(p, 0)
		responseTo := getInt32(p, 8)
		opCode := getInt32(p, 12)

		// Don't use socket.server.Addr here.  socket is not
		// locked and socket.server may go away.
		debugf("Socket %p to %s: got reply (%d bytes)", socket, socket.addr, totalLen)

		_ = totalLen

		if opCode != 1 {
			socket.kill(errors.New("opcode != 1, corrupted data?"), true)
			return
		}

		reply := replyOp{
			flags:     uint32(getInt32(p, 16)),
			cursorId:  getInt64(p, 20),
			firstDoc:  getInt32(p, 28),
			replyDocs: getInt32(p, 32),
		}

		stats.receivedOps(+1)
		stats.receivedDocs(int(reply.replyDocs))

		socket.Lock()
		replyFunc, replyFuncFound := socket.replyFuncs[uint32(responseTo)]
		socket.Unlock()

		if replyFunc != nil && reply.replyDocs == 0 {
			replyFunc(nil, &reply, -1, nil)
		} else {
			for i := 0; i != int(reply.replyDocs); i++ {
				err := fill(conn, s)
				if err != nil {
					socket.kill(err, true)
					return
				}

				b := make([]byte, int(getInt32(s, 0)))

				// copy(b, s) in an efficient way.
				b[0] = s[0]
				b[1] = s[1]
				b[2] = s[2]
				b[3] = s[3]

				err = fill(conn, b[4:])
				if err != nil {
					socket.kill(err, true)
					return
				}

				if globalDebug && globalLogger != nil {
					m := bson.M{}
					if err := bson.Unmarshal(b, m); err == nil {
						debugf("Socket %p to %s: received document: %#v", socket, socket.addr, m)
					}
				}

				if replyFunc != nil {
					replyFunc(nil, &reply, i, b)
				}

				// XXX Do bound checking against totalLen.
			}
		}

		// Only remove replyFunc after iteration, so that kill() will see it.
		socket.Lock()
		if replyFuncFound {
			delete(socket.replyFuncs, uint32(responseTo))
		}
		socket.Unlock()

		// XXX Do bound checking against totalLen.
	}
}