| 505 | | |
|---|
| 506 | | # Helper function designed to acquire exclusive access to the |
|---|
| 507 | | # shared $driverData, for use within any thread. |
|---|
| 508 | | # |
|---|
| 509 | | # In perl, it is difficult to share hashtables between threads. |
|---|
| 510 | | # However, it is easy to share scalars between threads. |
|---|
| 511 | | # As such, we share a hashtable between threads by *serializing* |
|---|
| 512 | | # the data using nfreeze(). The result can be stored in a scalar. |
|---|
| 513 | | # |
|---|
| 514 | | # When we are in a thread where we subsequently want to read/use |
|---|
| 515 | | # this hashtable, we thaw() the serialized data (it performs the |
|---|
| 516 | | # deserialization process) and use the hashtable accordingly. |
|---|
| 517 | | # |
|---|
| 518 | | # This function guarantees that no other thread will access |
|---|
| 519 | | # $driverData and returns the thaw()'d contents of $driverData. |
|---|
| 520 | | # |
|---|
| 521 | | # Input: None |
|---|
| 522 | | # Output: driverData (deserialized) |
|---|
| 523 | | # XXX: DELETE |
|---|
| 524 | | sub _lock { |
|---|
| 525 | | # Acquire lock on stored driver state. |
|---|
| 526 | | $driverDataSemaphore->down(); |
|---|
| 527 | | |
|---|
| 528 | | # Thaw the data. |
|---|
| 529 | | return thaw($driverData); |
|---|
| 530 | | } |
|---|
| 531 | | |
|---|
| 532 | | # Helper function designed to release exclusive access to the |
|---|
| 533 | | # shared $driverData, for use within any thread. |
|---|
| 534 | | # |
|---|
| 535 | | # By calling this function, we assume that the thread has already |
|---|
| 536 | | # called _lock() and would like to (optionally) update $driverData |
|---|
| 537 | | # with a new, modified hashtable, prior to releasing the lock |
|---|
| 538 | | # on $driverData. |
|---|
| 539 | | # |
|---|
| 540 | | # This function can optionally take in a normal hashtable reference, |
|---|
| 541 | | # overwriting the $driverData with the contents of the supplied |
|---|
| 542 | | # hashtable. Once the $driverData's updated contents has been |
|---|
| 543 | | # set and serialized, this function releases the corresponding |
|---|
| 544 | | # lock. |
|---|
| 545 | | # |
|---|
| 546 | | # Input: driverData (deserialized, optional) |
|---|
| 547 | | # Output: None |
|---|
| 548 | | # XXX: DELETE |
|---|
| 549 | | sub _unlock { |
|---|
| 550 | | my $data = shift; |
|---|
| 551 | | |
|---|
| 552 | | if (defined($data)) { |
|---|
| 553 | | # Refreze changed data. |
|---|
| 554 | | $driverData = nfreeze($data); |
|---|
| 555 | | } |
|---|
| 556 | | |
|---|
| 557 | | # Release lock on stored driver state. |
|---|
| 558 | | $driverDataSemaphore->up(); |
|---|
| 559 | | } |
|---|
| 560 | | |
|---|
| 561 | | # Helper function designed to retrieve queued, external |
|---|
| 562 | | # updates to driver state information from %driverUpdateQueues. |
|---|
| 563 | | # |
|---|
| 564 | | # When called from run(), this function takes in the corresponding |
|---|
| 565 | | # Driver object; checks to see if there's a new entry within the |
|---|
| 566 | | # driver's corresponding update queue; and dequeues the *all* |
|---|
| 567 | | # entries in the queue, overwriting the Driver's state data |
|---|
| 568 | | # accordingly. |
|---|
| 569 | | # |
|---|
| 570 | | # The external updateState() call adds new driver state into the queue, |
|---|
| 571 | | # one entry per call. The internal _update() function merges this |
|---|
| 572 | | # driver state with the currently running driver, merging everything |
|---|
| 573 | | # queued per call. In order words, a single call to _update() |
|---|
| 574 | | # *WILL* empty the corresponding Driver update queue completely |
|---|
| 575 | | # -- all entries within the queue will be dequeued per _update() |
|---|
| 576 | | # call made. |
|---|
| 577 | | # |
|---|
| 578 | | # Input: driver |
|---|
| 579 | | # Output: driver (updated) |
|---|
| 580 | | # XXX: DELETE |
|---|
| 581 | | sub _update { |
|---|
| 582 | | # Extract arguments. |
|---|
| 583 | | my $driver = shift; |
|---|
| 584 | | |
|---|
| 585 | | # Figure out the corresponding driver name. |
|---|
| 586 | | my $driverName = ref($driver); |
|---|
| 587 | | |
|---|
| 588 | | # Extract the corresponding queue. |
|---|
| 589 | | my $queue = $driverUpdateQueues{$driverName}; |
|---|
| 590 | | |
|---|
| 591 | | # XXX: One possible DoS condition here; what if |
|---|
| 592 | | # the manager keeps feeding updates to the Agent |
|---|
| 593 | | # before the Agent has a chance to do any work? |
|---|
| 594 | | |
|---|
| 595 | | # If we have data in our driver specific queue... |
|---|
| 596 | | while ($queue->pending) { |
|---|
| 597 | | |
|---|
| 598 | | # Update our driver state with the first entry |
|---|
| 599 | | # found... |
|---|
| 600 | | my $queuedData = thaw($queue->dequeue_nb); |
|---|
| 601 | | |
|---|
| 602 | | # Sanity check: Only copy defined data. |
|---|
| 603 | | if (defined($queuedData)) { |
|---|
| 604 | | |
|---|
| 605 | | # Copy (and overwrite) overloaded object data |
|---|
| 606 | | # into shared memory. This looks creepy, I know, but |
|---|
| 607 | | # it actually works. We're essentially identifying |
|---|
| 608 | | # driver-specific parameters that the user supplied |
|---|
| 609 | | # via $queuedData and overwriting our current driver state |
|---|
| 610 | | # with any matching, user supplied values. |
|---|
| 611 | | @{$driver}{keys %{$queuedData}} = values %{$queuedData}; |
|---|
| 612 | | } |
|---|
| 613 | | } |
|---|
| 614 | | |
|---|
| 615 | | # Return the modified driver state. |
|---|
| 616 | | return $driver; |
|---|
| 617 | | } |
|---|
| 786 | | # TODO: Clean up this comment block. |
|---|
| 787 | | # This function should do the following: |
|---|
| 788 | | # - Initialize all drivers with starting state. |
|---|
| 789 | | # - "Drive" each driver, one-by-one. |
|---|
| 790 | | # - Collect any integrity violations found, with offending |
|---|
| 791 | | # state information. |
|---|
| 792 | | # |
|---|
| 793 | | # Notes: |
|---|
| 794 | | # This function will eventually sit in a sub-thread, allowing the parent |
|---|
| 795 | | # thread to return without any delay. It is expected that the Manager |
|---|
| 796 | | # would then subsequently call a getStatus() operation, in order to |
|---|
| 797 | | # then poll for any new violations found. |
|---|
| 798 | | # |
|---|
| 799 | | # TODO: We need to create a fault reporting mechanism, in order |
|---|
| 800 | | # to properly deal with exceptions/faults that occur within this |
|---|
| 801 | | # thread. |
|---|
| 802 | | # XXX: DELETE |
|---|
| 803 | | sub worker { |
|---|
| 804 | | |
|---|
| 805 | | # Extract arguments. |
|---|
| 806 | | my $args = shift; |
|---|
| 807 | | my $driverName = $args->{'driver_name'}; |
|---|
| 808 | | my $integrity = $args->{'integrity'}; |
|---|
| 809 | | |
|---|
| 810 | | # Temporary variable, used to hold thawed driver data. |
|---|
| 811 | | my $data = undef; |
|---|
| 812 | | |
|---|
| 813 | | # Yield processing to parent thread. |
|---|
| 814 | | threads->yield(); |
|---|
| 815 | | |
|---|
| 816 | | # Trap all faults that may occur from these asynchronous operations. |
|---|
| 817 | | eval { |
|---|
| 818 | | |
|---|
| 819 | | ################################### |
|---|
| 820 | | ### Driver Initialization Phase ### |
|---|
| 821 | | ################################### |
|---|
| 822 | | |
|---|
| 823 | | # Initially set all driver objects to undef. |
|---|
| 824 | | my $driver = undef; |
|---|
| 825 | | |
|---|
| 826 | | # Last resource used by driver. |
|---|
| 827 | | my $lastResource = undef; |
|---|
| 828 | | |
|---|
| 829 | | # Acquire lock on stored driver state. |
|---|
| 830 | | $data = _lock(); |
|---|
| 831 | | |
|---|
| 832 | | # Now, initialize each driver object. |
|---|
| 833 | | # Figure out which $driver object to use... |
|---|
| 834 | | my $driverClass = $driverName; |
|---|
| 835 | | |
|---|
| 836 | | if (!defined($data->{$driverName}->{'state'})) { |
|---|
| 837 | | |
|---|
| 838 | | # If the driver state is undefined, then |
|---|
| 839 | | # create a new state object. |
|---|
| 840 | | $driver = $driverClass->new(); |
|---|
| 841 | | |
|---|
| 842 | | } else { |
|---|
| 843 | | # Then the driver state object is already defined, |
|---|
| 844 | | # so go ahead and reuse it. |
|---|
| 845 | | $driver = $driverClass->new( |
|---|
| 846 | | %{$data->{$driverName}->{'state'}}, |
|---|
| 847 | | ); |
|---|
| 848 | | } |
|---|
| 849 | | |
|---|
| 850 | | # Next, we make sure we have no updates, before we update |
|---|
| 851 | | # the corresponding shared memory version. |
|---|
| 852 | | $driver = _update($driver); |
|---|
| 853 | | |
|---|
| 854 | | # Once we've initialized the object, be sure to update |
|---|
| 855 | | # the corresponding shared memory version. We do this |
|---|
| 856 | | # one time before the loop starts, in case we end up |
|---|
| 857 | | # finishing before we drove anywhere. |
|---|
| 858 | | |
|---|
| 859 | | # Copy object data to shared memory. |
|---|
| 860 | | $data->{$driverName}->{'next'} = $driver->next(); |
|---|
| 861 | | $data->{$driverName}->{'status'} = $driver->status(); |
|---|
| 862 | | $data->{$driverName}->{'status'}->{'is_compromised'} = 0; |
|---|
| 863 | | $data->{$driverName}->{'status'}->{'is_running'} = 1; |
|---|
| 864 | | $data->{$driverName}->{'state'} = $driver; |
|---|
| 865 | | |
|---|
| 866 | | # Release lock on stored driver state. |
|---|
| 867 | | _unlock($data); |
|---|
| 868 | | |
|---|
| 869 | | ################################### |
|---|
| 870 | | ### Driver Running Phase ### |
|---|
| 871 | | ################################### |
|---|
| 872 | | |
|---|
| 873 | | # Boolean to indicate that the driver is about to transition |
|---|
| 874 | | # to a new set of targets upon the next drive() operation. |
|---|
| 875 | | my $driverTargetsChanged = 0; |
|---|
| 876 | | |
|---|
| 877 | | # Boolean to indicate that the driver has been compromised. |
|---|
| 878 | | my $isCompromised = 0; |
|---|
| 879 | | |
|---|
| 880 | | # Variable to hold any changes found in a compromise. |
|---|
| 881 | | my $changes = undef; |
|---|
| 882 | | |
|---|
| 883 | | while (!$driver->isFinished() && !$driverTargetsChanged) { |
|---|
| 884 | | # XXX: Debug. Remove this. |
|---|
| 885 | | # We assume $driver->next() returns defined data. |
|---|
| 886 | | foreach my $resource (keys %{$driver->next()->{resources}}) { |
|---|
| 887 | | $LOG->info($driverName . " - Driving To Resource: " . $resource); |
|---|
| 888 | | $lastResource = $resource; |
|---|
| 889 | | } |
|---|
| 890 | | |
|---|
| 891 | | # Drive the driver for one step. |
|---|
| 892 | | # If the operation fails, then an exception will be generated. |
|---|
| 893 | | $driver->drive(); |
|---|
| 894 | | |
|---|
| 895 | | # Perform an integrity check, if needed. |
|---|
| 896 | | if (defined($integrity)) { |
|---|
| 897 | | # For now, we update a scalar called 'is_compromised' within |
|---|
| 898 | | # the $data->{$driverName}->{'status'} sub-hashtable. |
|---|
| 899 | | $LOG->info($driverName . " - Performing Integrity Checks."); |
|---|
| 900 | | $changes = $integrity->check(); |
|---|
| 901 | | if (scalar(@{$changes->{os_processes}})) { |
|---|
| 902 | | $LOG->warn($driverName . " - Integrity Check: FAILED"); |
|---|
| 903 | | $isCompromised = 1; |
|---|
| 904 | | $changes->{'last_resource'} = $lastResource; |
|---|
| 905 | | |
|---|
| 906 | | # Release our copy of the integrity object, but do not destroy |
|---|
| 907 | | # any internal references. |
|---|
| 908 | | $integrity = undef; |
|---|
| 909 | | |
|---|
| 910 | | # Exit the while block. |
|---|
| 911 | | last; |
|---|
| 912 | | |
|---|
| 913 | | } else { |
|---|
| 914 | | $LOG->info($driverName . " - Integrity Check: PASSED"); |
|---|
| 915 | | } |
|---|
| 916 | | } |
|---|
| 917 | | |
|---|
| 918 | | # Acquire lock on stored driver state. |
|---|
| 919 | | $data = _lock(); |
|---|
| 920 | | |
|---|
| 921 | | # Check for any additional external driver updates. |
|---|
| 922 | | $driver = _update($driver); |
|---|
| 923 | | |
|---|
| 924 | | # Check to see if our driver's targets have changed. |
|---|
| 925 | | $driverTargetsChanged = not(Compare($data->{$driverName}->{'next'}->{'targets'}, $driver->next()->{'targets'})); |
|---|
| 926 | | # XXX: Delete this, eventually. |
|---|
| 927 | | if ($driverTargetsChanged) { |
|---|
| 928 | | $LOG->info($driverName . " - Driver targets have changed."); |
|---|
| 929 | | #$Data::Dumper::Terse = 0; |
|---|
| 930 | | #$Data::Dumper::Indent = 1; |
|---|
| 931 | | #print "Current: " . Dumper($data->{$driverName}->{'next'}->{'targets'}) . "\n"; |
|---|
| 932 | | #print "Next: " . Dumper($driver->next()->{'targets'}) . "\n"; |
|---|
| 933 | | } |
|---|
| 934 | | |
|---|
| 935 | | # Copy object data to shared memory. |
|---|
| 936 | | $data->{$driverName}->{'next'} = $driver->next(); |
|---|
| 937 | | $data->{$driverName}->{'status'} = $driver->status(); |
|---|
| 938 | | $data->{$driverName}->{'status'}->{'is_compromised'} = $isCompromised; |
|---|
| 939 | | $data->{$driverName}->{'status'}->{'is_running'} = 1; |
|---|
| 940 | | $data->{$driverName}->{'state'} = $driver; |
|---|
| 941 | | |
|---|
| 942 | | # Release lock on stored driver state. |
|---|
| 943 | | _unlock($data); |
|---|
| 944 | | } |
|---|
| 945 | | |
|---|
| 946 | | # XXX: This code may come in handy again, if we decide to keep the |
|---|
| 947 | | # old-style integrity checks. |
|---|
| 948 | | # Perform an integrity check, if needed. |
|---|
| 949 | | # if (defined($integrity)) { |
|---|
| 950 | | # # For now, we update a scalar called 'is_compromised' within |
|---|
| 951 | | # # the $data->{$driverName}->{'status'} sub-hashtable. |
|---|
| 952 | | # $LOG->info($driverName . " - Performing Integrity Checks."); |
|---|
| 953 | | # $changes = $integrity->check(); |
|---|
| 954 | | # if (scalar(@{$changes->{os_processes}})) { |
|---|
| 955 | | # $LOG->warn($driverName . " - Integrity Check: FAILED"); |
|---|
| 956 | | # $isCompromised = 1; |
|---|
| 957 | | # $changes->{'last_resource'} = $lastResource; |
|---|
| 958 | | # } else { |
|---|
| 959 | | # $LOG->info($driverName . " - Integrity Check: PASSED"); |
|---|
| 960 | | # } |
|---|
| 961 | | # } |
|---|
| 962 | | |
|---|
| 963 | | # Release our copy of the integrity object, but do not destroy |
|---|
| 964 | | # any internal references. |
|---|
| 965 | | $integrity = undef; |
|---|
| 966 | | |
|---|
| 967 | | # Update driver state one last time, before exiting. |
|---|
| 968 | | # Acquire lock on stored driver state. |
|---|
| 969 | | $data = _lock(); |
|---|
| 970 | | |
|---|
| 971 | | # Check for any additional external driver updates. |
|---|
| 972 | | $driver = _update($driver); |
|---|
| 973 | | |
|---|
| 974 | | # Copy object data to shared memory. |
|---|
| 975 | | $data->{$driverName}->{'next'} = $driver->next(); |
|---|
| 976 | | $data->{$driverName}->{'status'} = $driver->status(); |
|---|
| 977 | | $data->{$driverName}->{'status'}->{'is_compromised'} = $isCompromised; |
|---|
| 978 | | $data->{$driverName}->{'status'}->{'fingerprint'} = $changes; |
|---|
| 979 | | $data->{$driverName}->{'status'}->{'is_running'} = 0; |
|---|
| 980 | | $data->{$driverName}->{'state'} = $driver; |
|---|
| 981 | | |
|---|
| 982 | | # Release lock on stored driver state. |
|---|
| 983 | | _unlock($data); |
|---|
| 984 | | }; |
|---|
| 985 | | |
|---|
| 986 | | ################################### |
|---|
| 987 | | ### Driver Cleanup Phase ### |
|---|
| 988 | | ################################### |
|---|
| 989 | | |
|---|
| 990 | | # Check to see if any errors occurred within the thread. |
|---|
| 991 | | # Queue any faults found, to transmit back to the next SOAP |
|---|
| 992 | | # caller. |
|---|
| 993 | | if ($@) { |
|---|
| 994 | | # Release any pending locks, to avoid deadlocks. |
|---|
| 995 | | _unlock(); |
|---|
| 996 | | |
|---|
| 997 | | # TODO: Do proper fault queuing. |
|---|
| 998 | | $LOG->error($driverName . " - FAULT: " . $@); |
|---|
| 999 | | } |
|---|
| 1000 | | |
|---|
| 1001 | | # XXX: Debugging, remove eventually. |
|---|
| 1002 | | print $driverName . " - About to return out of child thread.\n"; |
|---|
| 1003 | | if (!threads->is_detached()) { |
|---|
| 1004 | | threads->detach(); |
|---|
| 1005 | | } |
|---|
| 1006 | | threads->exit(); |
|---|
| 1007 | | } |
|---|
| 1008 | | |
|---|
| 1009 | | # XXX: Document this. |
|---|
| 1010 | | # Should be something like: |
|---|
| 1011 | | # updateState( |
|---|
| 1012 | | # IE => { |
|---|
| 1013 | | # links => [ url1, url2, ... , ], |
|---|
| 1014 | | # params => { |
|---|
| 1015 | | # timeout => 5, |
|---|
| 1016 | | # blah => "testing", |
|---|
| 1017 | | # }, |
|---|
| 1018 | | # }, |
|---|
| 1019 | | # ) |
|---|
| 1020 | | # TODO: When updateState() hashtable data is sent across SOAP, |
|---|
| 1021 | | # we get the warning message: |
|---|
| 1022 | | # |
|---|
| 1023 | | # Cannot encode 'links_to_visit' element as 'hash'. |
|---|
| 1024 | | # Will be encoded as 'map' instead. |
|---|
| 1025 | | # |
|---|
| 1026 | | # Check to make sure this issue is not critical. |
|---|
| 1027 | | # |
|---|
| 1028 | | # We must base64 encode the data, since SOAP doesn't like URLs |
|---|
| 1029 | | # that contain amperstands. |
|---|
| 1030 | | # XXX: DELETE |
|---|
| 1031 | | sub updateState { |
|---|
| 1032 | | |
|---|
| 1033 | | # Extract arguments. |
|---|
| 1034 | | my ($class, $arg) = @_; |
|---|
| 1035 | | my %args = (); |
|---|
| 1036 | | |
|---|
| 1037 | | # Decode serialized hash. |
|---|
| 1038 | | if (defined($arg)) { |
|---|
| 1039 | | %args = %{thaw(decode_base64($arg))}; |
|---|
| 1040 | | } |
|---|
| 1041 | | |
|---|
| 1042 | | my $argsExist = scalar(%args); |
|---|
| 1043 | | |
|---|
| 1044 | | # Temporary variable, used to hold thawed driver data. |
|---|
| 1045 | | my $data = undef; |
|---|
| 1046 | | |
|---|
| 1047 | | # Temporary variable, used to hold thread IDs. |
|---|
| 1048 | | my $tid = undef; |
|---|
| 1049 | | |
|---|
| 1050 | | # Temporary variable, used to hold retrieved driver state. |
|---|
| 1051 | | my $driver = undef; |
|---|
| 1052 | | |
|---|
| 1053 | | # Temporary variable, used to hold thread objects. |
|---|
| 1054 | | my $thread = undef; |
|---|
| 1055 | | |
|---|
| 1056 | | # Figure out which driver to use. |
|---|
| 1057 | | for my $driverName (@{$ALLOWED_DRIVERS}) { |
|---|
| 1058 | | |
|---|
| 1059 | | # If the corresponding key within the argument |
|---|
| 1060 | | # hash does not exist or is not defined, then |
|---|
| 1061 | | # go ahead and skip to the next |
|---|
| 1062 | | if (!($argsExist && |
|---|
| 1063 | | exists($args{$driverName}) && |
|---|
| 1064 | | defined($args{$driverName}))) { |
|---|
| 1065 | | next; |
|---|
| 1066 | | } |
|---|
| 1067 | | |
|---|
| 1068 | | # Enqueue the updated state information. |
|---|
| 1069 | | # If this call fails, an exception is thrown or the process |
|---|
| 1070 | | # remains locked. If the process locks, then external |
|---|
| 1071 | | # detection is used to catch for these types of failures. |
|---|
| 1072 | | $driverUpdateQueues{$driverName}->enqueue(nfreeze($args{$driverName})); |
|---|
| 1073 | | |
|---|
| 1074 | | # Acquire data lock. |
|---|
| 1075 | | $data = _lock(); |
|---|
| 1076 | | |
|---|
| 1077 | | # Sanity check: See if the run() thread is already running. |
|---|
| 1078 | | $tid = $data->{$driverName}->{'thread_id'}; |
|---|
| 1079 | | if (defined($tid) && |
|---|
| 1080 | | defined($thread = threads->object($tid)) && |
|---|
| 1081 | | $thread->is_running()) { |
|---|
| 1082 | | |
|---|
| 1083 | | # The run() thread is active, so we assume that the run() thread will actually |
|---|
| 1084 | | # merge these updates into the shared driver state. |
|---|
| 1085 | | |
|---|
| 1086 | | # Release data lock. |
|---|
| 1087 | | _unlock(); |
|---|
| 1088 | | |
|---|
| 1089 | | } else { |
|---|
| 1090 | | |
|---|
| 1091 | | # If we've gotten this far, then the run() thread is no longer active, |
|---|
| 1092 | | # which means that we have to manually update the driver state |
|---|
| 1093 | | # information. |
|---|
| 1094 | | |
|---|
| 1095 | | # Initialize the driver object. |
|---|
| 1096 | | # Figure out which $driver object to use... |
|---|
| 1097 | | my $driverClass = $driverName; |
|---|
| 1098 | | |
|---|
| 1099 | | if (!defined($data->{$driverName}->{'state'})) { |
|---|
| 1100 | | |
|---|
| 1101 | | # If the existing driver state is undefined, then |
|---|
| 1102 | | # create a new state object. |
|---|
| 1103 | | $driver = $driverClass->new(); |
|---|
| 1104 | | |
|---|
| 1105 | | } else { |
|---|
| 1106 | | # Else the driver state object is already defined, |
|---|
| 1107 | | # so go ahead and reuse it. |
|---|
| 1108 | | $driver = $driverClass->new( |
|---|
| 1109 | | %{$data->{$driverName}->{'state'}}, |
|---|
| 1110 | | ); |
|---|
| 1111 | | } |
|---|
| 1112 | | |
|---|
| 1113 | | # Once we have the correct driver state (either newly initialized or |
|---|
| 1114 | | # preinitialized from a prior run() thread), we need to update this |
|---|
| 1115 | | # state with our new information. |
|---|
| 1116 | | $driver = _update($driver); |
|---|
| 1117 | | |
|---|
| 1118 | | # Copy object data to shared memory. |
|---|
| 1119 | | $data->{$driverName}->{'next'} = $driver->next(); |
|---|
| 1120 | | $data->{$driverName}->{'status'} = $driver->status(); |
|---|
| 1121 | | # XXX: This may not be ideal, as a previous compromised status indicator |
|---|
| 1122 | | # would get overwritten, during the next updateState() call. |
|---|
| 1123 | | $data->{$driverName}->{'status'}->{'is_compromised'} = 0; |
|---|
| 1124 | | $data->{$driverName}->{'status'}->{'is_running'} = 0; |
|---|
| 1125 | | $data->{$driverName}->{'state'} = $driver; |
|---|
| 1126 | | |
|---|
| 1127 | | # Release data lock. |
|---|
| 1128 | | _unlock($data); |
|---|
| 1129 | | } |
|---|
| 1130 | | } |
|---|
| 1131 | | } |
|---|
| 1132 | | |
|---|
| 1133 | | # XXX: Document this. |
|---|
| 1134 | | # XXX: DELETE |
|---|
| 1135 | | sub getState { |
|---|
| 1136 | | my $ret = undef; |
|---|
| 1137 | | _lock(); |
|---|
| 1138 | | |
|---|
| 1139 | | # Sanity check. |
|---|
| 1140 | | if (defined($driverData)) { |
|---|
| 1141 | | |
|---|
| 1142 | | # We're only interested in driver state information |
|---|
| 1143 | | # (and no other status information). Thus, we prune the |
|---|
| 1144 | | # hashtable, before transmitting. |
|---|
| 1145 | | my $data = thaw($driverData); |
|---|
| 1146 | | my $driverName = undef; |
|---|
| 1147 | | my @driverNames = keys %{$data}; |
|---|
| 1148 | | |
|---|
| 1149 | | foreach $driverName (@driverNames) { |
|---|
| 1150 | | $data->{$driverName} = $data->{$driverName}->{'state'}; |
|---|
| 1151 | | } |
|---|
| 1152 | | $ret = encode_base64(nfreeze($data)); |
|---|
| 1153 | | } |
|---|
| 1154 | | _unlock(); |
|---|
| 1155 | | return $ret; |
|---|
| 1156 | | } |
|---|
| 1157 | | |
|---|
| 1158 | | # XXX: DELETE |
|---|
| 1159 | | # XXX: Document this. |
|---|
| 1160 | | sub getStatus { |
|---|
| 1161 | | my $ret = undef; |
|---|
| 1162 | | _lock(); |
|---|
| 1163 | | if (defined($driverData)) { |
|---|
| 1164 | | $ret = encode_base64($driverData); |
|---|
| 1165 | | } |
|---|
| 1166 | | _unlock(); |
|---|
| 1167 | | return $ret; |
|---|
| 1168 | | } |
|---|
| 1169 | | |
|---|
| 1170 | | # XXX: DELETE |
|---|
| 1171 | | # XXX: Document this. |
|---|
| 1172 | | # XXX: Do we really need this? |
|---|
| 1173 | | sub shutdown { |
|---|
| 1174 | | |
|---|
| 1175 | | print "Shutting down...\n"; |
|---|
| 1176 | | |
|---|
| 1177 | | # Shutdown in 5 seconds after returning. |
|---|
| 1178 | | my $thread = async { |
|---|
| 1179 | | threads->yield(); |
|---|
| 1180 | | sleep(5); |
|---|
| 1181 | | exit; |
|---|
| 1182 | | }; |
|---|
| 1183 | | |
|---|
| 1184 | | # Return true. |
|---|
| 1185 | | return 1; |
|---|
| 1186 | | } |
|---|
| 1187 | | |
|---|
| 1188 | | # XXX: DELETE |
|---|
| 1189 | | # XXX: Document this. |
|---|
| 1190 | | # TODO: Make this more robust. |
|---|
| 1191 | | sub killProcess { |
|---|
| 1192 | | |
|---|
| 1193 | | # Extract arguments. |
|---|
| 1194 | | my ($class, $processName) = @_; |
|---|
| 1195 | | |
|---|
| 1196 | | # Sanity check. |
|---|
| 1197 | | unless (defined($processName)) { |
|---|
| 1198 | | return 0; |
|---|
| 1199 | | } |
|---|
| 1200 | | |
|---|
| 1201 | | # TODO: Need unit tests. |
|---|
| 1202 | | require Win32::Process; |
|---|
| 1203 | | require Win32::Process::Info; |
|---|
| 1204 | | |
|---|
| 1205 | | # Create a new process inspector. |
|---|
| 1206 | | my $inspector = Win32::Process::Info->new(); |
|---|
| 1207 | | my @procs = $inspector->GetProcInfo(); |
|---|
| 1208 | | |
|---|
| 1209 | | foreach my $proc (@procs) { |
|---|
| 1210 | | if ($proc->{Name} eq $processName) { |
|---|
| 1211 | | # TODO: Should this statement be in here? |
|---|
| 1212 | | $LOG->warn("Killing Process ID: " . $proc->{ProcessId}); |
|---|
| 1213 | | Carp::carp "Killing Process ID: " . $proc->{ProcessId} . "\n"; |
|---|
| 1214 | | Win32::Process::KillProcess($proc->{ProcessId}, 0); |
|---|
| 1215 | | } |
|---|
| 1216 | | } |
|---|
| 1217 | | |
|---|
| 1218 | | return 1; |
|---|
| 1219 | | } |
|---|
| 1220 | | |
|---|