ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/repos/CCSFinger/CCSFinger.cpp
Revision: 613
Committed: 2005-12-12T18:30:01-08:00 (19 years, 6 months ago) by douglas
File size: 6109 byte(s)
Log Message:
Moving along!

File Contents

# User Rev Content
1 douglas 594 // Douglas Thrift
2     //
3     // CCS Computer Science
4     //
5     // Windows Finger Daemon
6    
7     #include <windows.h>
8     #include <tchar.h>
9 douglas 596 #include <signal.h>
10 douglas 608 #include <wtsapi32.h>
11 douglas 594
12 douglas 595 #include <iostream>
13 douglas 608 #include <string>
14 douglas 610 #include <sstream>
15 douglas 609 #include <vector>
16 douglas 613 #include <set>
17 douglas 595
18 douglas 610 inline std::string Utf8(const std::wstring &wstring)
19     {
20 douglas 613 std::string string(::WideCharToMultiByte(CP_UTF8, 0, wstring.data(), int(wstring.size()), NULL, 0, NULL, NULL), '\0');
21 douglas 610
22 douglas 613 ::WideCharToMultiByte(CP_UTF8, 0, wstring.data(), int(wstring.size()), const_cast<LPSTR>(string.data()), int(string.size()), NULL, NULL);
23 douglas 610
24     return string;
25     }
26    
27     class Finger
28     {
29     private:
30 douglas 613 struct Login
31     {
32     std::string login, name, session;
33     Login(const std::string &login, const std::string &session) : login(login), session(session)
34     {
35     }
36     bool operator<(const Login &login) const
37     {
38     if (this->login == login.login)
39     return session < login.session;
40     else
41     return this->login < login.login;
42     }
43     };
44 douglas 610 std::ostringstream stream;
45 douglas 613 std::set<Login> logins;
46 douglas 610
47     public:
48     Finger(bool full)
49     {
50     PWTS_SESSION_INFO sessions;
51     DWORD count;
52    
53 douglas 613 ::WTSEnumerateSessions(WTS_CURRENT_SERVER_HANDLE, 0, 1, &sessions, &count);
54 douglas 610
55 douglas 613 for (PWTS_SESSION_INFO session(sessions); session != sessions + count; ++session)
56 douglas 610 {
57     LPTSTR name;
58     DWORD size;
59    
60 douglas 613 ::WTSQuerySessionInformation(WTS_CURRENT_SERVER_HANDLE, session->SessionId, WTSUserName, &name, &size);
61 douglas 610
62 douglas 613 if (!std::wstring(name).empty())
63     {
64     LPTSTR session_;
65 douglas 610
66 douglas 613 ::WTSQuerySessionInformation(WTS_CURRENT_SERVER_HANDLE, session->SessionId, WTSWinStationName, &session_, &size);
67 douglas 611
68 douglas 613 Login login(Utf8(name), Utf8(session_));
69 douglas 610
70 douglas 613 ::WTSFreeMemory(session_);
71    
72     logins.insert(login);
73     }
74    
75     ::WTSFreeMemory(name);
76 douglas 610 }
77    
78 douglas 613 ::WTSFreeMemory(sessions);
79    
80     if (!full)
81     {
82     stream << "Login\t\tName" << std::string(17, ' ') << "Session\r\n";
83    
84     for (std::set<Login>::const_iterator login(logins.begin()); login != logins.end(); ++login)
85     stream << login->login << std::string(16 - login->login.size(), ' ') << login->name << std::string(21 - login->name.size(), ' ') << login->session << "\r\n";
86     }
87 douglas 610 }
88    
89     Finger(const std::string &name)
90     {
91 douglas 612 //NetQueryDisplayInformation
92     //NetUserGetInfo
93 douglas 610 }
94    
95     inline operator std::string()
96     {
97     return stream.str();
98     }
99     };
100    
101 douglas 595 LPTSTR name;
102 douglas 594 SERVICE_STATUS status;
103     SERVICE_STATUS_HANDLE handle;
104 douglas 595 HANDLE stop;
105 douglas 594 WSADATA data;
106 douglas 609 std::vector<HANDLE> threads;
107 douglas 594
108 douglas 596 void FingerDaemon();
109 douglas 609 DWORD WINAPI FingerListen(LPVOID server_);
110     DWORD WINAPI FingerDo(LPVOID client_);
111 douglas 596 void FingerStop(int);
112 douglas 595 void WINAPI FingerMain(DWORD argc, LPTSTR *argv);
113     void WINAPI FingerControl(DWORD control);
114 douglas 594
115     int _tmain(int argc, TCHAR *argv[])
116     {
117 douglas 609 SERVICE_TABLE_ENTRY entry[] = { { TEXT("CCS Finger Daemon"), LPSERVICE_MAIN_FUNCTION(FingerMain) }, { NULL, NULL } };
118 douglas 594
119 douglas 613 if (!::StartServiceCtrlDispatcher(entry))
120 douglas 594 {
121 douglas 613 DWORD error(::GetLastError());
122 douglas 594
123     switch (error)
124     {
125     case ERROR_FAILED_SERVICE_CONTROLLER_CONNECT:
126 douglas 595 goto go;
127 douglas 594
128     case ERROR_INVALID_DATA:
129     std::cerr << "ERROR_INVALID_DATA" << std::endl;
130    
131     break;
132    
133     case ERROR_SERVICE_ALREADY_RUNNING:
134     std::cerr << "ERROR_SERVICE_ALREADY_RUNNING" << std::endl;
135    
136     break;
137    
138     default:
139     std::cerr << error << std::endl;
140     }
141    
142     return 1;
143     }
144    
145     return 0;
146 douglas 595
147     go:
148 douglas 613 stop = ::CreateEvent(NULL, TRUE, FALSE, NULL);
149 douglas 608
150 douglas 613 ::signal(SIGINT, FingerStop);
151 douglas 595
152 douglas 596 try
153     {
154     FingerDaemon();
155     }
156     catch (...) {}
157    
158 douglas 609 return 0;
159 douglas 594 }
160    
161 douglas 596 void FingerDaemon()
162 douglas 594 {
163 douglas 613 ::WSAStartup(MAKEWORD(2, 0), &data);
164 douglas 594
165     //
166    
167 douglas 613 SOCKET server(::socket(PF_INET, SOCK_STREAM, IPPROTO_TCP));
168 douglas 594 SOCKADDR_IN service;
169    
170     service.sin_family = AF_INET;
171     service.sin_addr.s_addr = inet_addr("0.0.0.0");
172     service.sin_port = htons(79);
173    
174 douglas 613 ::bind(server, (SOCKADDR *)(&service), sizeof (service));
175     ::listen(server, SOMAXCONN);
176 douglas 594
177 douglas 613 threads.push_back(::CreateThread(NULL, 0, FingerListen, &server, 0, NULL));
178 douglas 608
179 douglas 613 while(::WaitForSingleObject(stop, 1000) != WAIT_OBJECT_0);
180 douglas 594
181     //
182    
183 douglas 613 ::closesocket(server);
184 douglas 608
185 douglas 613 ::WSACleanup();
186 douglas 596 }
187 douglas 594
188 douglas 609 DWORD WINAPI FingerListen(LPVOID server_)
189     {
190     SOCKET &server(*reinterpret_cast<SOCKET *>(server_));
191    
192     while (true)
193     {
194     SOCKET client(accept(server, NULL, NULL));
195    
196 douglas 613 threads.push_back(::CreateThread(NULL, 0, FingerDo, &client, 0, NULL));
197 douglas 609 }
198    
199     return 0;
200     }
201    
202     DWORD WINAPI FingerDo(LPVOID client_)
203     {
204     SOCKET &client(*reinterpret_cast<SOCKET *>(client_));
205 douglas 610 char buffer[1024];
206 douglas 613 std::istringstream stream(std::string(buffer, ::recv(client, buffer, sizeof buffer, 0)));
207 douglas 610 std::string line;
208 douglas 609
209 douglas 610 std::getline(stream, line);
210 douglas 609
211 douglas 610 stream.str(line);
212 douglas 609
213 douglas 610 std::getline(stream, line, '\r');
214 douglas 609
215 douglas 610 stream.str(line);
216 douglas 609
217 douglas 610 std::string name;
218     bool full(false);
219 douglas 609
220 douglas 610 while (stream >> line)
221     if (line == "/W")
222     full = true;
223     else
224     name = line;
225 douglas 609
226 douglas 610 std::string finger(name.empty() ? Finger(full) : Finger(name));
227 douglas 609
228 douglas 613 ::send(client, finger.data(), int(finger.size()), 0);
229     ::closesocket(client);
230 douglas 609
231     return 0;
232     }
233    
234 douglas 596 void FingerStop(int)
235     {
236 douglas 613 ::SetEvent(stop);
237 douglas 596 }
238    
239     void WINAPI FingerMain(DWORD argc, LPTSTR *argv)
240     {
241     name = argv[0];
242     handle = RegisterServiceCtrlHandler(name, LPHANDLER_FUNCTION(FingerControl));
243 douglas 613 stop = ::CreateEvent(NULL, TRUE, FALSE, NULL);
244 douglas 596
245     //
246    
247     status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
248     status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
249     status.dwServiceSpecificExitCode = 0;
250     status.dwCurrentState = SERVICE_RUNNING;
251     status.dwWin32ExitCode = NO_ERROR;
252     status.dwCheckPoint = 0;
253     status.dwWaitHint = 0;
254    
255 douglas 613 ::SetServiceStatus(handle, &status);
256 douglas 596
257     try
258     {
259     FingerDaemon();
260     }
261     catch (...) {}
262    
263 douglas 595 status.dwCurrentState = SERVICE_STOPPED;
264 douglas 594 status.dwWin32ExitCode = NO_ERROR;
265     status.dwCheckPoint = 0;
266     status.dwWaitHint = 0;
267    
268 douglas 613 ::SetServiceStatus(handle, &status);
269 douglas 594 }
270    
271     void WINAPI FingerControl(DWORD control)
272     {
273     switch (control)
274     {
275     case SERVICE_CONTROL_STOP:
276     case SERVICE_CONTROL_SHUTDOWN:
277     status.dwCurrentState = SERVICE_STOP_PENDING;
278    
279 douglas 613 ::SetEvent(stop);
280 douglas 594
281     break;
282    
283     case SERVICE_CONTROL_INTERROGATE:
284     break;
285     }
286    
287 douglas 613 ::SetServiceStatus(handle, &status);
288 douglas 594 }