netserv.cpp 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  1. /*
  2. ** Command & Conquer Generals Zero Hour(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. /////////////////////////////////////////////////////////////////////////EA-V1
  19. // $File: //depot/GeneralsMD/Staging/code/Libraries/Source/debug/netserv/netserv.cpp $
  20. // $Author: mhoffe $
  21. // $Revision: #1 $
  22. // $DateTime: 2003/07/03 11:55:26 $
  23. //
  24. // ©2003 Electronic Arts
  25. //
  26. // Simple console based server for NET I/O connections
  27. //////////////////////////////////////////////////////////////////////////////
  28. #define STRICT
  29. #define WIN32_LEAN_AND_MEAN
  30. #include <windows.h>
  31. #include <malloc.h>
  32. // Note: This implementation is quick'n'ugly. I've developed this
  33. // program basically just for testing the net I/O class.
  34. static char m_input[256];
  35. static unsigned m_inputUsed;
  36. static void InitConsole(void)
  37. {
  38. AllocConsole();
  39. HANDLE h=GetStdHandle(STD_INPUT_HANDLE);
  40. SetConsoleMode(h,0);
  41. // make screen buffer same size as currently displayed area
  42. // (prevents that our input line gets scrolled out of view)
  43. h=GetStdHandle(STD_OUTPUT_HANDLE);
  44. CONSOLE_SCREEN_BUFFER_INFO info;
  45. GetConsoleScreenBufferInfo(h,&info);
  46. COORD newSize;
  47. newSize.X=info.srWindow.Right+1;
  48. newSize.Y=info.srWindow.Bottom+1;
  49. SetConsoleScreenBufferSize(h,newSize);
  50. // hide cursor
  51. CONSOLE_CURSOR_INFO ci;
  52. ci.dwSize=1;
  53. ci.bVisible=FALSE;
  54. SetConsoleCursorInfo(h,&ci);
  55. }
  56. static char *InputConsole(void)
  57. {
  58. // update our input buffer
  59. HANDLE h=GetStdHandle(STD_INPUT_HANDLE);
  60. bool returnChars=false;
  61. for (;;)
  62. {
  63. DWORD dwRecords;
  64. if (!GetNumberOfConsoleInputEvents(h,&dwRecords))
  65. break;
  66. if (!dwRecords)
  67. break;
  68. INPUT_RECORD record;
  69. ReadConsoleInput(h,&record,1,&dwRecords);
  70. if (record.EventType!=KEY_EVENT)
  71. continue;
  72. KEY_EVENT_RECORD &key=record.Event.KeyEvent;
  73. if (!key.bKeyDown||!key.uChar.AsciiChar)
  74. continue;
  75. if (key.uChar.AsciiChar=='\r'||
  76. key.uChar.AsciiChar=='\n')
  77. {
  78. m_input[m_inputUsed++]='\n';
  79. returnChars=true;
  80. break;
  81. }
  82. /// @todo_opt if somebody wants this can be improved by adding support for cursor keys, history, etc
  83. if (key.uChar.AsciiChar=='\b')
  84. {
  85. if (m_inputUsed)
  86. m_inputUsed--;
  87. }
  88. else if (((unsigned char)key.uChar.AsciiChar)>=' ')
  89. {
  90. if (m_inputUsed<sizeof(m_input)-1)
  91. m_input[m_inputUsed++]=key.uChar.AsciiChar;
  92. }
  93. }
  94. // update screen
  95. h=GetStdHandle(STD_OUTPUT_HANDLE);
  96. CONSOLE_SCREEN_BUFFER_INFO info;
  97. GetConsoleScreenBufferInfo(h,&info);
  98. CHAR_INFO ci[sizeof(m_input)+1];
  99. for (unsigned k=0;k<=sizeof(m_input);k++)
  100. {
  101. ci[k].Char.AsciiChar=k<m_inputUsed?m_input[k]:' ';
  102. ci[k].Attributes=BACKGROUND_BLUE|FOREGROUND_BLUE|FOREGROUND_GREEN
  103. |FOREGROUND_RED|FOREGROUND_INTENSITY;
  104. }
  105. // fake another cursor
  106. if (GetTickCount()&512)
  107. ci[m_inputUsed].Attributes=BACKGROUND_BLUE|BACKGROUND_GREEN
  108. |BACKGROUND_RED|BACKGROUND_INTENSITY|FOREGROUND_BLUE;
  109. COORD srcSize,srcCoord;
  110. srcSize.X=sizeof(m_input); srcSize.Y=1;
  111. srcCoord.X=srcCoord.Y=0;
  112. SMALL_RECT r;
  113. r.Left=r.Top=r.Bottom=0; r.Right=info.dwSize.X-1;
  114. WriteConsoleOutput(h,ci+(m_inputUsed<=info.dwSize.X?0:m_inputUsed-info.dwSize.X),
  115. srcSize,srcCoord,&r);
  116. // return data now?
  117. if (returnChars&&m_inputUsed>1)
  118. {
  119. m_input[--m_inputUsed]=0;
  120. m_inputUsed=0;
  121. return m_input;
  122. }
  123. return 0;
  124. }
  125. class Pipe
  126. {
  127. Pipe(const Pipe&);
  128. Pipe& operator=(const Pipe&);
  129. HANDLE m_pipe;
  130. bool m_connected;
  131. int m_state;
  132. int m_stringType;
  133. int m_len;
  134. char *m_src;
  135. char *m_str;
  136. public:
  137. Pipe(void):
  138. m_pipe(INVALID_HANDLE_VALUE),
  139. m_src(NULL), m_str(NULL), m_stringType(0)
  140. {
  141. }
  142. ~Pipe()
  143. {
  144. if (m_pipe!=INVALID_HANDLE_VALUE)
  145. {
  146. DisconnectNamedPipe(m_pipe);
  147. CloseHandle(m_pipe);
  148. free(m_src);
  149. free(m_str);
  150. }
  151. }
  152. bool Create(const char *name)
  153. {
  154. m_pipe=CreateNamedPipe(name,
  155. PIPE_ACCESS_DUPLEX,
  156. PIPE_TYPE_MESSAGE|PIPE_READMODE_MESSAGE|PIPE_NOWAIT,
  157. PIPE_UNLIMITED_INSTANCES,1024,1024,0,NULL);
  158. m_connected=false;
  159. return m_pipe!=INVALID_HANDLE_VALUE;
  160. }
  161. bool Connected(void)
  162. {
  163. if (!m_connected)
  164. {
  165. ConnectNamedPipe(m_pipe,NULL);
  166. if (GetLastError()==ERROR_PIPE_CONNECTED)
  167. {
  168. DWORD dwDummy;
  169. WriteFile(GetStdHandle(STD_OUTPUT_HANDLE),"\n<connect>\n",11,&dwDummy,NULL);
  170. m_connected=true;
  171. m_state=0;
  172. }
  173. }
  174. return m_connected;
  175. }
  176. void Write(char msg)
  177. {
  178. DWORD dummy;
  179. if (!WriteFile(m_pipe,&msg,1,&dummy,NULL)||!dummy)
  180. {
  181. char sp[30];
  182. wsprintf(sp,"%c:%i/%i\n",msg,dummy,GetLastError());
  183. DWORD dwDummy;
  184. WriteFile(GetStdHandle(STD_OUTPUT_HANDLE),sp,strlen(sp),&dwDummy,NULL);
  185. }
  186. }
  187. const char *Read(void)
  188. {
  189. DWORD read;
  190. switch(m_state)
  191. {
  192. case 0:
  193. if (!ReadFile(m_pipe,&m_stringType,1,&read,NULL))
  194. break;
  195. if (read==1)
  196. m_state++;
  197. return NULL;
  198. case 1:
  199. case 3:
  200. if (!ReadFile(m_pipe,&m_len,4,&read,NULL))
  201. break;
  202. if (read==4)
  203. {
  204. if (m_state==1)
  205. m_src=(char *)realloc(m_src,m_len+1);
  206. else
  207. m_str=(char *)realloc(m_str,m_len+1);
  208. m_state++;
  209. }
  210. return NULL;
  211. case 2:
  212. if (!ReadFile(m_pipe,m_src,m_len,&read,NULL))
  213. break;
  214. if (read==m_len)
  215. {
  216. m_src[m_len]=0;
  217. m_state++;
  218. }
  219. return NULL;
  220. case 4:
  221. if (!ReadFile(m_pipe,m_str,m_len,&read,NULL))
  222. break;
  223. if (read==m_len)
  224. {
  225. m_str[m_len]=0;
  226. m_state=0;
  227. return m_str;
  228. }
  229. return NULL;
  230. }
  231. if (GetLastError()==ERROR_BROKEN_PIPE)
  232. {
  233. DisconnectNamedPipe(m_pipe);
  234. DWORD dwDummy;
  235. WriteFile(GetStdHandle(STD_OUTPUT_HANDLE),"\n<disconnect>\n",14,&dwDummy,NULL);
  236. m_connected=false;
  237. }
  238. return NULL;
  239. }
  240. };
  241. int CALLBACK WinMain(HINSTANCE,HINSTANCE,LPSTR,int)
  242. {
  243. InitConsole();
  244. char buf1[200],buf2[400];
  245. DWORD dwDummy=sizeof(buf1);
  246. GetComputerName(buf1,&dwDummy);
  247. WriteFile(GetStdHandle(STD_OUTPUT_HANDLE),buf2,
  248. wsprintf(buf2,"\n\nSimple debug.net Server ready. Enter 'quit' to exit.\n\nLocal machine: %s\n\n",buf1),
  249. &dwDummy,NULL);
  250. Pipe p[10];
  251. for (int k=0;k<10;k++)
  252. if (!p[k].Create("\\\\.\\pipe\\ea_debug_v1"))
  253. {
  254. char msg[200];
  255. wsprintf(msg,"Can't create named pipe (Code %i).",GetLastError());
  256. MessageBox(NULL,msg,"Error",MB_OK);
  257. return 1;
  258. }
  259. for (;;)
  260. {
  261. char *input=InputConsole();
  262. if (input)
  263. {
  264. if (!strcmp(input,"quit"))
  265. break;
  266. }
  267. for (int k=0;k<10;k++)
  268. {
  269. if (!p[k].Connected())
  270. continue;
  271. const char *msg=p[k].Read();
  272. if (msg)
  273. {
  274. DWORD dwDummy;
  275. WriteFile(GetStdHandle(STD_OUTPUT_HANDLE),msg,strlen(msg),&dwDummy,NULL);
  276. }
  277. if (input)
  278. {
  279. for (unsigned i=0;input[i];i++)
  280. p[k].Write(input[i]);
  281. p[k].Write('\n');
  282. }
  283. }
  284. Sleep(10);
  285. }
  286. return 0;
  287. }