16 #define _WIN32_WINNT 0x0500 33 #if !defined(CPPPARSER) && !defined(LINK_ALL_STATIC) && !defined(BUILDING_DIRECT_DIRECTD) 34 #error Buildsystem error: BUILDING_DIRECT_DIRECTD not defined 50 #define TA_SUCCESS_CLEAN 1 51 #define TA_SUCCESS_KILL 2 52 #define TA_SUCCESS_16 3 55 TerminateAppEnum(HWND hwnd, LPARAM lParam) {
57 GetWindowThreadProcessId(hwnd, &dwID);
58 if(dwID == (DWORD)lParam) {
59 PostMessage(hwnd, WM_CLOSE, 0, 0);
84 TerminateApp(DWORD dwPID, DWORD dwTimeout) {
90 hProc = OpenProcess(SYNCHRONIZE|PROCESS_TERMINATE, FALSE, dwPID);
91 if(hProc ==
nullptr) {
97 EnumWindows((WNDENUMPROC)TerminateAppEnum, (LPARAM)dwPID);
101 if(WaitForSingleObject(hProc, dwTimeout)!=WAIT_OBJECT_0) {
102 dwRet=(TerminateProcess(hProc,0)?TA_SUCCESS_KILL:TA_FAILED);
104 dwRet = TA_SUCCESS_CLEAN;
116 StartApp(
const string& cmd) {
119 PROCESS_INFORMATION pi;
120 ZeroMemory(&si,
sizeof(STARTUPINFO));
121 si.cb =
sizeof(STARTUPINFO);
122 ZeroMemory(&pi,
sizeof(PROCESS_INFORMATION));
123 if (CreateProcess(
nullptr, (
char*)cmd.c_str(),
124 0, 0, 1, NORMAL_PRIORITY_CLASS,
127 CloseHandle(pi.hProcess);
128 CloseHandle(pi.hThread);
130 nout<<
"CreateProcess failed: "<<cmd<<endl;
138 _reader(&_cm, 1), _writer(&_cm, 0), _listener(&_cm, 0),
139 _jobObject(0), _shutdown(false), _useOldStuff(false) {
142 DirectD::~DirectD() {
144 ConnectionSet::iterator ci;
145 for (ci = _connections.begin(); ci != _connections.end(); ++ci) {
146 _cm.close_connection((*ci));
148 _connections.clear();
156 std::stringstream ss;
158 send_one_message(server_host, port, ss.str());
165 send_one_message(server_host, port, cmd);
175 const int wait_ms=200;
176 int cycles=timeout_ms/wait_ms;
178 check_for_new_clients();
179 check_for_lost_connection();
188 cout << count <<
": Server at " << datagram.
get_address()
189 <<
" is ready." << endl;
194 if (s==
"r" && !--count) {
211 send_one_message(client_host, port,
"r");
217 DirectD::start_app(
const string& cmd) {
218 nout<<
"start_app(cmd="<<cmd<<
")"<<endl;
220 _pids.push_back(StartApp(cmd));
221 nout<<
" pid="<<_pids.back()<<endl;
224 _jobObject=CreateJobObject(0, 0);
226 nout<<
"CreateProcess failed: no _jobObject: "<<GetLastError()<<endl;
232 PROCESS_INFORMATION pi;
233 ZeroMemory(&si,
sizeof(STARTUPINFO));
234 si.cb =
sizeof(STARTUPINFO);
235 ZeroMemory(&pi,
sizeof(PROCESS_INFORMATION));
236 if (CreateProcess(
nullptr, (
char*)cmd.c_str(),
237 0, 0, 1, NORMAL_PRIORITY_CLASS | CREATE_SUSPENDED,
242 if (!AssignProcessToJobObject(_jobObject, pi.hProcess)) {
244 cerr<<
"StartJob AssignProcessToJobObject Error: "<<GetLastError()<<endl;
246 CloseHandle(pi.hProcess);
249 if (ResumeThread(pi.hThread) == -1) {
250 cerr<<
"StartJob ResumeThread Error: "<<GetLastError()<<endl;
252 CloseHandle(pi.hThread);
254 nout<<
"StartJob CreateProcess failed: "<<cmd<<endl;
260 DirectD::kill_app(
int index) {
262 int i = _pids.size() - 1 - index % _pids.size();
263 PidStack::iterator pi = _pids.begin() + i;
264 if (pi!=_pids.end()) {
265 nout<<
"trying kill "<<(*pi)<<endl;
266 TerminateApp((*pi), 1000);
270 cerr<<
"kill_app(index) not implemented, calling kill_all() instead."<<endl;
276 DirectD::kill_all() {
278 PidStack::reverse_iterator pi;
279 for (pi = _pids.rbegin(); pi != _pids.rend(); ++pi) {
280 nout<<
"trying kill "<<(*pi)<<endl;
281 TerminateApp((*pi), 1000);
286 cerr<<
"kill_all(): No open _jobObject"<<endl;
287 }
else if (!TerminateJobObject(_jobObject, 0)) {
288 cerr<<
"kill_all() TerminateJobObject Error: "<<GetLastError()<<endl;
290 CloseHandle(_jobObject);
300 ConnectionSet::iterator ci;
301 for (ci = _connections.begin(); ci != _connections.end(); ++ci) {
302 _writer.
send(datagram, (*ci));
309 string cmd=di.get_string();
314 DirectD::handle_command(
const string& cmd) {
315 nout<<
"DirectD::handle_command: "<<cmd<<endl;
319 DirectD::send_one_message(
const string& host_name,
321 const string& message) {
323 if (!host.
set_host(host_name, port)) {
324 nout <<
"Unknown host: " << host_name <<
"\n";
327 const int timeout_ms=5000;
328 PT(
Connection) c = _cm.open_TCP_client_connection(host, timeout_ms);
330 nout <<
"No connection.\n";
334 nout <<
"Successfully opened TCP connection to " << host_name
336 << c->get_address().get_port() <<
" and IP " 337 << c->get_address() <<
"\n";
343 _writer.
send(datagram, c);
347 _cm.close_connection(c);
353 if (!host.
set_host(host_name, port)) {
354 nout <<
"Unknown host: " << host_name <<
"\n";
357 const int timeout_ms=5000;
358 PT(
Connection) c = _cm.open_TCP_client_connection(host, timeout_ms);
360 nout <<
"No connection.\n";
364 nout <<
"Successfully opened TCP connection to " << host_name
366 << c->get_address().get_port() <<
" and IP " 367 << c->get_address() <<
"\n";
370 _connections.insert(c);
371 return c->get_address().get_port();
376 nout<<
"disconnect_from(\""<<host_name<<
", port="<<port<<
")"<<endl;
377 for (ConnectionSet::iterator i=_connections.begin(); i != _connections.end(); ++i) {
378 nout<<
" found "<<(*i)->get_address().get_ip_string()<<
", port "<<(*i)->get_address().get_port()<<endl;
379 if ((*i)->get_address().get_ip_string()==host_name) {
380 nout<<
" disconnecting."<<endl;
382 _cm.close_connection((*i));
383 _connections.erase(i);
390 DirectD::check_for_lost_connection() {
394 nout<<
"Lost connection from "<<c->get_address()<<endl;
395 _connections.erase(c);
396 _cm.close_connection(c);
402 DirectD::check_for_datagrams(){
407 nout <<
"Got datagram " "from " 410 handle_datagram(datagram);
417 PT(
Connection) rendezvous = _cm.open_TCP_server_rendezvous(port, backlog);
418 if (rendezvous.is_null()) {
419 nout <<
"Cannot grab port " << port <<
".\n";
422 nout <<
"Listening for connections on port " << port <<
"\n";
427 DirectD::check_for_new_clients() {
433 nout <<
"Got connection from " << address <<
"\n";
435 _connections.insert(new_connection);
A specific kind of Datagram, especially for sending across or receiving from a network.
bool send(const Datagram &datagram, const PT(Connection) &connection, bool block=false)
Enqueues a datagram for transmittal on the indicated socket.
int tell_server(const std::string &server_host, int port, const std::string &cmd)
Tell the server to do the command cmd.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void dump_hex(std::ostream &out, unsigned int indent=0) const
Writes a representation of the entire datagram contents, as a sequence of hex (and ASCII) values.
void disconnect_from(const std::string &server_host, int port)
This is the counterpart to connect_to().
bool get_reset_connection(PT(Connection) &connection)
If a previous call to reset_connection_available() returned true, this function will return informati...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
int server_ready(const std::string &client_host, int port)
Call this function from the server when import ShowbaseGlobal is nearly finished.
std::string get_string()
Extracts a variable-length string.
bool reset_connection_available() const
Returns true if one of the readers/writers/listeners reported a connection reset recently.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
const NetAddress & get_address() const
Retrieves the host from which the datagram was read, or to which it is scheduled to be sent.
int connect_to(const std::string &server_host, int port)
Call connect_to from client for each server.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
int client_ready(const std::string &server_host, int port, const std::string &cmd)
Call this function from the client when import ShowbaseGlobal is nearly finished.
bool data_available()
Returns true if a datagram is available on the queue; call get_data() to extract the datagram.
bool set_host(const std::string &hostname, int port)
Sets the address up to refer to a particular port on a particular host.
void listen_to(int port, int backlog=8)
Call listen_to in the server.
void add_string(const std::string &str)
Adds a variable-length string to the datagram.
bool new_connection_available()
Returns true if a new connection was recently established; the connection information may then be ret...
bool remove_connection(Connection *connection)
Removes a socket from the list of sockets being monitored.
bool wait_for_servers(int count, int timeout_ms=2 *60 *1000)
Call this function from the client after calling <count> client_ready() calls.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void send_command(const std::string &cmd)
Send the same command string to all current connections.
bool get_data(NetDatagram &result)
If a previous call to data_available() returned true, this function will return the datagram that has...
bool add_connection(Connection *connection)
Adds a new socket to the list of sockets the ConnectionReader will monitor.
A class to retrieve the individual data elements previously stored in a Datagram.
Represents a single TCP or UDP socket for input or output.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
bool get_new_connection(PT(Connection) &rendezvous, NetAddress &address, PT(Connection) &new_connection)
If a previous call to new_connection_available() returned true, this function will return information...
Represents a network address to which UDP packets may be sent or to which a TCP socket may be bound.