source: chevmsgr/trunk/msgsrv.cpp@ 4

Last change on this file since 4 was 4, checked in by cheese, 9 years ago

자 이제 시작이야 (졸작을)

File size: 8.7 KB
Line 
1
2#include "cf/network.h"
3#include "cf/task.h"
4#include "cf/codec.h"
5#include "cf/file.h"
6
7#include "msg.hpp"
8
9#include <map>
10#include <stdlib.h>
11#include <time.h>
12
13#include "sqlite3.h"
14
15// --------------------------------------------------------------
16
17typedef struct
18{
19 cf::network::tcp * sock;
20 cf::bin key;
21} LoginSession;
22std::map<std::string, LoginSession> gOnlineUsers;
23
24
25//================================================================
26
27int cb_getFriendList(void * userArg, int argc, char ** argv, char ** colName)
28{
29 std::string * friendList = (std::string *) userArg;
30
31 *friendList = argv[1];
32
33 return 0;
34}
35
36int cb_getSMS(void * userArg, int argc, char ** argv, char ** colName)
37{
38 std::string * SMS = (std::string *) userArg;
39
40 *SMS = argv[1];
41
42 return 0;
43}
44
45int cb_login(void * userArg, int argc, char ** argv, char ** colName)
46{
47 bool * result = (bool *)userArg;
48
49 *result = true;
50
51 return 0;
52}
53
54int cb_join(void * userArg, int argc, char ** argv, char ** colName)
55{
56 bool * isExist = (bool *)userArg;
57
58 *isExist = true;
59
60 return 0;
61}
62
63//===============================================================
64
65// --------------------------------------------------------------
66class DBManager
67{
68private:
69 sqlite3 * db;
70
71public:
72 DBManager()
73 throw (cf::exception)
74 : db(NULL)
75 {
76 }
77
78 void Init()
79 throw (cf::exception)
80 {
81 int result = 0;
82 bool isExist = false;
83
84 isExist = cf::file("account.db").exists();
85
86 result = sqlite3_open("account.db", &db);
87 if (result)
88 fprintf(stderr, "sqlite_open failed\n");
89
90 if (!isExist)
91 setup();
92 }
93
94 void setup()
95 throw (cf::exception)
96 {
97 std::string sqlCreateAccountTable;
98 std::string sqlCreateAuthTable;
99 std::string sqlCreateFriendsTable;
100 // declaration
101
102 // query
103 sqlCreateAccountTable =
104 "CREATE TABLE T_ACCOUNT"
105 "("
106 " no INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,"
107 " id TEXT,"
108 " pw TEXT"
109 ")";
110 sqlCreateAuthTable =
111 "CREATE TABLE T_AUTH"
112 "("
113 " id TEXT PRIMARY KEY NOT NULL,"
114 " sms1 TEXT,"
115 " ip1 TEXT,"
116 " sms2 TEXT,"
117 " ip2 TEXT,"
118 " sms3 TEXT,"
119 " ip3 TEXT,"
120 " sms4 TEXT,"
121 " ip4 TEXT,"
122 " sms5 TEXT,"
123 " ip5 TEXT"
124 ")";
125 sqlCreateFriendsTable =
126 "CREATE TABLE T_FRIENDS"
127 "("
128 " id TEXT PRIMARY KEY NOT NULL,"
129 " friend TEXT"
130 ")";
131
132 exec(sqlCreateAccountTable, NULL, NULL);
133 exec(sqlCreateAuthTable, NULL, NULL);
134 exec(sqlCreateFriendsTable, NULL, NULL);
135 }
136
137 void exec(std::string & query, sqlite3_callback cb, void * userArg)
138 throw(cf::exception)
139 {
140 int result;
141 char * errMsg;
142
143 result = sqlite3_exec(db, query.c_str(), cb, userArg, &errMsg);
144
145 if (result != SQLITE_OK)
146 THROW_EXCEPTION (errMsg);
147 }
148
149 bool login(const std::string & id, const std::string & pw)
150 throw (cf::exception)
151 {
152 try
153 {
154 bool result = false;
155 std::string query = "select * from T_ACCOUNT where id ='" + id + "' and pw = '" + pw + "'";
156
157 this->exec(query, cb_login, &result);
158
159 return result;
160 }
161 catch (cf::exception & e)
162 {
163 FORWARD_EXCEPTION(e);
164
165 return false;
166 }
167 }
168
169 bool join(const std::string & id, const std::string & pw, const std::string & sms, const std::string & ip)
170 throw (cf::exception)
171 {
172 try
173 {
174 bool isExist = false;
175 std::string existQuery = "select * from T_ACCOUNT where id = '" + id + "'";
176 std::string insertQuery = "insert into T_ACCOUNT values('" + id + "', '" + pw + "', '" + sms + "', '" + ip + "')";
177
178 this->exec(existQuery, cb_join, &isExist);
179
180 if (!isExist)
181 this->exec(insertQuery, NULL, NULL);
182 }
183 catch (cf::exception & e)
184 {
185 FORWARD_EXCEPTION(e);
186 }
187
188 return true;
189 }
190
191 std::string getFriendList(std::string & id)
192 throw(cf::exception)
193 {
194 int result = 0;
195 std::string friendList;
196
197 try
198 {
199 std::string query = "select * from T_FRIENDS where id = '" + id + "'";
200
201 this->exec(query, cb_getFriendList, &friendList);
202 }
203 catch (cf::exception & e)
204 {
205 FORWARD_EXCEPTION(e);
206 }
207 }
208
209 int getSMS(std::string & id)
210 {
211 int result = 0;
212 std::string smsMsg;
213
214 try
215 {
216 std::string query = "select * from T_AUTH where id = '" + id + "'";
217
218 this->exec(query, cb_getSMS, &smsMsg);
219 }
220 catch (cf::exception & e)
221 {
222 FORWARD_EXCEPTION(e);
223 }
224 }
225
226 int addFriend(std::string & id)
227 {
228 try
229 {
230 std::string query = "insert into T_FRIENDS values('" + id + "')";
231
232 this->exec(query, NULL, NULL);
233 }
234 catch (cf::exception & e)
235 {
236 FORWARD_EXCEPTION(e);
237 }
238 }
239};
240DBManager dbmgr;
241
242class Runner
243{
244public:
245 cf::network::tcp * mSock;
246 cf::task::thread * mThread;
247
248 Runner(cf::network::tcp & sock, int (*worker)(void *))
249 : mSock(NULL)
250 , mThread(NULL)
251 {
252 mSock = new(std::nothrow) cf::network::tcp(sock.detach());
253 mThread = new(std::nothrow) cf::task::thread(worker);
254 if (!mSock || !mThread)
255 {
256 dispose();
257 THROW_EXCEPTION("cannot allocate thread arguments");
258 }
259
260 mThread->start(this);
261 }
262
263 ~Runner()
264 {
265 dispose();
266 }
267
268 void dispose()
269 {
270 if (mSock) delete mSock;
271 if (mThread) delete mThread;
272 }
273};
274
275static bool isOnline(const std::string & id)
276{
277 return gOnlineUsers.find(id) != gOnlineUsers.end();
278}
279
280static void logout(const std::string & id)
281{
282 gOnlineUsers.erase(id);
283}
284
285static bool command(const Message::Parser & parser)
286{
287 bool isContinued = true;
288 std::string command = parser.get<std::string>("command");
289
290 if (command == "logout")
291 isContinued = false;
292 /*
293 else if (...)
294 */
295
296 return isContinued;
297}
298
299static std::string getRandomCode()
300{
301 char random[8] = {0x00,};
302 sprintf(random, "%06d", rand() % 1000000);
303
304 return random;
305}
306
307static std::string httpSMS(const Message::Parser & parser)
308{
309 std::string phone = parser.get<std::string>("phone");
310
311#define CRLF "\r\n"
312 std::string code = getRandomCode();
313 std::string url = "unsigned.kr";
314 std::string uri = "/~cheese/sms/req.php?to=" + phone + "&code=" + code;
315 std::string http =
316 "GET " + uri + " HTTP/1.1" CRLF
317 "Host: " + url + CRLF
318 "Accept: text/plain" CRLF
319 CRLF;
320
321 Message::Response response;
322 cf::network::tcp smsSock;
323 cf::network::host smsServer(url, 80);
324
325 smsSock.connect(smsServer);
326 smsSock.send(http);
327 smsSock.close();
328
329 return code;
330}
331
332static bool join(const Message::Parser & parser, const std::string & sms, const std::string & address)
333 throw (cf::exception)
334{
335 if (sms != parser.get<std::string>("sms"))
336 THROW_EXCEPTION("SMS is not same");
337
338 std::string id = parser.get<std::string>("id");
339 std::string pw = parser.get<std::string>("pw");
340
341 return dbmgr.join(id, pw, sms, address);
342}
343
344static bool login(const Message::Parser & parser)
345 throw (cf::exception)
346{
347 std::string id = parser.get<std::string>("id");
348 std::string pw = parser.get<std::string>("pw");
349
350 return dbmgr.login(id, pw);
351}
352
353static bool chat(const Message::Parser & parser,
354 const std::string & message)
355{
356 bool result = false;
357 std::string to = parser.get<std::string>("to");
358
359 if (isOnline(to))
360 {
361 gOnlineUsers[to].sock->send(message);
362 result = true;
363 }
364
365 return result;
366}
367
368static std::string keyExchange(const std::string sms, const std::string address)
369{
370 std::string sessionKey;
371
372
373}
374
375static std::string workerInitiator(cf::network::tcp & sock)
376{
377 try
378 {
379 std::string sms;
380
381 while (true)
382 {
383 Message::Parser parser;
384 parser.parse(sock.receive().toString());
385
386 if (parser.type() == "sms")
387 {
388 sms = httpSMS(parser);
389 }
390 else if (parser.type() == "join")
391 {
392 if (join(parser, sms, sock.peer().address()))
393 THROW_EXCEPTION("user(" << parser.get<std::string>("id") << ") cannot join");
394 }
395 else if (parser.type() == "login")
396 {
397 if (login(parser))
398 return parser.get<std::string>("id");
399 }
400 }
401 }
402 catch (cf::exception & e)
403 {
404 FORWARD_EXCEPTION(e);
405 }
406}
407
408static int worker(void * arg)
409{
410 Runner * runner = reinterpret_cast<Runner *>(arg);
411 cf::network::tcp * sock = runner->mSock;
412
413 std::string id;
414
415 try
416 {
417 workerInitiator(*sock);
418
419 Message::Response response;
420 bool result = true;
421
422 while (result)
423 {
424 std::string message = sock->receive().toString();
425 Message::Parser parser;
426 parser.parse(message);
427
428 LOG(message);
429
430 if (parser.type() == "command")
431 result = command(parser);
432 else if (parser.type() == "chat")
433 result = chat(parser, message);
434
435 sock->send(response.result(result));
436 }
437 }
438 catch (cf::exception & e)
439 {
440 LOG(e.what());
441 }
442
443 logout(id);
444 delete runner;
445 return 0;
446}
447
448static int server(unsigned short port)
449{
450 cf::network::tcp sock;
451
452 srand((unsigned int)time(NULL));
453
454 try
455 {
456 sock.bind(port);
457 sock.listen();
458 }
459 catch(cf::exception & e)
460 {
461 LOG(e.what());
462 return -1;
463 }
464
465 while (true)
466 {
467 try
468 {
469 cf::network::tcp client = sock.accept();
470 Runner * runner = new(std::nothrow) Runner(client, worker);
471 if (!runner)
472 THROW_EXCEPTION("cannot create thread argument");
473 }
474 catch(cf::exception & e)
475 {
476 LOG(e.what());
477 }
478 }
479
480 return 0;
481}
482
483int main(int argc, char ** argv)
484{
485 if (argc != 2)
486 {
487 std::cerr << "-_-^" << std::endl;
488 return -1;
489 }
490
491 return server((unsigned short)atoi(argv[1]));
492}
Note: See TracBrowser for help on using the repository browser.