Example #1
0
func P_forward_req(hostid int32, pkt *packet.Packet) []byte {
	tbl, _ := PKT_FORWARDIPC(pkt)

	object := &IPCObject{}
	err := json.Unmarshal(tbl.F_IPC, object)

	if err != nil {
		log.Println("decode forward IPCObject error")
		return nil
	}

	// if user is online, send to the server, or else send to database
	state := core.State(object.DestID)

	//fmt.Println(tbl.F_dest_id, tbl.F_IPC)
	switch state {
	case core.ON_PROT, core.ON_FREE:
		host := core.Host(object.DestID)

		ch := ForwardChan(host)

		if ch != nil {
			ch <- tbl.F_IPC
		} else {
			forward_tbl.Push(object)
		}
	default:
		forward_tbl.Push(object)
	}

	ret := INT{F_v: 1}
	return packet.Pack(-1, &ret, nil)
}
Example #2
0
//---------------------------------------------------------- p2p send from src_id to dest_id
func Send(src_id, dest_id int32, service int16, multicast bool, object interface{}) (ret bool) {
	if multicast {
		return _multicast(src_id, dest_id, service, object)
	}

	// convert the OBJECT to json, LEVEL-1 encapsulation
	val, err := json.Marshal(object)
	if err != nil {
		log.Println("cannot marshal object to json", err)
		return false
	}

	req := &IPCObject{SrcID: src_id, DestID: dest_id, Service: service, Object: val, Time: time.Now().Unix()}

	// first try local delivery, if dest_id is not in the same server, just forward to HUB server.
	peer := gsdb.QueryOnline(dest_id)
	if peer != nil {
		defer func() {
			if x := recover(); x != nil {
				ret = false
				forward_tbl.Push(req)
			}
		}()

		select {
		case peer.MQ <- *req:
		case <-time.After(time.Second):
			panic("deadlock") // rare case, when both chan is full
		}
		return true
	} else {
		// convert req to json again, LEVEL-2 encapsulation
		return hub_client.Forward(req)
	}
}
Example #3
0
//---------------------------------------------------------- deliver an IPCObject to a user
func _deliver(obj *IPCObject) {
	sess := gsdb.QueryOnline(obj.DestID)
	if sess != nil {
		func() {
			defer func() {
				if x := recover(); x != nil {
					forward_tbl.Push(obj)
				}
			}()

			sess.MQ <- *obj
		}()
	} else {
		forward_tbl.Push(obj)
	}
}
Example #4
0
func _unicast(hostid int32, obj *IPCObject) {
	// if user is online, send to the server, or else send to database
	state := core.State(obj.DestID)

	switch state {
	case ON_PROT, ON_FREE:
		host := core.Host(obj.DestID)
		ch := ForwardChan(host)

		if ch != nil {
			ch <- *obj
		} else {
			forward_tbl.Push(obj)
		}
	default:
		forward_tbl.Push(obj)
	}
}
Example #5
0
//------------------------------------------------ 载入离线时收到的的IPCObject
func LoadIPCObjects(user_id int32, MQ chan IPCObject) {
	objs := forward_tbl.PopAll(user_id)

	// 消息没有完全push到MQ, 存回db
	var k int

	defer func() {
		if x := recover(); x != nil {
			for k < len(objs) {
				forward_tbl.Push(&objs[k])
				k++
			}
		}
	}()

	for k = range objs {
		MQ <- objs[k]
	}
}
Example #6
0
//----------------------------------------------- connection close cleanup work
func close_work(sess *Session) {
	if sess.LoggedIn {
		hub_client.Logout(sess.User.Id)
		gsdb.UnregisterOnline(sess.User.Id)
		close(sess.MQ)

		// 未处理的IPC数据,重新放入db
		if len(sess.MQ) > 0 {
			log.Println("re-push ipcobject back to db")
		}

		for len(sess.MQ) > 0 {
			ipcobject := <-sess.MQ
			forward_tbl.Push(&ipcobject)
		}

		// 持久化逻辑#3: 离线时,刷入数据库
		_flush(sess)
	}
}
Example #7
0
File: ipc.go Project: hycxa/gonet
//---------------------------------------------------------- 异步消息发送
func Send(src_id, dest_id int32, service int16, object interface{}) (ret bool) {
	// 况序列化被传输对象为json
	val, err := json.Marshal(object)
	if err != nil {
		ERR("cannot marshal object to json", err)
		return false
	}
	// Send函数不能投递到SYS_USR
	if dest_id == SYS_USR {
		ERR("cannot Send to SYS_USR")
		return false
	}

	// 打包为IPCObject
	req := &IPCObject{SrcID: src_id,
		DestID:  dest_id,
		Service: service,
		Object:  val,
		Time:    time.Now().Unix()}

	peer := gsdb.QueryOnline(dest_id)
	if peer != nil { // 如果玩家在本服务器
		// 对方的channel 可能会close, 需要处理panic的情况
		defer func() {
			if x := recover(); x != nil {
				ret = false
				forward_tbl.Push(req)
			}
		}()
		select {
		case peer.MQ <- *req:
		case <-time.After(time.Second):
			panic("deadlock") // rare case, when both chans are full.
		}
		return true
	} else { // 通过HUB转发IPCObject
		return hub_client.Forward(req)
	}

	return false
}
Example #8
0
//----------------------------------------------- cleanup work after disconnection
func close_work(sess *Session) {
	defer PrintPanicStack()
	if sess.Flag&SESS_LOGGED_IN == 0 {
		return
	}

	// must flush user data
	_flush(sess)

	// notify hub
	hub_client.Logout(sess.User.Id)

	// unregister online at this server
	gsdb.UnregisterOnline(sess.User.Id)

	// close MQ, and save the queue to db
	close(sess.MQ)
	for ipcobject := range sess.MQ {
		forward_tbl.Push(&ipcobject)
		NOTICE("re-pushed ipcobject back to db, userid:", sess.User.Id)
	}

	NOTICE(sess.User.Name, "disconnected from", sess.IP, "country:", geoip.Query(sess.IP))
}
Example #9
0
//----------------------------------------------- receive message from hub
func HubReceiver(conn net.Conn) {
	defer conn.Close()

	header := make([]byte, 2)
	seq_id := make([]byte, 8)

	for {
		// header
		n, err := io.ReadFull(conn, header)
		if n == 0 && err == io.EOF {
			break
		} else if err != nil {
			log.Println("error receiving header:", err)
			break
		}

		// packet seq_id uint32
		n, err = io.ReadFull(conn, seq_id)
		if n == 0 && err == io.EOF {
			break
		} else if err != nil {
			log.Println("error receiving seq_id:", err)
			break
		}

		// read big-endian header
		seqval := binary.BigEndian.Uint64(seq_id)
		size := binary.BigEndian.Uint16(header) - 8
		data := make([]byte, size)
		n, err = io.ReadFull(conn, data)

		if err != nil {
			log.Println("error receiving msg:", err)
			break
		}

		// two kinds of IPC:
		// a). Hub Sends to GS, sequence number is not required (set to 0), just forwarding to session
		// b). Call, sequence number is needed, send will wake up blocking-chan.
		//
		if seqval == 0 {
			obj := &IPCObject{}
			err := json.Unmarshal(data, obj)
			if err != nil {
				log.Println("unable to decode received IPCObject")
				continue
			}

			sess := gsdb.QueryOnline(obj.DestID)
			if sess == nil {
				// if the user is disconnected
				forward_tbl.Push(obj)
			} else {
				func() {
					defer func() {
						if x := recover(); x != nil {
							log.Println("forward: deliver to MQ failed.")
							forward_tbl.Push(obj)
						}
					}()

					sess.MQ <- *obj
				}()
			}
		} else {
			_wait_ack_lock.Lock()
			if ack, ok := _wait_ack[seqval]; ok {
				ack <- data
				delete(_wait_ack, seqval)
			} else {
				log.Printf("Illegal packet sequence number [%x] from HUB", seqval)
			}
			_wait_ack_lock.Unlock()
		}
	}
}