github.com/iDigitalFlame/xmt@v0.5.4/c2/job.go (about)

     1  //go:build !implant
     2  // +build !implant
     3  
     4  // Copyright (C) 2020 - 2023 iDigitalFlame
     5  //
     6  // This program is free software: you can redistribute it and/or modify
     7  // it under the terms of the GNU General Public License as published by
     8  // the Free Software Foundation, either version 3 of the License, or
     9  // any later version.
    10  //
    11  // This program is distributed in the hope that it will be useful,
    12  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    13  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    14  // GNU General Public License for more details.
    15  //
    16  // You should have received a copy of the GNU General Public License
    17  // along with this program.  If not, see <https://www.gnu.org/licenses/>.
    18  //
    19  
    20  package c2
    21  
    22  import (
    23  	"time"
    24  
    25  	"github.com/iDigitalFlame/xmt/com"
    26  )
    27  
    28  // These are status values that indicate the general status of the Job.
    29  const (
    30  	StatusWaiting  status = 0
    31  	StatusAccepted status = iota
    32  	StatusReceiving
    33  	StatusCompleted
    34  	StatusError
    35  	StatusCanceled
    36  )
    37  
    38  // Job is a struct that is used to track and manage Tasks given to Session
    39  // Clients.
    40  //
    41  // This struct has function callbacks that can be used to watch for completion
    42  // and offers a Wait function to pause execution until a response is received.
    43  //
    44  // This struct is always empty for implants.
    45  type Job struct {
    46  	Start, Complete time.Time
    47  
    48  	Update func(*Job)
    49  	Result *com.Packet
    50  	done   chan struct{}
    51  	s      *Session
    52  
    53  	Error              string
    54  	ID, Frags, Current uint16
    55  
    56  	Type   uint8
    57  	Status status
    58  }
    59  type status uint8
    60  
    61  // Wait will block until the Job is completed or the parent Server is shutdown.
    62  func (j *Job) Wait() {
    63  	if j == nil || j.done == nil {
    64  		return
    65  	}
    66  	<-j.done
    67  }
    68  
    69  // Cancel will stop the current Job in-flight and will remove it from the Task
    70  // queue. Any threads waiting on this Job will return once this function completes.
    71  //
    72  // This does NOT prevent the client Session from running it, but will close
    73  // out all receiving channels and any received data will be marked as an un-tracked
    74  // Job.
    75  //
    76  // This is the only method that results in a Status of Canceled.
    77  func (j *Job) Cancel() {
    78  	if j == nil || j.done == nil {
    79  		return
    80  	}
    81  	if j.Status >= StatusCompleted {
    82  		// Something happened and didn't close done.
    83  		if j.done != nil {
    84  			// NOTE(dij): I don't think this will panic, but I need to test to
    85  			//            be 100% sure.
    86  			close(j.done)
    87  		}
    88  		return
    89  	}
    90  	j.s.lock.Lock()
    91  	if j.s.jobs == nil || len(j.s.jobs) == 0 {
    92  		close(j.done)
    93  		j.Status, j.done = StatusCanceled, nil
    94  		// NOTE(dij): We're using the Session Mutex to protect all Jobs since it's
    95  		//            the only non-OOB place we'd cancel em at.
    96  		j.s.lock.Unlock()
    97  		return
    98  	}
    99  	if _, ok := j.s.jobs[j.ID]; !ok {
   100  		close(j.done)
   101  		j.Status, j.done = StatusCanceled, nil
   102  		j.s.lock.Unlock()
   103  		// NOTE(dij): I know this does a lot of work while the Mutex is spinning,
   104  		//            but it stays in sync.
   105  		return
   106  	}
   107  	j.s.jobs[j.ID] = nil
   108  	delete(j.s.jobs, j.ID)
   109  	close(j.done)
   110  	j.done = nil
   111  	if j.s.lock.Unlock(); j.Update == nil {
   112  		return
   113  	}
   114  	j.s.m.queue(event{j: j, jf: j.Update})
   115  }
   116  
   117  // IsDone returns true when the Job has received a response, has error out or
   118  // was canceled. Use the Status field to determine the state of the Job.
   119  func (j *Job) IsDone() bool {
   120  	if j == nil || j.done == nil {
   121  		return true
   122  	}
   123  	select {
   124  	case <-j.done:
   125  		return true
   126  	default:
   127  	}
   128  	return false
   129  }
   130  
   131  // IsError returns true when the Job has received a response, but the response
   132  // is an error.
   133  func (j *Job) IsError() bool {
   134  	if j == nil {
   135  		return false
   136  	}
   137  	if j.IsDone() {
   138  		return len(j.Error) > 0
   139  	}
   140  	return false
   141  }
   142  
   143  // Session returns the Session that is associated with this Job.
   144  func (j *Job) Session() *Session {
   145  	return j.s
   146  }