servewin32.cc

Go to the documentation of this file.
00001 /*
00002 Copyright (C) 2002 The Exult Team
00003 
00004 This program is free software; you can redistribute it and/or
00005 modify it under the terms of the GNU General Public License
00006 as published by the Free Software Foundation; either version 2
00007 of the License, or (at your option) any later version.
00008 
00009 This program is distributed in the hope that it will be useful,
00010 but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 GNU General Public License for more details.
00013 
00014 You should have received a copy of the GNU General Public License
00015 along with this program; if not, write to the Free Software
00016 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00017 
00018 */
00019 
00020 // Win32 Only file
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>     /* For debugging msgs. */
00030 #include <cstring>      /* For debugging msgs. */
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;     // Overlap structure
00044 static LPOVERLAPPED lpOverlap = 0;    // Pointer to overlap structure
00045 static OVERLAPPED oOverlapCon;      // Overlap structure
00046 static LPOVERLAPPED lpOverlapCon = 0;   // Pointer to overlap structure
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 // static Functions
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   // Check to make sure that the pipe name hasn't been passed to us
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   // Check to make sure that the mailslot name hasn't been passed to us
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   // Platform is NT
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   // Platform is NT
00128   if (bWinNT)
00129   {
00130     // Create the overlap event
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 // This sets up mailslots for the interprocess coms on Win9x
00155 static bool setup_server_mailslots(const char *static_path, bool both)
00156 {
00157   // Create read frst
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     //cout << "Created mailslot. Name " << server_name << std::endl;
00171     delete [] server_name ;
00172     if (!both) return true;
00173   }
00174 
00175   // Now attempt to create read
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,   // Pipe Name
00181         GENERIC_WRITE,      // Desired Access
00182         FILE_SHARE_READ,    // Share Mode
00183         NULL,       // Security Att
00184         OPEN_EXISTING,      // Creation Disposition
00185         FILE_ATTRIBUTE_NORMAL,    // Flags and Attributes
00186         NULL);        // TemplateFile
00187 
00188     if (hPipeWrite == INVALID_HANDLE_VALUE) {
00189       //std::cout << "Unable to connect to mailslot: " << client_name <<" Code " << GetLastError() << std::endl;
00190       delete [] client_name;
00191       return false;
00192     }
00193     //std::cout << "Connected to mailslot. Name " << client_name << std::endl;
00194     delete [] client_name ;
00195   }
00196 
00197   return true;
00198 }
00199 
00200 // This sets up mailslots for the interprocess coms on Win9x
00201 static bool setup_client_mailslots(const char *static_path)
00202 {
00203   // Create write frst
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,   // Pipe Name
00209         GENERIC_WRITE,      // Desired Access
00210         FILE_SHARE_READ,    // Share Mode
00211         NULL,       // Security Att
00212         OPEN_EXISTING,      // Creation Disposition
00213         FILE_ATTRIBUTE_NORMAL,    // Flags and Attributes
00214         NULL);        // TemplateFile
00215 
00216     if (hPipeWrite == INVALID_HANDLE_VALUE) {
00217       //std::cout << "Unable to connect to mailslot: " << server_name <<" Code " << GetLastError() << std::endl;
00218       delete [] server_name;
00219       return false;
00220     }
00221     //std::cout << "Connected to mailslot. Name " << server_name << std::endl;
00222     delete [] server_name ;
00223   }
00224 
00225   // Now attempt to create read
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     //std::cout << "Created mailslot. Name " << client_name << std::endl;
00240     delete [] client_name ;
00241   }
00242 
00243   return true;
00244 }
00245 
00246 // Hack functions
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   //cout << "write = " << len << endl;
00255   //for (int q = 0 ; q < len; q++) cout << ((int) data [q]) << " ";
00256   //cout << endl;
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   //std::cout << "The Num wanted is " << len << std::endl;
00278 
00279   // Buffer is empty, fill it
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     //std::cout << "Read " << num_read << " bytes from mailslot" << std::endl;
00300   }
00301 
00302   // Now copy the amount of bytes, if we can, if we can't call the func recursively
00303   num_read = 0;
00304 
00305   // Buffer contains enough
00306   if (num_left >= len) {
00307     std::memcpy (v, buf+offset, len);
00308     num_left -= len;
00309     num_read  = len;
00310     offset += len;
00311   } // Uh oh, the buffer doesn't contain enough
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   //std::cout << "The Num read is " << num_read << std::endl;
00323   //std::cout << num_left << " byte left in buffer with offset " << offset<< std::endl;
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   //cout << "read = " << num_read << endl;
00345   //for (int q = 0 ; q < num_read; q++) cout << ((int) data[q]) << " ";
00346   //cout << endl;
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 // Server Functions
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   // Must have overlap for now
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   //cout << "Exult Server pipe name: " << pipe_name << endl;
00386 
00387   // Create the Win32 Named pipe
00388   hPipeRead = hPipeWrite = CreateNamedPipe(pipe_name,   // pipe name
00389         PIPE_ACCESS_DUPLEX|oflag,   // pipe open mode
00390         PIPE_TYPE_BYTE|PIPE_READMODE_BYTE,  // pipe-specific modes
00391         1,          // maximum number of instances
00392         32768,          // output buffer size
00393         32768,          // input buffer size
00394         0,          // time-out interval
00395         NULL);          // Security Descriptor
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   // Attempt to connect to the pipe
00419         BOOL fConnected = ConnectNamedPipe(hPipeWrite, lpOverlapCon) ? 
00420     TRUE : (GetLastError() == ERROR_PIPE_CONNECTED); 
00421 
00422   // If it's connected, signal the event
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 // Client Functions
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   // No server
00495   if (!WaitNamedPipe(pipe_name, 0)) return 0;
00496 
00497   // Must have overlap
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   //cout << "Attempting to connect to server: " << pipe_name << endl;
00505 
00506   hPipeRead = hPipeWrite = CreateFile (pipe_name,   // Pipe Name
00507         GENERIC_READ|GENERIC_WRITE, // Desired Access
00508         0,        // Share Mode
00509         NULL,       // Security Att
00510         OPEN_EXISTING,      // Creation Disposition
00511         oflag,        // Flags and Attributes
00512         NULL);        // TemplateFile
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   //CreateMailslot
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     // This is a keep alive. It doesn't send anything,
00575     // But, if the mailslot closes, this will fail.
00576     // That is the theory, but win9x doesn't quite
00577     // work that way
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

Generated on Mon Jul 9 14:42:50 2007 for ExultEngine by  doxygen 1.5.1