00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #define _WIN32_WINNT 0x0500
00022
00023 #include "directd.h"
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035 #include "netAddress.h"
00036 #include "connection.h"
00037 #include "datagramIterator.h"
00038 #include "netDatagram.h"
00039
00040 #include "pset.h"
00041
00042 namespace {
00043
00044
00045
00046
00047
00048 #define TA_FAILED 0
00049 #define TA_SUCCESS_CLEAN 1
00050 #define TA_SUCCESS_KILL 2
00051 #define TA_SUCCESS_16 3
00052
00053 BOOL CALLBACK
00054 TerminateAppEnum(HWND hwnd, LPARAM lParam) {
00055 DWORD dwID;
00056 GetWindowThreadProcessId(hwnd, &dwID);
00057 if(dwID == (DWORD)lParam) {
00058 PostMessage(hwnd, WM_CLOSE, 0, 0);
00059 }
00060 return TRUE;
00061 }
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082 DWORD WINAPI
00083 TerminateApp(DWORD dwPID, DWORD dwTimeout) {
00084 HANDLE hProc;
00085 DWORD dwRet;
00086
00087
00088
00089 hProc = OpenProcess(SYNCHRONIZE|PROCESS_TERMINATE, FALSE, dwPID);
00090 if(hProc == NULL) {
00091 return TA_FAILED;
00092 }
00093
00094
00095
00096 EnumWindows((WNDENUMPROC)TerminateAppEnum, (LPARAM)dwPID);
00097
00098
00099
00100 if(WaitForSingleObject(hProc, dwTimeout)!=WAIT_OBJECT_0) {
00101 dwRet=(TerminateProcess(hProc,0)?TA_SUCCESS_KILL:TA_FAILED);
00102 } else {
00103 dwRet = TA_SUCCESS_CLEAN;
00104 }
00105 CloseHandle(hProc);
00106
00107 return dwRet;
00108 }
00109
00110
00111
00112
00113
00114 DWORD
00115 StartApp(const string& cmd) {
00116 DWORD pid=0;
00117 STARTUPINFO si;
00118 PROCESS_INFORMATION pi;
00119 ZeroMemory(&si, sizeof(STARTUPINFO));
00120 si.cb = sizeof(STARTUPINFO);
00121 ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
00122 if (CreateProcess(NULL, (char*)cmd.c_str(),
00123 0, 0, 1, NORMAL_PRIORITY_CLASS,
00124 0, 0, &si, &pi)) {
00125 pid=pi.dwProcessId;
00126 CloseHandle(pi.hProcess);
00127 CloseHandle(pi.hThread);
00128 } else {
00129 nout<<"CreateProcess failed: "<<cmd<<endl;
00130 }
00131 return pid;
00132 }
00133
00134 }
00135
00136 DirectD::DirectD() :
00137 _reader(&_cm, 1), _writer(&_cm, 0), _listener(&_cm, 0),
00138 _jobObject(0), _shutdown(false), _useOldStuff(false) {
00139 }
00140
00141 DirectD::~DirectD() {
00142
00143 ConnectionSet::iterator ci;
00144 for (ci = _connections.begin(); ci != _connections.end(); ++ci) {
00145 _cm.close_connection((*ci));
00146 }
00147 _connections.clear();
00148
00149 kill_all();
00150 }
00151
00152 int
00153 DirectD::client_ready(const string& server_host, int port,
00154 const string& cmd) {
00155 stringstream ss;
00156 ss<<"!"<<cmd;
00157 send_one_message(server_host, port, ss.str());
00158 return 0;
00159 }
00160
00161 int
00162 DirectD::tell_server(const string& server_host, int port,
00163 const string& cmd) {
00164 send_one_message(server_host, port, cmd);
00165 return 0;
00166 }
00167
00168 bool
00169 DirectD::wait_for_servers(int count, int timeout_ms) {
00170 if (count <= 0) {
00171 return true;
00172 }
00173
00174 const wait_ms=200;
00175 int cycles=timeout_ms/wait_ms;
00176 while (cycles--) {
00177 check_for_new_clients();
00178 check_for_lost_connection();
00179
00180
00181
00182
00183
00184
00185 while (_reader.data_available()) {
00186 NetDatagram datagram;
00187 if (_reader.get_data(datagram)) {
00188 cout << count << ": Server at " << datagram.get_address()
00189 << " is ready." << endl;
00190 datagram.dump_hex(nout);
00191
00192 DatagramIterator di(datagram);
00193 string s=di.get_string();
00194 if (s=="r" && !--count) {
00195 return true;
00196 }
00197 }
00198 }
00199
00200
00201 PR_Sleep(PR_MillisecondsToInterval(wait_ms));
00202 }
00203
00204
00205 return false;
00206 }
00207
00208 int
00209 DirectD::server_ready(const string& client_host, int port) {
00210 send_one_message(client_host, port, "r");
00211 return 0;
00212 }
00213
00214
00215 void
00216 DirectD::start_app(const string& cmd) {
00217 nout<<"start_app(cmd="<<cmd<<")"<<endl;
00218 if (_useOldStuff) {
00219 _pids.push_back(StartApp(cmd));
00220 nout<<" pid="<<_pids.back()<<endl;
00221 } else {
00222 if (!_jobObject) {
00223 _jobObject=CreateJobObject(0, 0);
00224 if (!_jobObject) {
00225 nout<<"CreateProcess failed: no _jobObject: "<<GetLastError()<<endl;
00226 return;
00227 }
00228 }
00229 DWORD pid=0;
00230 STARTUPINFO si;
00231 PROCESS_INFORMATION pi;
00232 ZeroMemory(&si, sizeof(STARTUPINFO));
00233 si.cb = sizeof(STARTUPINFO);
00234 ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
00235 if (CreateProcess(NULL, (char*)cmd.c_str(),
00236 0, 0, 1, NORMAL_PRIORITY_CLASS | CREATE_SUSPENDED,
00237 0, 0, &si, &pi)) {
00238
00239
00240
00241 if (!AssignProcessToJobObject(_jobObject, pi.hProcess)) {
00242
00243 cerr<<"StartJob AssignProcessToJobObject Error: "<<GetLastError()<<endl;
00244 }
00245 CloseHandle(pi.hProcess);
00246
00247
00248 if (ResumeThread(pi.hThread) == -1) {
00249 cerr<<"StartJob ResumeThread Error: "<<GetLastError()<<endl;
00250 }
00251 CloseHandle(pi.hThread);
00252 } else {
00253 nout<<"StartJob CreateProcess failed: "<<cmd<<endl;
00254 }
00255 }
00256 }
00257
00258 void
00259 DirectD::kill_app(int index) {
00260 if (_useOldStuff) {
00261 int i = _pids.size() - 1 - index % _pids.size();
00262 PidStack::iterator pi = _pids.begin() + i;
00263 if (pi!=_pids.end()) {
00264 nout<<"trying kill "<<(*pi)<<endl;
00265 TerminateApp((*pi), 1000);
00266 _pids.erase(pi);
00267 }
00268 } else {
00269 cerr<<"kill_app(index) not implemented, calling kill_all() instead."<<endl;
00270 kill_all();
00271 }
00272 }
00273
00274 void
00275 DirectD::kill_all() {
00276 if (_useOldStuff) {
00277 PidStack::reverse_iterator pi;
00278 for (pi = _pids.rbegin(); pi != _pids.rend(); ++pi) {
00279 nout<<"trying kill "<<(*pi)<<endl;
00280 TerminateApp((*pi), 1000);
00281 }
00282 _pids.clear();
00283 } else {
00284 if (!_jobObject) {
00285 cerr<<"kill_all(): No open _jobObject"<<endl;
00286 } else if (!TerminateJobObject(_jobObject, 0)) {
00287 cerr<<"kill_all() TerminateJobObject Error: "<<GetLastError()<<endl;
00288 }
00289 CloseHandle(_jobObject);
00290 _jobObject=0;
00291 }
00292 }
00293
00294 void
00295 DirectD::send_command(const string& cmd) {
00296 NetDatagram datagram;
00297 datagram.add_string(cmd);
00298
00299 ConnectionSet::iterator ci;
00300 for (ci = _connections.begin(); ci != _connections.end(); ++ci) {
00301 _writer.send(datagram, (*ci));
00302 }
00303 }
00304
00305 void
00306 DirectD::handle_datagram(NetDatagram& datagram){
00307 DatagramIterator di(datagram);
00308 string cmd=di.get_string();
00309 handle_command(cmd);
00310 }
00311
00312 void
00313 DirectD::handle_command(const string& cmd) {
00314 nout<<"DirectD::handle_command: "<<cmd<<endl;
00315 }
00316
00317 void
00318 DirectD::send_one_message(const string& host_name,
00319 int port,
00320 const string& message) {
00321 NetAddress host;
00322 if (!host.set_host(host_name, port)) {
00323 nout << "Unknown host: " << host_name << "\n";
00324 }
00325
00326 const int timeout_ms=5000;
00327 PT(Connection) c = _cm.open_TCP_client_connection(host, timeout_ms);
00328 if (c.is_null()) {
00329 nout << "No connection.\n";
00330 return;
00331 }
00332
00333 nout << "Successfully opened TCP connection to " << host_name
00334 << " on port "
00335 << c->get_address().get_port() << " and IP "
00336 << c->get_address() << "\n";
00337
00338
00339
00340 NetDatagram datagram;
00341 datagram.add_string(message);
00342 _writer.send(datagram, c);
00343
00344
00345
00346
00347 _cm.close_connection(c);
00348 }
00349
00350 int
00351 DirectD::connect_to(const string& host_name, int port) {
00352 NetAddress host;
00353 if (!host.set_host(host_name, port)) {
00354 nout << "Unknown host: " << host_name << "\n";
00355 }
00356
00357 const int timeout_ms=5000;
00358 PT(Connection) c = _cm.open_TCP_client_connection(host, timeout_ms);
00359 if (c.is_null()) {
00360 nout << "No connection.\n";
00361 return 0;
00362 }
00363
00364 nout << "Successfully opened TCP connection to " << host_name
00365 << " on port "
00366 << c->get_address().get_port() << " and IP "
00367 << c->get_address() << "\n";
00368
00369 _reader.add_connection(c);
00370 _connections.insert(c);
00371 return c->get_address().get_port();
00372 }
00373
00374 void
00375 DirectD::disconnect_from(const string& host_name, int port) {
00376 nout<<"disconnect_from(\""<<host_name<<", port="<<port<<")"<<endl;
00377 for (ConnectionSet::iterator i=_connections.begin(); i != _connections.end(); ++i) {
00378 nout<<" found "<<(*i)->get_address().get_ip_string()<<", port "<<(*i)->get_address().get_port()<<endl;
00379 if ((*i)->get_address().get_ip_string()==host_name) {
00380 nout<<" disconnecting."<<endl;
00381 _reader.remove_connection((*i));
00382 _cm.close_connection((*i));
00383 _connections.erase(i);
00384 break;
00385 }
00386 }
00387 }
00388
00389 void
00390 DirectD::check_for_lost_connection() {
00391 while (_cm.reset_connection_available()) {
00392 PT(Connection) c;
00393 if (_cm.get_reset_connection(c)) {
00394 nout<<"Lost connection from "<<c->get_address()<<endl;
00395 _connections.erase(c);
00396 _cm.close_connection(c);
00397 }
00398 }
00399 }
00400
00401 void
00402 DirectD::check_for_datagrams(){
00403
00404 while (_reader.data_available()) {
00405 NetDatagram datagram;
00406 if (_reader.get_data(datagram)) {
00407 nout << "Got datagram " "from "
00408 << datagram.get_address() << endl;
00409 datagram.dump_hex(nout);
00410 handle_datagram(datagram);
00411 }
00412 }
00413 }
00414
00415 void
00416 DirectD::listen_to(int port, int backlog) {
00417 PT(Connection) rendezvous = _cm.open_TCP_server_rendezvous(port, backlog);
00418 if (rendezvous.is_null()) {
00419 nout << "Cannot grab port " << port << ".\n";
00420 exit(1);
00421 }
00422 nout << "Listening for connections on port " << port << "\n";
00423 _listener.add_connection(rendezvous);
00424 }
00425
00426 void
00427 DirectD::check_for_new_clients() {
00428 while (_listener.new_connection_available()) {
00429 PT(Connection) rv;
00430 NetAddress address;
00431 PT(Connection) new_connection;
00432 if (_listener.get_new_connection(rv, address, new_connection)) {
00433 nout << "Got connection from " << address << "\n";
00434 _reader.add_connection(new_connection);
00435 _connections.insert(new_connection);
00436 }
00437 }
00438 }