// Save to DB func (this *UdpSessionList) SaveSession(sid *uuid.UUID, s *UdpSession) error { v, ok := gUdpSessions.udpmap[s.Addr.String()] if ok { v.Reset(40 * time.Second) } return SetDeviceSession(sid.String(), gUdpTimeout, s.String(), s.DeviceId, s.Addr) }
/* NewJob creates a new job from the config as well as a job spec. After creating the job, calling job.Process() will actually perform the work. */ func NewJob(cfg *Config, spec *Spec, req *http.Request) *Job { var idUUID *gouuid.UUID var err error idUUID, err = gouuid.NewV4() if TestMode { idUUID, err = gouuid.NewV5(gouuid.NamespaceURL, []byte("0")) } if err != nil { cfg.Logger.WithField("error", err).Error("error creating uuid") } id := idUUID.String() bobfile := spec.Bobfile if bobfile == "" { bobfile = defaultBobfile } ret := &Job{ Bobfile: bobfile, ID: id, Account: spec.RepoOwner, GitHubAPIToken: spec.GitHubAPIToken, Ref: spec.GitRef, Repo: spec.RepoName, Workdir: cfg.Workdir, InfoRoute: "/jobs/" + id, LogRoute: "/jobs/" + id + "/tail?n=" + defaultTail, logDir: cfg.Workdir + "/" + id, Status: "created", Created: time.Now(), } ret.addHostToRoutes(req) out, file, err := newMultiWriter(ret.logDir) if err != nil { cfg.Logger.WithField("error", err).Error("error creating log dir") id = "" } ret.logFile = file ret.Logger = &logrus.Logger{ Formatter: cfg.Logger.Formatter, Level: cfg.Logger.Level, Out: out, } if ret.GitHubAPIToken == "" { ret.GitHubAPIToken = cfg.GitHubAPIToken } if id != "" { jobs[id] = ret } return ret }
// Get existed session from DB func (this *UdpSessionList) GetSession(sid *uuid.UUID) (*UdpSession, error) { data, err := GetDeviceSession(sid.String()) if err != nil { return nil, err } s := &UdpSession{ Addr: &net.UDPAddr{}, } err = s.FromString(data) if err != nil { return nil, err } s.Sid = sid.String() return s, nil }
func (sr *SessionDbRow) InsertSession() (csi *ClearSessionId, err error) { var u4 *uuid.UUID u4, err = uuid.NewV4() if err != nil { return nil, err } csi = new(ClearSessionId) saltBytes := makeSalt() csi.Salt = hex.EncodeToString(saltBytes) csi.SessionToken = u4.String() sessionIdCrypt, err := csi.EncryptToken() if err != nil { err = fmt.Errorf("Failed to encrypt SessionToken: %s", err) return nil, err } insertSql := fmt.Sprintf(` INSERT INTO session.session ( SessionId, SysUserId, start_dt, expires_dt, IpAddr, UserAgent) VALUES ($1, $2, now(), now() + interval '%d second', $3, $4)`, Conf.SessionTimeout) _, err = Conf.DatabaseHandle.Exec(insertSql, sessionIdCrypt, sr.SysUserId, sr.IpAddr, sr.UserAgent) if err != nil { glog.Errorf("Insert of session row failed: %s", err) return nil, err } return csi, nil }
It("should use an empty request ID if generating a new one fails", func() { instrumented_handler.GenerateUuid = func() (u *uuid.UUID, err error) { return nil, errors.New("test error") } h.ServeHTTP(httptest.NewRecorder(), req) Expect(req.Header.Get("X-CF-RequestID")).To(Equal("00000000-0000-0000-0000-000000000000")) }) }) Describe("event emission", func() { var requestId *uuid.UUID BeforeEach(func() { requestId, _ = uuid.NewV4() req.Header.Set("X-CF-RequestID", requestId.String()) }) Context("without an application ID or instanceIndex", func() { BeforeEach(func() { h.ServeHTTP(httptest.NewRecorder(), req) }) It("should emit a start event with the right origin", func() { Expect(fakeEmitter.GetMessages()[0].Event).To(BeAssignableToTypeOf(new(events.HttpStart))) Expect(fakeEmitter.GetMessages()[0].Origin).To(Equal("testHandler/41")) }) It("should emit a stop event", func() { Expect(fakeEmitter.GetMessages()[1].Event).To(BeAssignableToTypeOf(new(events.HttpStop))) stopEvent := fakeEmitter.GetMessages()[1].Event.(*events.HttpStop)
UserAgent: proto.String("our-testing-client"), } startEvent := factories.NewHttpStart(req, events.PeerType_Server, requestId) Expect(startEvent.GetTimestamp()).ToNot(BeZero()) startEvent.Timestamp = nil Expect(startEvent).To(Equal(expectedStartEvent)) }) }) Context("with an application ID", func() { It("should include it in the start event", func() { applicationId, _ := uuid.NewV4() req.Header.Set("X-CF-ApplicationID", applicationId.String()) startEvent := factories.NewHttpStart(req, events.PeerType_Server, requestId) Expect(startEvent.GetApplicationId()).To(Equal(factories.NewUUID(applicationId))) }) }) Context("with an application instance index", func() { It("should include it in the start event", func() { req.Header.Set("X-CF-InstanceIndex", "1") startEvent := factories.NewHttpStart(req, events.PeerType_Server, requestId) Expect(startEvent.GetInstanceIndex()).To(BeNumerically("==", 1)) })
}) }) Context("event emission", func() { It("should emit a start event", func() { rt.RoundTrip(req) Expect(fakeEmitter.Messages[0].Event).To(BeAssignableToTypeOf(new(events.HttpStart))) Expect(fakeEmitter.Messages[0].Origin).To(Equal("testRoundtripper/42")) }) Context("if request ID already exists", func() { var existingRequestId *uuid.UUID BeforeEach(func() { existingRequestId, _ = uuid.NewV4() req.Header.Set("X-CF-RequestID", existingRequestId.String()) }) It("should emit the existing request ID as the parent request ID", func() { rt.RoundTrip(req) startEvent := fakeEmitter.Messages[0].Event.(*events.HttpStart) Expect(startEvent.GetParentRequestId()).To(Equal(factories.NewUUID(existingRequestId))) }) }) Context("if round tripper returns an error", func() { It("should emit a stop event with blank response fields", func() { fakeRoundTripper.FakeError = errors.New("fakeEmitter error") rt.RoundTrip(req) Expect(fakeEmitter.Messages[1].Event).To(BeAssignableToTypeOf(new(events.HttpStop)))
func (h *Handler) handle(t *UdpMsg) error { // TODO need decryption later mlen := len(t.Msg) if mlen < FrameHeaderLen { return fmt.Errorf("[protocol] invalid message length for device proxy,reason: mlen < FrameHeaderLen | %v < %v.", mlen, FrameHeaderLen) } // check opcode op := (0x7 & t.Msg[0]) if op != 0x2 && op != 0x3 { return fmt.Errorf("[protocol] reason: wrong opcode, op!=2&&op!=3, op=", op) } if op == 0x2 { if mlen < FrameHeaderLen+DataHeaderLen { return fmt.Errorf("[protocol] invalid message length for protocol, mlen < FrameHeaderLen+DataHeaderLen ,%v < %v", mlen, FrameHeaderLen+DataHeaderLen) } packNum := binary.LittleEndian.Uint16(t.Msg[2:4]) bodyLen := int(binary.LittleEndian.Uint16(t.Msg[FrameHeaderLen+6:])) // discard msg if found checking error if t.Msg[FrameHeaderLen+8] != msgs.ChecksumHeader(t.Msg, FrameHeaderLen+8) { return fmt.Errorf("checksum header error %v!=%v", t.Msg[FrameHeaderLen+8], msgs.ChecksumHeader(t.Msg, FrameHeaderLen+8)) } // check body if t.Msg[FrameHeaderLen+9] != msgs.ChecksumHeader(t.Msg[FrameHeaderLen+10:], 2+bodyLen) { return fmt.Errorf("checksum body error %v!=%v", t.Msg[FrameHeaderLen+9], msgs.ChecksumHeader(t.Msg[FrameHeaderLen+10:], 2+bodyLen)) } var ( sess *UdpSession sid *uuid.UUID err error locker Locker body []byte bodyIndex int ) bodyIndex = FrameHeaderLen + DataHeaderLen if bodyLen != len(t.Msg[bodyIndex:]) { return fmt.Errorf("wrong body length in data header: %d != %d", bodyLen, len(t.Msg[bodyIndex:])) } body = t.Msg[bodyIndex : bodyIndex+bodyLen] // parse data(udp) // 28 = FrameHeaderLen + 4 c := binary.LittleEndian.Uint16(t.Msg[28:30]) if c == CmdSyncState { glog.Infoln("执行设备状态同步") GMsgBusManager.Push2Bus(0, nil, t.Msg) return nil } else if c == 0x31 { glog.Infoln("执行报警信息同步") GMsgBusManager.Push2Bus(0, nil, t.Msg) return nil //TODO alarm msg synchronization } else if c != CmdGetToken { sid, err = uuid.Parse(t.Msg[bodyIndex : bodyIndex+16]) if err != nil { return fmt.Errorf("parse session id error: %v", err) } locker = NewDeviceSessionLocker(sid.String()) err = locker.Lock() if err != nil { return fmt.Errorf("lock session id [%s] failed: %v", sid, err) } sess, err = gUdpSessions.GetSession(sid) if err != nil { locker.Unlock() return fmt.Errorf("cmd: %X, sid: [%v], error: %v", c, sid, err) } err = sess.VerifySession(packNum) if err != nil { locker.Unlock() return fmt.Errorf("cmd: %X, verify session error: %v", c, err) } } output := make([]byte, bodyIndex) // copy same packNum into this ACK response copy(output[:bodyIndex], t.Msg[:bodyIndex]) var res []byte switch c { case CmdGetToken: t.CmdType = c res, err = h.onGetToken(t, body) case CmdRegister: t.CmdType = c t.Url = h.kApiUrls[c] res, err = h.onRegister(t, sess, body) case CmdLogin: t.CmdType = c t.Url = h.kApiUrls[c] res, err = h.onLogin(t, sess, body) case CmdRename: t.CmdType = c t.Url = h.kApiUrls[c] res, err = h.onRename(t, sess, body) //case CmdDoBind: // t.CmdType = c // t.Url = h.kApiUrls[c] // res, err = h.onDoBind(t, sess, body) case CmdHeartBeat: t.CmdType = c res, err = h.onHearBeat(t, sess, body) case CmdSubDeviceOffline: t.CmdType = c res, err = h.onSubDeviceOffline(t, sess, body) // case CmdSyncState: // GMsgBusManager.Push2Bus(0, nil, t.Msg) default: glog.Warningf("invalid command type %v", c) if sess != nil { locker.Unlock() } // don't reply on wrong msgid //b := make([]byte, 4) //binary.LittleEndian.PutUint32(b, uint32(DAckBadCmd)) //output = append(output, b...) //err = computeCheck(output) //if err == nil { // h.Server.Send(t.Peer, output) //} else { // if glog.V(1) { // glog.Warningf("[handle] check message failed: %v", err) // } //} return nil } if sess != nil { gUdpSessions.SaveSession(sid, sess) locker.Unlock() } if err != nil { if glog.V(1) { glog.Errorf("[handle] cmd: %X, error: %v", c, err) } } if c != CmdGetToken { copy(res[4:20], t.Msg[bodyIndex:bodyIndex+16]) copy(res[4:20], sid[:]) } if res != nil { output = append(output, res...) } output[FrameHeaderLen] |= (msgs.FlagAck | msgs.FlagRead) binary.LittleEndian.PutUint16(output[FrameHeaderLen+6:], uint16(len(res))) output[FrameHeaderLen+8] = msgs.ChecksumHeader(output, FrameHeaderLen+8) output[FrameHeaderLen+9] = msgs.ChecksumHeader(output[FrameHeaderLen+10:], 2+len(res)) h.Server.Send(t.Peer, output) } else if op == 0x3 { if mlen < FrameHeaderLen+kSidLen+FrameHeaderLen+DataHeaderLen { return fmt.Errorf("[protocol] invalid message length for protocol") } packNum := binary.LittleEndian.Uint16(t.Msg[2:4]) // bodyLen := int(binary.LittleEndian.Uint16(t.Msg[FrameHeaderLen+kSidLen+FrameHeaderLen+6:])) // discard msg if found checking error // if t.Msg[FrameHeaderLen+kSidLen+FrameHeaderLen+8] != msgs.ChecksumHeader(t.Msg, FrameHeaderLen+kSidLen+FrameHeaderLen+8) { // return fmt.Errorf("checksum header error") // } // check data body // if t.Msg[FrameHeaderLen+kSidLen+FrameHeaderLen+9] != msgs.ChecksumHeader(t.Msg[FrameHeaderLen+kSidLen+FrameHeaderLen+10:], 2+bodyLen) { // return fmt.Errorf("checksum data error") // } var ( sess *UdpSession sid *uuid.UUID err error locker Locker ) //bodyIndex = FrameHeaderLen + DataHeaderLen //if bodyLen != len(t.Msg[bodyIndex:]) { // return fmt.Errorf("wrong body length in data header: %d != %d", bodyLen, len(t.Msg[bodyIndex:])) //} // body = t.Msg[bodyIndex : bodyIndex+bodyLen] sid, err = uuid.Parse(t.Msg[FrameHeaderLen : FrameHeaderLen+kSidLen]) if err != nil { return fmt.Errorf("parse session id error: %v", err) } locker = NewDeviceSessionLocker(sid.String()) err = locker.Lock() if err != nil { return fmt.Errorf("lock session id [%s] failed: %v", sid, err) } sess, err = gUdpSessions.GetSession(sid) if err != nil { locker.Unlock() return fmt.Errorf("[ForwardMsg] sid: [%v], error: %v", sid, err) } err = sess.VerifySession(packNum) if err != nil { locker.Unlock() return fmt.Errorf("[ForwardMsg] verify session error: %v", err) } toId := int64(binary.LittleEndian.Uint64(t.Msg[8:16])) srcId := int64(binary.LittleEndian.Uint64(t.Msg[16:24])) // check binded ids destIds := sess.CalcDestIds(toId) locker.Unlock() if glog.V(3) { glog.Infof("[udp|received] %d -> %d udp, calc to: %v, data: (len: %d)%v...", srcId, toId, destIds, len(t.Msg), t.Msg) } else if glog.V(2) { glog.Infof("[udp|received] %d -> %d udp, calc to: %v, data: (len: %d)%v...", srcId, toId, sess.BindedUsers, destIds, len(t.Msg), t.Msg[0:kDstIdEnd]) } GMsgBusManager.Push2Bus(srcId, destIds, t.Msg) } return nil }