source: chevmsgr/trunk/msgsrv.cpp@ 13

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

서버 쪼끔 수정

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