func NewPacket(conn *net.TCPConn, raw []byte) (*Packet, error) { if len(raw) < 8 { return nil, errors.New("The packet is too short. The header can't be completed.") } if len(raw) > config.MAX_PACKET_SIZE { return nil, errors.New("The packet exceeds the maximal packet size.") } contentLength := int(utils.ByteToUint(raw[0:3])) - 5 if len(raw) != contentLength+8 { return nil, errors.New("The packet content size does not match the size value in the header: " + strconv.Itoa(len(raw)) + " != " + strconv.Itoa(int(contentLength))) } packet := new(Packet) packet.Sender = conn packet.ServiceId = utils.ByteToUint8(raw[3]) packet.PacketType = utils.ByteToUint8(raw[4]) packet.PacketId = utils.ByteToUint(raw[5:8]) packet.ContentLength = uint(contentLength) if packet.ContentLength > 0 { packet.Content = raw[8:] } else { packet.Content = []byte{} } packet.Raw = raw packet.prepared = true return packet, nil }
func (c *UnsubscribeCommand) Handle(packet *core.Packet, service *core.Service) error { utils.Debug("UNSUBSCRIBE packet: ", packet) if service == nil { return errors.New("UNSUBSCRIBE error: There is no service for this serviceId connected.") } if len(packet.Content) <= 0 { return errors.New("UNSUBSCRIBE error: The packet data is too short.") } for i := 0; i < len(packet.Content); i++ { c.GetMaster().SubscriptionMap.RemoveSubscription(service, utils.ByteToUint8(packet.Content[i])) } return nil }
func (c *ConnectCommand) Handle(packet *core.Packet, service *core.Service) error { utils.Debug("CONNECT packet: ", packet) if service != nil { return errors.New("CONNECT error: There is already a service for this serviceId connected.") } rawData := packet.Content dataLength := len(rawData) if dataLength < 2 { return errors.New("CONNECT error: The packet data is too short.") } serviceName := "" tunnelHost := "" tunnelPorts := make(map[uint8]uint) lenServiceName := int(utils.ByteToUint8(rawData[0])) if dataLength < 2+lenServiceName { return errors.New("CONNECT error: The packet data is too short. (serviceName)") } lenTunnelHost := int(utils.ByteToUint8(rawData[lenServiceName+1])) if dataLength < 2+lenServiceName+lenTunnelHost { return errors.New("CONNECT error: The packet data is too short. (tunnelHost)") } lenTunnelPorts := dataLength - lenServiceName - lenTunnelHost - 2 if lenTunnelPorts%3 != 0 { return errors.New("CONNECT error: The packet data length is not valid. (tunnelPorts)") } if lenServiceName > 0 { serviceName = string(rawData[1 : lenServiceName+1]) } if lenTunnelHost > 0 { tunnelHost = string(rawData[lenServiceName+2 : lenServiceName+2+lenTunnelHost]) } for i := 0; i*3 < lenTunnelPorts; i++ { pos := lenServiceName + lenTunnelHost + 2 + (i * 3) tunnelPorts[utils.ByteToUint8(rawData[pos])] = utils.ByteToUint(rawData[pos+1 : pos+3]) } return c.GetMaster().ConnectService(core.NewService(c.GetMaster(), packet.ServiceId, serviceName, packet.Sender, tunnelHost, tunnelPorts)) }
func (c *AskTunnelCommand) Handle(packet *core.Packet, service *core.Service) error { utils.Debug("ASK_TUNNEL packet: ", packet) if service == nil { return errors.New("ASK_TUNNEL error: There is no service for this serviceId connected.") } if len(packet.Content) <= 0 { return errors.New("ASK_TUNNEL error: The packet data is too small.") } answerPacket := core.ConstructPacket(packet.Sender, packet.ServiceId, packet.PacketType, packet.PacketId, []byte{}) services := c.GetMaster().Services for i := 0; i < len(packet.Content); i++ { tunnelRequest := utils.ByteToUint8(packet.Content[i]) for _, service := range services { if port, ok := service.TunnelPorts[packet.ServiceId]; ok && service.ServiceId == tunnelRequest { answerPacket.AppendContent(utils.UintToByte(uint(len(service.TunnelHost)+3), 2)) answerPacket.AppendContent(utils.UintToByte(uint(service.ServiceId), 1)) answerPacket.AppendContent(utils.UintToByte(port, 2)) answerPacket.AppendContent([]byte(service.TunnelHost)) } } } service.Write(answerPacket) return nil }
func (r *PacketReader) Read(conn *net.TCPConn) (*Packet, error) { headerBuffer := make([]byte, 8) n, err := conn.Read(headerBuffer) if err != nil { return nil, err } if n != 8 { return nil, errors.New("Packet header was " + strconv.Itoa(n) + " bytes.") } contentLength := int(utils.ByteToUint(headerBuffer[0:3])) - 5 if contentLength < 0 { return nil, errors.New("Packet ContentLength is a negative number. ContentLength - 5 Header bytes: " + strconv.Itoa(contentLength)) } serviceId := utils.ByteToUint8(headerBuffer[3]) packetId := utils.ByteToUint(headerBuffer[5:8]) service := r.master.ServiceById[serviceId] // Don't trust the packet serviceId, if the connection is already connected to the master, // instead use the connected serviceId information setServiceId := serviceId for sId, service := range r.master.ServiceById { if service.Connection == conn { setServiceId = sId } } if setServiceId != serviceId { utils.Debug("PacketReader: WARN: The serviceId of the connected service for this Connection (", conn, ") does not match the packet serviceId", serviceId, ". Overriding the packet serviceId for recover messages.") } recoverMessage := ConstructPacket(conn, setServiceId, PACKETTYPE_NOTHING, packetId, []byte{}) if contentLength > config.MAX_PACKET_SIZE { r.SetRecovering(conn, recoverMessage) return nil, errors.New("Packet header indicates too long packet: " + strconv.Itoa(contentLength)) } if service != nil && service.Connection != conn { r.SetRecovering(conn, recoverMessage) return nil, errors.New("packet sender connection is not origin service connection") } if lastId, found := r.master.LastPacketId[serviceId]; found { if packetId <= lastId { r.SetRecovering(conn, recoverMessage) return nil, errors.New("Packet header packetId is too small: " + strconv.Itoa(int(packetId)) + " <= " + strconv.Itoa(int(lastId))) } } r.master.LastPacketId[serviceId] = packetId if contentLength <= 0 { return NewPacket(conn, headerBuffer) } contentBuffer := make([]byte, contentLength) n, err = conn.Read(contentBuffer) if err != nil { if err != io.EOF && err.Error()[0:11] != "WSARecv tcp" { netOpError, ok := err.(*net.OpError) if !ok || (netOpError.Err.Error() != "use of closed network connection" && netOpError.Err.Error() != "read: connection reset by peer") { r.SetRecovering(conn, recoverMessage) } } return nil, err } if n != contentLength { r.SetRecovering(conn, recoverMessage) return nil, errors.New("Packet content does not fit into the defined content buffer size exactly: " + strconv.Itoa(n) + " != " + strconv.Itoa(contentLength)) } return NewPacket(conn, append(headerBuffer, contentBuffer...)) }
func (r *PacketReader) Recover(conn *net.TCPConn) { recoverBuffer := make([]byte, 4096) recovered := false LoopRecovering: for !recovered { if !r.master.IsValidConnection(conn) { break LoopRecovering } n, err := conn.Read(recoverBuffer) if err == nil && n < 8 { // to few bytes, next try continue } if err != nil { netOpError, ok := err.(*net.OpError) if err == io.EOF || err.Error()[0:11] == "WSARecv tcp" || (ok && netOpError.Err.Error() == "read: connection reset by peer") { utils.Debug("PacketReader: Recovering stopped (Client disconnected) on Connection", conn) r.master.SetValidConnection(conn, false) break LoopRecovering } if ok && netOpError.Err.Error() == "use of closed network connection" { utils.Debug("PacketReader: Recovering stopped (Lost Connection) on Connection", conn) r.master.SetValidConnection(conn, false) break LoopRecovering } _, err := conn.Write(r.recovering[conn]) if err != nil { utils.Debug("PacketReader: Error sending recover message:", err) netOpError, ok := err.(*net.OpError) if err == io.EOF || err.Error()[0:11] == "WSARecv tcp" || (ok && (netOpError.Err.Error() == "use of closed network connection" || netOpError.Err.Error() == "read: connection reset by peer")) { r.master.SetValidConnection(conn, false) } // Break anyway, but keep the connection valid // if wrong break LoopRecovering } utils.Debug("PacketReader: Recovering not successful, continue.") continue } recoverBufferStr := []uint8{} for _, b := range recoverBuffer { recoverBufferStr = append(recoverBufferStr, utils.ByteToUint8(b)) } recovered = true for i := 1; recovered && i <= 8; i++ { if r.recovering[conn][8-i] != recoverBuffer[n-i] { recovered = false } } } r.recovering[conn] = []byte{} if recovered && r.master.IsValidConnection(conn) { utils.Debug("PacketReader: Recovering successful on Connection", conn) } else { utils.Debug("PacketReader: Recovering failed on Connection", conn) } }