00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #ifdef HAVE_CONFIG_H
00023 # include <config.h>
00024 #endif
00025
00026
00027 #if defined(WIN32) && defined(USE_EXULTSTUDIO)
00028
00029 #include <iostream>
00030 #include <cstring>
00031 #include "servemsg.h"
00032 #include "servewin32.h"
00033
00034 using std::cout;
00035 using std::cerr;
00036 using std::endl;
00037
00038 namespace Exult_server
00039 {
00040 static HANDLE hPipeRead = INVALID_HANDLE_VALUE;
00041 static HANDLE hPipeWrite = INVALID_HANDLE_VALUE;
00042
00043 static OVERLAPPED oOverlap;
00044 static LPOVERLAPPED lpOverlap = 0;
00045 static OVERLAPPED oOverlapCon;
00046 static LPOVERLAPPED lpOverlapCon = 0;
00047 static BOOL bWinNT = FALSE;
00048 static BOOL bClient = FALSE;
00049 static BOOL bBroken = FALSE;
00050 static BOOL bNotifyDis = FALSE;
00051
00052 static const char * const pipe_name = "\\\\.\\pipe\\exultserver-";
00053 static const char * const mail_server = "\\\\.\\mailslot\\exultserver-";
00054 static const char * const mail_client = "\\\\.\\mailslot\\exultclient-";
00055
00056
00057
00058 static char *get_pipe_name(const char *static_path, const char * const pipe_name = Exult_server::pipe_name, bool ms = false)
00059 {
00060
00061 if (!std::strncmp(static_path, "\\\\.\\pipe\\", std::strlen("\\\\.\\pipe\\"))) {
00062 char *path = new char[std::strlen(static_path)+1];
00063 return std::strcpy(path, static_path);
00064 }
00065
00066
00067 if (!std::strncmp(static_path, "\\\\.\\mailslot\\", std::strlen("\\\\.\\mailslot\\"))) {
00068 char *path = new char[std::strlen(static_path)+1];
00069 return std::strcpy(path, static_path);
00070 }
00071
00072 int num_chars = GetShortPathName(static_path, NULL, 0);
00073 int head_len = std::strlen(pipe_name);
00074 char *actual_path;
00075
00076 if (num_chars) {
00077 char *temp = new char[num_chars+1];
00078 GetShortPathName(static_path, temp, num_chars+1);
00079 num_chars = GetFullPathName(temp, 0, NULL, NULL);
00080 actual_path = new char[num_chars+head_len+1];
00081 char *temp2;
00082 GetFullPathName(temp, num_chars+1, actual_path+head_len, &temp2);
00083 }
00084 else {
00085 cout << "Unable to find actual static path" << endl;
00086 return 0;
00087 }
00088
00089 std::memcpy (actual_path, pipe_name,head_len);
00090
00091 if (!ms){
00092 for (char *temp = actual_path+head_len; *temp; temp++)
00093 if (*temp == '\\') *temp = '/';
00094 }
00095 else {
00096 for (char *temp = actual_path+head_len; *temp; temp++)
00097 if (*temp == '/') *temp = '\\';
00098 else if (*temp == ':') *temp = '_';
00099 }
00100
00101 if (std::strlen(actual_path) > 255)actual_path[255] = 0;
00102
00103 while (actual_path[std::strlen(actual_path)-1] == '/') actual_path[std::strlen(actual_path)-1] = 0;
00104 while (actual_path[std::strlen(actual_path)-1] == '\\') actual_path[std::strlen(actual_path)-1] = 0;
00105
00106 return actual_path;
00107 }
00108
00109 static void detect_winnt()
00110 {
00111 OSVERSIONINFO info;
00112 info.dwOSVersionInfoSize = sizeof (info);
00113 GetVersionEx (&info);
00114
00115
00116 if (info.dwPlatformId == 2 && (info.dwMajorVersion > 5 ||
00117 (info.dwMajorVersion == 5 && info.dwMinorVersion >= 1)))
00118 bWinNT = TRUE;
00119 }
00120
00121
00122 static bool setup_overlap()
00123 {
00124 memset(&oOverlap,0, sizeof (oOverlap));
00125 memset(&oOverlapCon,0, sizeof (oOverlapCon));
00126
00127
00128 if (bWinNT)
00129 {
00130
00131 oOverlap.hEvent = CreateEvent (NULL, TRUE, TRUE, NULL);
00132 lpOverlap = &oOverlap;
00133 oOverlapCon.hEvent = CreateEvent (NULL, TRUE, TRUE, NULL);
00134 lpOverlapCon = &oOverlapCon;
00135
00136 return true;
00137 }
00138
00139 return false;
00140 }
00141
00142 static void free_overlap()
00143 {
00144 if (oOverlap.hEvent) CloseHandle(oOverlap.hEvent);
00145 oOverlap.hEvent = 0;
00146 lpOverlap = 0;
00147
00148 if (oOverlapCon.hEvent) CloseHandle(oOverlapCon.hEvent);
00149 oOverlapCon.hEvent = 0;
00150 lpOverlapCon = 0;
00151
00152 }
00153
00154
00155 static bool setup_server_mailslots(const char *static_path, bool both)
00156 {
00157
00158 if (hPipeRead == INVALID_HANDLE_VALUE)
00159 {
00160 char *server_name = Exult_server::get_pipe_name(static_path,mail_server, true);
00161 hPipeRead = CreateMailslot(server_name, 1024, 0, NULL);
00162
00163 if (hPipeRead == INVALID_HANDLE_VALUE) {
00164 std::cout << "Unable to create mailslot : " << server_name << " Code " << GetLastError() << std::endl;
00165 delete [] server_name ;
00166 return false;
00167 }
00168
00169
00170
00171 delete [] server_name ;
00172 if (!both) return true;
00173 }
00174
00175
00176 if (hPipeWrite == INVALID_HANDLE_VALUE)
00177 {
00178 char *client_name = Exult_server::get_pipe_name(static_path,mail_client, true);
00179
00180 hPipeWrite = CreateFile (client_name,
00181 GENERIC_WRITE,
00182 FILE_SHARE_READ,
00183 NULL,
00184 OPEN_EXISTING,
00185 FILE_ATTRIBUTE_NORMAL,
00186 NULL);
00187
00188 if (hPipeWrite == INVALID_HANDLE_VALUE) {
00189
00190 delete [] client_name;
00191 return false;
00192 }
00193
00194 delete [] client_name ;
00195 }
00196
00197 return true;
00198 }
00199
00200
00201 static bool setup_client_mailslots(const char *static_path)
00202 {
00203
00204 if (hPipeWrite == INVALID_HANDLE_VALUE)
00205 {
00206 char *server_name = Exult_server::get_pipe_name(static_path,mail_server, true);
00207
00208 hPipeWrite = CreateFile (server_name,
00209 GENERIC_WRITE,
00210 FILE_SHARE_READ,
00211 NULL,
00212 OPEN_EXISTING,
00213 FILE_ATTRIBUTE_NORMAL,
00214 NULL);
00215
00216 if (hPipeWrite == INVALID_HANDLE_VALUE) {
00217
00218 delete [] server_name;
00219 return false;
00220 }
00221
00222 delete [] server_name ;
00223 }
00224
00225
00226 if (hPipeRead == INVALID_HANDLE_VALUE)
00227 {
00228 char *client_name = Exult_server::get_pipe_name(static_path,mail_client, true);
00229 hPipeRead = CreateMailslot(client_name, 1024, 0, NULL);
00230
00231 if (hPipeRead == INVALID_HANDLE_VALUE) {
00232 std::cout << "Unable to create mailslot : " << client_name << " Code " << GetLastError() << std::endl;
00233 delete [] client_name ;
00234 CloseHandle(hPipeWrite);
00235 hPipeWrite = INVALID_HANDLE_VALUE;
00236 return false;
00237 }
00238
00239
00240 delete [] client_name ;
00241 }
00242
00243 return true;
00244 }
00245
00246
00247 int write(int file, const void *v, unsigned int len)
00248 {
00249 DWORD num_written;
00250
00251 BOOL failed = !WriteFile(hPipeWrite, v, len, &num_written, lpOverlap);
00252
00253 const unsigned char *data = (unsigned char *)v;
00254
00255
00256
00257
00258 if ((!bWinNT && failed) || GetLastError() == ERROR_BROKEN_PIPE) {
00259 std::cout << "Broken!" << std::endl;
00260 bBroken = TRUE;
00261 return 0;
00262 }
00263
00264 if (num_written == 0) return -1;
00265
00266 return num_written;
00267 }
00268
00269 static unsigned char buf[2048];
00270 static unsigned int offset = 2048;
00271 static unsigned int num_left = 0;
00272
00273 int read_win9x(int file, unsigned char *v, unsigned int len)
00274 {
00275 DWORD num_read;
00276
00277
00278
00279
00280 if (num_left == 0)
00281 {
00282 int total = peek_pipe();
00283
00284 if (total >= 2048) {
00285 std::cerr << "Buffer too small. Read failed" << std::endl;
00286 return 0;
00287 }
00288 else if (total == 0) {
00289 return 0;
00290 }
00291 else if (total == -1) {
00292 return -1;
00293 }
00294
00295 ReadFile(hPipeRead, buf, total, &num_read, NULL);
00296 offset = 0;
00297 num_left = total;
00298
00299
00300 }
00301
00302
00303 num_read = 0;
00304
00305
00306 if (num_left >= len) {
00307 std::memcpy (v, buf+offset, len);
00308 num_left -= len;
00309 num_read = len;
00310 offset += len;
00311 }
00312 else {
00313 std::memcpy (v, buf+offset, num_left);
00314 len -= num_left;
00315 num_read += num_left;
00316 offset += num_left;
00317 num_left = 0;
00318
00319 num_left += read_win9x(file, v+num_read, len);
00320 }
00321
00322
00323
00324
00325 bNotifyDis = TRUE;
00326 return num_read;
00327 }
00328
00329 int read(int file, void *v, unsigned int len)
00330 {
00331 if (!bWinNT) return read_win9x(file, (unsigned char*) v, len);
00332
00333 DWORD num_read;
00334 int total = peek_pipe();
00335
00336 if (total == -1) return 0;
00337 else if (len == 0) return 0;
00338 else if (total == 0) return -1;
00339 else if (total < len) len = total;
00340
00341 ReadFile(hPipeRead, v, len, &num_read, NULL);
00342
00343 const unsigned char *data = (unsigned char *)v;
00344
00345
00346
00347
00348 if (GetLastError() == ERROR_BROKEN_PIPE) {
00349 bBroken = TRUE;
00350 return 0;
00351 }
00352
00353 return num_read;
00354 }
00355
00356 int close(int file)
00357 {
00358 return 0;
00359 }
00360
00361
00362
00363 bool create_pipe (const char *static_path)
00364 {
00365 bBroken = FALSE;
00366
00367 detect_winnt();
00368
00369 if (!bWinNT)
00370 {
00371 std::cout << "Using mailslots" << std::endl;
00372 hPipeRead = hPipeWrite= INVALID_HANDLE_VALUE;
00373 return setup_server_mailslots(static_path, false);
00374 }
00375
00376 char *pipe_name = Exult_server::get_pipe_name(static_path);
00377
00378
00379 DWORD oflag = FILE_FLAG_OVERLAPPED;
00380 if(!setup_overlap()) {
00381 cerr << "Pipe Server not supported on Win9x." << endl;
00382 return true;
00383 }
00384
00385
00386
00387
00388 hPipeRead = hPipeWrite = CreateNamedPipe(pipe_name,
00389 PIPE_ACCESS_DUPLEX|oflag,
00390 PIPE_TYPE_BYTE|PIPE_READMODE_BYTE,
00391 1,
00392 32768,
00393 32768,
00394 0,
00395 NULL);
00396
00397 delete [] pipe_name;
00398
00399 if (hPipeWrite == INVALID_HANDLE_VALUE) {
00400 cerr << "Unable to create pipe. Reason: " << GetLastError() << endl;
00401 free_overlap();
00402 return false;
00403 }
00404
00405 cout << "Created Pipe for Exult Server" << endl;
00406
00407 setup_connect();
00408
00409 return true;
00410 }
00411
00412 void setup_connect()
00413 {
00414 bBroken = FALSE;
00415
00416 if (!bWinNT) return;
00417
00418
00419 BOOL fConnected = ConnectNamedPipe(hPipeWrite, lpOverlapCon) ?
00420 TRUE : (GetLastError() == ERROR_PIPE_CONNECTED);
00421
00422
00423 if (fConnected) SetEvent(oOverlapCon.hEvent);
00424 }
00425
00426 bool try_connect_to_client(const char *static_path)
00427 {
00428 bBroken = FALSE;
00429
00430 if (bWinNT)
00431 {
00432 DWORD num_bytes;
00433
00434 BOOL fConnected = GetOverlappedResult (hPipeWrite, lpOverlapCon, &num_bytes, FALSE);
00435
00436 if (!fConnected) return false;
00437 }
00438 else {
00439 return setup_server_mailslots(static_path, true);
00440 }
00441
00442 return true;
00443 }
00444
00445 void disconnect_from_client()
00446 {
00447 bBroken = FALSE;
00448 if (bWinNT) {
00449 FlushFileBuffers (hPipeWrite);
00450 DisconnectNamedPipe(hPipeWrite);
00451 }
00452 else {
00453 if (hPipeWrite != INVALID_HANDLE_VALUE) {
00454 FlushFileBuffers (hPipeWrite);
00455 CloseHandle(hPipeWrite);
00456 }
00457 if (hPipeRead != INVALID_HANDLE_VALUE) {
00458 CloseHandle(hPipeRead);
00459 }
00460 hPipeRead = hPipeWrite= INVALID_HANDLE_VALUE;
00461 }
00462 }
00463
00464 void close_pipe()
00465 {
00466 bBroken = FALSE;
00467 if (bWinNT) {
00468 if (hPipeWrite != INVALID_HANDLE_VALUE) {
00469 disconnect_from_client();
00470 free_overlap();
00471 CloseHandle(hPipeWrite);
00472 hPipeRead = hPipeWrite = INVALID_HANDLE_VALUE;
00473 }
00474 }
00475 else {
00476 disconnect_from_client();
00477 }
00478 }
00479
00480
00481 int try_connect_to_server (const char *static_path)
00482 {
00483 bBroken = FALSE;
00484 detect_winnt();
00485
00486 if (!bWinNT)
00487 {
00488 hPipeRead = hPipeWrite= INVALID_HANDLE_VALUE;
00489 return setup_client_mailslots(static_path);
00490 }
00491
00492 char *pipe_name = Exult_server::get_pipe_name(static_path);
00493
00494
00495 if (!WaitNamedPipe(pipe_name, 0)) return 0;
00496
00497
00498 DWORD oflag = FILE_FLAG_OVERLAPPED;
00499 if(!setup_overlap()) {
00500 cerr << "Pipe Client not supported on Win9x." << endl;
00501 return -1;
00502 }
00503
00504
00505
00506 hPipeRead = hPipeWrite = CreateFile (pipe_name,
00507 GENERIC_READ|GENERIC_WRITE,
00508 0,
00509 NULL,
00510 OPEN_EXISTING,
00511 oflag,
00512 NULL);
00513
00514
00515 if (hPipeWrite == INVALID_HANDLE_VALUE)
00516 {
00517 ERROR_ALREADY_EXISTS;
00518 cout << "Pipe handle was invalid! : " << GetLastError () << endl;
00519 free_overlap();
00520 return 0;
00521 }
00522
00523 bClient = TRUE;
00524
00525 return 1;
00526 }
00527
00528 void disconnect_from_server()
00529 {
00530
00531 bBroken = FALSE;
00532 if (bWinNT) {
00533 if (hPipeWrite != INVALID_HANDLE_VALUE) {
00534 FlushFileBuffers (hPipeWrite);
00535 free_overlap();
00536 CloseHandle(hPipeWrite);
00537 hPipeRead = hPipeWrite= INVALID_HANDLE_VALUE;
00538 }
00539 }
00540 else
00541 {
00542 if (hPipeWrite != INVALID_HANDLE_VALUE) {
00543 FlushFileBuffers (hPipeWrite);
00544 CloseHandle(hPipeWrite);
00545 }
00546 if (hPipeRead != INVALID_HANDLE_VALUE) {
00547 CloseHandle(hPipeRead);
00548 }
00549 hPipeRead = hPipeWrite= INVALID_HANDLE_VALUE;
00550 }
00551 }
00552
00553 #define WIN9X_KEEPALIVE_SIZE 1
00554 int peek_pipe()
00555 {
00556 if (bBroken) return -1;
00557
00558 DWORD to_get;
00559
00560 if (bWinNT) {
00561 PeekNamedPipe(hPipeRead, 0, 0, 0, &to_get, 0);
00562
00563 if (GetLastError() == ERROR_BROKEN_PIPE) {
00564 std::cout << "Broken!" << std::endl;
00565 bBroken = TRUE;
00566 return -1;
00567 }
00568
00569 }
00570 else {
00571 DWORD num_read;
00572 static DWORD last_time = 0;
00573
00574
00575
00576
00577
00578 #ifdef USE_WIN9X_KEEPALIVE
00579 if (last_time < GetTickCount()) {
00580 last_time = GetTickCount() + 5000;
00581 char buf[WIN9X_KEEPALIVE_SIZE];
00582 if (!WriteFile(hPipeWrite, buf, WIN9X_KEEPALIVE_SIZE, &num_read, 0)) {
00583 std::cout << "Broken!" << std::endl;
00584 bBroken = TRUE;
00585 return -1;
00586 }
00587 }
00588 #endif
00589
00590 GetMailslotInfo(hPipeRead, NULL, &to_get, NULL, NULL);
00591
00592 #ifdef USE_WIN9X_KEEPALIVE
00593 while (to_get <= WIN9X_KEEPALIVE_SIZE) {
00594 char buf[WIN9X_KEEPALIVE_SIZE];
00595 ReadFile(hPipeRead, buf, to_get, &num_read, 0);
00596 GetMailslotInfo(hPipeRead, NULL, &to_get, NULL, NULL);
00597 }
00598 #endif
00599
00600
00601 if (to_get == MAILSLOT_NO_MESSAGE) return 0;
00602 }
00603
00604 return to_get;
00605 }
00606
00607 bool is_broken()
00608 {
00609 return bBroken != FALSE;
00610 }
00611
00612 bool notify_connection_lost()
00613 {
00614 if (bNotifyDis == TRUE) {
00615 bNotifyDis = FALSE;
00616 return true;
00617 }
00618 return bWinNT != FALSE;
00619 }
00620
00621 bool is_win9x()
00622 {
00623 return bWinNT == FALSE;
00624 }
00625
00626 }
00627
00628 #endif