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) {
144 ConnectionSet::iterator ci;
145 for (ci = _connections.begin(); ci != _connections.end(); ++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");
217DirectD::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;
260DirectD::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;
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();
314DirectD::handle_command(
const string& cmd) {
315 nout<<
"DirectD::handle_command: "<<cmd<<endl;
319DirectD::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);
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;
383 _connections.erase(i);
390DirectD::check_for_lost_connection() {
394 nout<<
"Lost connection from "<<c->get_address()<<endl;
395 _connections.erase(c);
402DirectD::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";
427DirectD::check_for_new_clients() {
433 nout <<
"Got connection from " << address <<
"\n";
435 _connections.insert(new_connection);
PT(Connection) open_TCP_client_connection(const std bool close_connection(const PT(Connection) &connection)
Terminates a UDP or TCP socket previously opened.
bool remove_connection(Connection *connection)
Removes a socket from the list of sockets being monitored.
bool add_connection(Connection *connection)
Adds a new socket to the list of sockets the ConnectionReader will monitor.
bool send(const Datagram &datagram, const PT(Connection) &connection, bool block=false)
Enqueues a datagram for transmittal on the indicated socket.
Represents a single TCP or UDP socket for input or output.
A class to retrieve the individual data elements previously stored in a Datagram.
std::string get_string()
Extracts a variable-length string.
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 add_string(const std::string &str)
Adds a variable-length string to the datagram.
void send_command(const std::string &cmd)
Send the same command string to all current connections.
int tell_server(const std::string &server_host, int port, const std::string &cmd)
Tell the server to do the command cmd.
int server_ready(const std::string &client_host, int port)
Call this function from the server when import ShowbaseGlobal is nearly finished.
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.
void disconnect_from(const std::string &server_host, int port)
This is the counterpart to connect_to().
void listen_to(int port, int backlog=8)
Call listen_to in the server.
bool wait_for_servers(int count, int timeout_ms=2 *60 *1000)
Call this function from the client after calling <count> client_ready() calls.
int connect_to(const std::string &server_host, int port)
Call connect_to from client for each server.
Represents a network address to which UDP packets may be sent or to which a TCP socket may be bound.
bool set_host(const std::string &hostname, int port)
Sets the address up to refer to a particular port on a particular host.
A specific kind of Datagram, especially for sending across or receiving from a network.
const NetAddress & get_address() const
Retrieves the host from which the datagram was read, or to which it is scheduled to be sent.
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...
bool new_connection_available()
Returns true if a new connection was recently established; the connection information may then be ret...
bool reset_connection_available() const
Returns true if one of the readers/writers/listeners reported a connection reset recently.
bool get_reset_connection(PT(Connection) &connection)
If a previous call to reset_connection_available() returned true, this function will return informati...
bool get_data(NetDatagram &result)
If a previous call to data_available() returned true, this function will return the datagram that has...
bool data_available()
Returns true if a datagram is available on the queue; call get_data() to extract the datagram.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.