Richard Boegli's CnC_Generals_Zero_Hour Fork WIP
This is documentation of Richard Boegil's Zero Hour Fork
 
Loading...
Searching...
No Matches
netserv.cpp
Go to the documentation of this file.
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
20// $File: //depot/GeneralsMD/Staging/code/Libraries/Source/debug/netserv/netserv.cpp $
21// $Author: mhoffe $
22// $Revision: #1 $
23// $DateTime: 2003/07/03 11:55:26 $
24//
25// ©2003 Electronic Arts
26//
27// Simple console based server for NET I/O connections
29#define STRICT
30#define WIN32_LEAN_AND_MEAN
31#include <windows.h>
32#include <malloc.h>
33
34// Note: This implementation is quick'n'ugly. I've developed this
35// program basically just for testing the net I/O class.
36
37static char m_input[256];
38static unsigned m_inputUsed;
39
40static void InitConsole(void)
41{
42 AllocConsole();
43
44 HANDLE h=GetStdHandle(STD_INPUT_HANDLE);
45 SetConsoleMode(h,0);
46
47 // make screen buffer same size as currently displayed area
48 // (prevents that our input line gets scrolled out of view)
49 h=GetStdHandle(STD_OUTPUT_HANDLE);
50 CONSOLE_SCREEN_BUFFER_INFO info;
51 GetConsoleScreenBufferInfo(h,&info);
52
53 COORD newSize;
54 newSize.X=info.srWindow.Right+1;
55 newSize.Y=info.srWindow.Bottom+1;
56 SetConsoleScreenBufferSize(h,newSize);
57
58 // hide cursor
59 CONSOLE_CURSOR_INFO ci;
60 ci.dwSize=1;
61 ci.bVisible=FALSE;
62 SetConsoleCursorInfo(h,&ci);
63}
64
65static char *InputConsole(void)
66{
67 // update our input buffer
68 HANDLE h=GetStdHandle(STD_INPUT_HANDLE);
69 bool returnChars=false;
70 for (;;)
71 {
72 DWORD dwRecords;
73 if (!GetNumberOfConsoleInputEvents(h,&dwRecords))
74 break;
75 if (!dwRecords)
76 break;
77
78 INPUT_RECORD record;
79 ReadConsoleInput(h,&record,1,&dwRecords);
80 if (record.EventType!=KEY_EVENT)
81 continue;
82
83 KEY_EVENT_RECORD &key=record.Event.KeyEvent;
84 if (!key.bKeyDown||!key.uChar.AsciiChar)
85 continue;
86
87 if (key.uChar.AsciiChar=='\r'||
88 key.uChar.AsciiChar=='\n')
89 {
90 m_input[m_inputUsed++]='\n';
91 returnChars=true;
92 break;
93 }
94
96
97 if (key.uChar.AsciiChar=='\b')
98 {
99 if (m_inputUsed)
100 m_inputUsed--;
101 }
102 else if (((unsigned char)key.uChar.AsciiChar)>=' ')
103 {
104 if (m_inputUsed<sizeof(m_input)-1)
105 m_input[m_inputUsed++]=key.uChar.AsciiChar;
106 }
107 }
108
109 // update screen
110 h=GetStdHandle(STD_OUTPUT_HANDLE);
111 CONSOLE_SCREEN_BUFFER_INFO info;
112 GetConsoleScreenBufferInfo(h,&info);
113 CHAR_INFO ci[sizeof(m_input)+1];
114 for (unsigned k=0;k<=sizeof(m_input);k++)
115 {
116 ci[k].Char.AsciiChar=k<m_inputUsed?m_input[k]:' ';
117 ci[k].Attributes=BACKGROUND_BLUE|FOREGROUND_BLUE|FOREGROUND_GREEN
118 |FOREGROUND_RED|FOREGROUND_INTENSITY;
119 }
120
121 // fake another cursor
122 if (GetTickCount()&512)
123 ci[m_inputUsed].Attributes=BACKGROUND_BLUE|BACKGROUND_GREEN
124 |BACKGROUND_RED|BACKGROUND_INTENSITY|FOREGROUND_BLUE;
125
126 COORD srcSize,srcCoord;
127 srcSize.X=sizeof(m_input); srcSize.Y=1;
128 srcCoord.X=srcCoord.Y=0;
129
130 SMALL_RECT r;
131 r.Left=r.Top=r.Bottom=0; r.Right=info.dwSize.X-1;
132 WriteConsoleOutput(h,ci+(m_inputUsed<=info.dwSize.X?0:m_inputUsed-info.dwSize.X),
133 srcSize,srcCoord,&r);
134
135 // return data now?
136 if (returnChars&&m_inputUsed>1)
137 {
138 m_input[--m_inputUsed]=0;
139 m_inputUsed=0;
140 return m_input;
141 }
142
143 return 0;
144}
145
146class Pipe
147{
148 Pipe(const Pipe&);
149 Pipe& operator=(const Pipe&);
150
151 HANDLE m_pipe;
152 bool m_connected;
153 int m_state;
154 int m_stringType;
155 int m_len;
156 char *m_src;
157 char *m_str;
158
159public:
160 Pipe(void):
161 m_pipe(INVALID_HANDLE_VALUE),
162 m_src(NULL), m_str(NULL), m_stringType(0)
163 {
164 }
165
167 {
168 if (m_pipe!=INVALID_HANDLE_VALUE)
169 {
170 DisconnectNamedPipe(m_pipe);
171 CloseHandle(m_pipe);
172 free(m_src);
173 free(m_str);
174 }
175 }
176
177 bool Create(const char *name)
178 {
179 m_pipe=CreateNamedPipe(name,
180 PIPE_ACCESS_DUPLEX,
181 PIPE_TYPE_MESSAGE|PIPE_READMODE_MESSAGE|PIPE_NOWAIT,
182 PIPE_UNLIMITED_INSTANCES,1024,1024,0,NULL);
183 m_connected=false;
184 return m_pipe!=INVALID_HANDLE_VALUE;
185 }
186
187 bool Connected(void)
188 {
189 if (!m_connected)
190 {
191 ConnectNamedPipe(m_pipe,NULL);
192 if (GetLastError()==ERROR_PIPE_CONNECTED)
193 {
194 DWORD dwDummy;
195 WriteFile(GetStdHandle(STD_OUTPUT_HANDLE),"\n<connect>\n",11,&dwDummy,NULL);
196 m_connected=true;
197 m_state=0;
198 }
199 }
200 return m_connected;
201 }
202
203 void Write(char msg)
204 {
205 DWORD dummy;
206 if (!WriteFile(m_pipe,&msg,1,&dummy,NULL)||!dummy)
207 {
208 char sp[30];
209 wsprintf(sp,"%c:%i/%i\n",msg,dummy,GetLastError());
210
211 DWORD dwDummy;
212 WriteFile(GetStdHandle(STD_OUTPUT_HANDLE),sp,strlen(sp),&dwDummy,NULL);
213 }
214 }
215
216 const char *Read(void)
217 {
218 DWORD read;
219 switch(m_state)
220 {
221 case 0:
222 if (!ReadFile(m_pipe,&m_stringType,1,&read,NULL))
223 break;
224 if (read==1)
225 m_state++;
226 return NULL;
227 case 1:
228 case 3:
229 if (!ReadFile(m_pipe,&m_len,4,&read,NULL))
230 break;
231 if (read==4)
232 {
233 if (m_state==1)
234 m_src=(char *)realloc(m_src,m_len+1);
235 else
236 m_str=(char *)realloc(m_str,m_len+1);
237 m_state++;
238 }
239 return NULL;
240 case 2:
241 if (!ReadFile(m_pipe,m_src,m_len,&read,NULL))
242 break;
243 if (read==m_len)
244 {
245 m_src[m_len]=0;
246 m_state++;
247 }
248 return NULL;
249 case 4:
250 if (!ReadFile(m_pipe,m_str,m_len,&read,NULL))
251 break;
252 if (read==m_len)
253 {
254 m_str[m_len]=0;
255 m_state=0;
256 return m_str;
257 }
258 return NULL;
259 }
260
261 if (GetLastError()==ERROR_BROKEN_PIPE)
262 {
263 DisconnectNamedPipe(m_pipe);
264
265 DWORD dwDummy;
266 WriteFile(GetStdHandle(STD_OUTPUT_HANDLE),"\n<disconnect>\n",14,&dwDummy,NULL);
267 m_connected=false;
268 }
269
270 return NULL;
271 }
272};
273
274int CALLBACK WinMain(HINSTANCE,HINSTANCE,LPSTR,int)
275{
276 InitConsole();
277
278 char buf1[200],buf2[400];
279 DWORD dwDummy=sizeof(buf1);
280 GetComputerName(buf1,&dwDummy);
281 WriteFile(GetStdHandle(STD_OUTPUT_HANDLE),buf2,
282 wsprintf(buf2,"\n\nSimple debug.net Server ready. Enter 'quit' to exit.\n\nLocal machine: %s\n\n",buf1),
283 &dwDummy,NULL);
284
285 Pipe p[10];
286 for (int k=0;k<10;k++)
287 if (!p[k].Create("\\\\.\\pipe\\ea_debug_v1"))
288 {
289 char msg[200];
290 wsprintf(msg,"Can't create named pipe (Code %i).",GetLastError());
291 MessageBox(NULL,msg,"Error",MB_OK);
292 return 1;
293 }
294
295 for (;;)
296 {
297 char *input=InputConsole();
298 if (input)
299 {
300 if (!strcmp(input,"quit"))
301 break;
302 }
303
304 for (int k=0;k<10;k++)
305 {
306 if (!p[k].Connected())
307 continue;
308
309 const char *msg=p[k].Read();
310 if (msg)
311 {
312 DWORD dwDummy;
313 WriteFile(GetStdHandle(STD_OUTPUT_HANDLE),msg,strlen(msg),&dwDummy,NULL);
314 }
315
316 if (input)
317 {
318 for (unsigned i=0;input[i];i++)
319 p[k].Write(input[i]);
320 p[k].Write('\n');
321 }
322 }
323
324 Sleep(10);
325 }
326
327 return 0;
328}
#define NULL
Definition BaseType.h:92
#define FALSE
Definition BaseType.h:113
unsigned long DWORD
Definition bittype.h:57
void Write(char msg)
Definition netserv.cpp:203
bool Create(const char *name)
Definition netserv.cpp:177
bool Connected(void)
Definition netserv.cpp:187
const char * Read(void)
Definition netserv.cpp:216
Pipe(void)
Definition netserv.cpp:160
~Pipe()
Definition netserv.cpp:166
int CALLBACK WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
Definition netserv.cpp:274
MSG msg
Definition patch.cpp:409