· 8 years ago · Nov 21, 2017, 03:40 PM
1from multiprocessing import Process
2import socket,time,sqlite3,time,os,random
3try:
4 import serv_settings
5except:
6 f = open("serv_settings.py","w")
7 t = '''
8IP_ADDRESS = ""
9
10PORT = 9090
11
12KEY_DECAY_TIME = 3600
13
14ONLINE_CONFIRM_TIME = 600
15
16LOGGING = 1
17
18LOGFOLDER = "logs"
19
20MAX_CLIENTS = 100
21 '''
22 f.write(t)
23 f.close()
24 import serv_settings
25
26
27
28def error_p(errmsg):
29 print("Error: "+errmsg)
30
31def logmsg(logmsg):
32 a = time.strftime("%H-%M %d %h %Y")
33 print(a+": "+logmsg)
34
35def add_nulls(dlen,data):
36 to_ret = data
37 if(len(data)<dlen):
38 dif = dlen-len(data)
39 to_ret = "0"*dif+to_ret
40 return to_ret
41
42class logging_db:
43 def __init__(self):
44 print(1)
45 #cur,connection = self.connect_to_db()
46 #todo
47 #make traffic counting
48 #make error logging here
49 #traffic counted by dates and users
50 #each user has to have separate table
51 #tables must be wiped sometimes))))00000
52
53 def connect_to_db(self):
54 try:
55 connection = sqlite3.connect(serv_settings.LOGFOLDER+"/"+"log.db")
56 except:
57 os.mkdir(serv_settings.LOGFOLDER)
58 connection = sqlite3.connect(serv_settings.LOGFOLDER+"/"+"log.db")
59 cur = connection.cursor()
60 return(cur,connection)
61
62
63
64
65class dbwork:
66 #1)login,password,id - logindata
67 #2)id,key,time_to_change_key - keys
68 #3)id,time_to_offline - onlines
69 #4)id,unread_messages - messages
70 def __init__(self):
71 cur,connection = self.connect_to_db()
72 #creating tables
73 cur.execute('''
74 CREATE TABLE IF NOT EXISTS logindata(
75 ID INTEGER PRIMARY KEY,
76 LOGIN TEXT,
77 PASSWORD TEXT)
78 ''')
79 cur.execute('''
80 CREATE TABLE IF NOT EXISTS keys(
81 ID INTEGER,
82 KEY INTEGER,
83 DTIME INTEGER)
84 ''')
85 cur.execute('''
86 CREATE TABLE IF NOT EXISTS onlines(
87 ID INTEGER PRIMARY KEY,
88 OTIME INTEGER)
89 ''')
90 cur.execute('''
91 CREATE TABLE IF NOT EXISTS messages(
92 ID INTEGER,
93 MESSAGE BLOB)
94 ''')#ID of the user to recive message
95 connection.commit()
96 connection.close()
97
98 def connect_to_db(self):
99 connection = sqlite3.connect("chatdb.db")
100 cur = connection.cursor()
101 return(cur,connection)
102
103 def generate_key(self,ID): #generates a new key for given ID
104 random.seed()
105 cur,connection = self.connect_to_db()
106 key = random.randint(10000000,99999999)
107 ok = 0
108 while(ok==0): #generating a unique key for messaging
109 cur.execute("SELECT * FROM keys WHERE KEY = ?",(key,))
110 if(cur.fetchone()==None):
111 ok = 1
112 break
113 else:
114 key = random.randint(10000000,99999999)
115 cur.execute("SELECT * FROM keys WHERE ID = ?",(ID,)) #checking if the
116 dtime = time.time()+serv_settings.KEY_DECAY_TIME #ID in table
117 if(cur.fetchone()==None):
118 cur.execute("INSERT INTO keys VALUES (?,?,?)",(ID,key,dtime))
119 else:
120 cur.execute("UPDATE keys SET KEY = ?, DTIME = ? WHERE ID = ?",(key,dtime,ID))
121 connection.commit()
122 connection.close()
123 return(key)
124
125 def get_messages(self,ID):
126 cur,connection = self.connect_to_db()
127 cur.execute("SELECT MESSAGE FROM messages WHERE ID = ?",(ID,))
128 msgs = cur.fetchall()
129 msgdata = b""
130 if(msgs==[]):
131 connection.close()
132 return(0)
133 else:
134 for msg in msgs:
135 message = msg[0]
136 msgdata+=message
137 cur.execute("DELETE FROM messages WHERE ID = ?",(ID,))
138 connection.commit()
139 connection.close()
140 return(msgdata)
141
142 def get_ID_by_login(self,login):
143 cur,connection = self.connect_to_db()
144 cur.execute("SELECT ID FROM logindata WHERE LOGIN = ?",(login,))
145 ID = cur.fetchone()[0]
146 connection.close()
147 return(ID)
148
149 def get_key(self,ID): #returns a key for given ID
150 cur,connection = self.connect_to_db()
151 cur.execute("SELECT KEY FROM keys WHERE ID = ?",(ID,))
152 key = cur.fetchone()
153 if(key!=None):
154 key=key[0]
155 connection.close()
156 return(key)
157
158 def get_key_dtime(self,ID):
159 cur,connection = self.connect_to_db()
160 cur.execute("SELECT DTIME FROM keys WHERE ID = ?",(ID,))
161 dtime = cur.fetchone()
162 if(dtime!=None):
163 dtime=dtime[0]
164 connection.close()
165 return(dtime)
166
167 def get_ID_by_key(self,key):
168 cur,connection = self.connect_to_db()
169 cur.execute("SELECT ID, DTIME FROM keys WHERE key = ?",(key,))
170 uid = cur.fetchone()
171 connection.close()
172 if(uid==None):
173 return(-1)#no such key
174 else:
175 dtime = uid[1]
176 uid = uid[0]
177 if(dtime<time.time()):
178 return(-2)#timed out key
179 else:
180 return(uid)
181
182 def update_user_online(self,ID):
183 otime = time.time()+serv_settings.ONLINE_CONFIRM_TIME
184 cur,connection = self.connect_to_db()
185 cur.execute("REPLACE INTO onlines VALUES(?,?)",(ID,otime))
186 connection.commit()
187 connection.close()
188
189 def get_users_online(self):
190 ctime = time.time()
191 cur,connection = self.connect_to_db()
192 cur.execute("SELECT ID FROM onlines WHERE OTIME > ?",(ctime,))
193 onlineIDs = cur.fetchall()
194 onlines = []
195 if(onlineIDs == []):
196 return([])
197 else:
198 for oid in onlineIDs:
199 onlines.append(oid[0])
200 return(onlines)
201
202 def add_message(self,ID,msg):
203 cur,connection = self.connect_to_db()
204 cur.execute("INSERT INTO messages VALUES(?,?)",(ID,msg))
205 connection.commit()
206 connection.close()
207
208 def login(self,login,password):
209 cur,connection = self.connect_to_db()
210 cur.execute("SELECT * FROM logindata WHERE LOGIN = ?",(login,))
211 udata = cur.fetchone()
212 if(udata==None):
213 cur.execute("INSERT INTO logindata VALUES (NULL,?,?)",(login,password))
214 connection.commit()
215 connection.close()
216 ID = self.get_ID_by_login(login)
217 key = self.generate_key(ID)
218 self.update_user_online(ID)
219 return([0,key]) #OK - new registered
220 else:
221 if(udata[2]==password):
222 connection.close()
223 ID = self.get_ID_by_login(login)
224 key = self.generate_key(ID)
225 self.update_user_online(ID)
226 return([0,key]) #OK - ok login&pwd
227 else:
228 connection.close()
229 return([1,0]) #login already exists(it means - password incorrect)
230
231
232class client_job:
233
234 def send_close(self,data):
235 self.send_msg(data)
236 self.conn.close()
237 def send_msg(self,data):
238 count = 0
239 try:
240 try:
241 self.conn.send(data.encode("utf-8"))
242 count = len(data.encode("utf-8"))
243 except:
244 self.conn.send(data)
245 count = len(data)
246 except:
247 self.write_log("error sending to: "+str(self.addr))
248 return
249 self.count_traffic(count,"out")
250
251 def answer_ask_chk(self):
252 self.ID = self.database.get_ID_by_key(self.key)
253 if(self.ID>0):
254 dtime = self.database.get_key_dtime(self.ID)
255 dtime-=time.time()
256 dtime = add_nulls(4,str(dtime))
257 self.database.update_user_online(self.ID)
258 self.send_msg("OK"+dtime)
259 return(-1)
260 else:
261 if(self.ID==-1):
262 self.error = 5 #wrong key
263 else:
264 self.error = 6 #key timed out
265 return(0)
266
267 def read_ask_msg(self,data):
268 try:
269 ask_m = data.decode("utf-8")
270 except:
271 self.error = 1 #encoding failure
272 return(0)
273 if(len(ask_m)!=11):
274 self.error = 3 #message badly structured
275 return(0)
276 mtype = ask_m[:3]
277 if(mtype=="CHK"):
278 try:
279 self.key = int(ask_m[3:])
280 except:
281 self.error = 5
282 return(0)
283 return self.answer_ask_chk()
284 if(mtype=="MES"):
285 try:
286 self.protocol = int(ask_m[3:7])
287 ret_bytes = int(ask_m[7:])
288 except:
289 self.error = 1
290 return(0)
291 return ret_bytes
292 else:
293 self.error = 2 #unknown initiation
294 return(0)
295
296 def check_key_ID(self):
297 realID = self.database.get_ID_by_key(self.key)
298 if(realID==self.ID):
299 return(1)
300 else:
301 if(realID==-1):
302 self.error = 5
303 return(0)
304 else:
305 self.error = 6
306 return(0)
307
308
309 def process_message(self,trg_ID,message):
310 if(self.check_key_ID()==1):
311 if(self.database.get_key(trg_ID)==None):
312 self.error = 9
313 return(0)
314 else:
315 msglen = str(add_nulls(4,str(len(message)))).encode("utf-8")
316 sender = str(add_nulls(8,str(self.ID))).encode("utf-8")
317 dbmsg = sender+msglen+message #add a sender's ID and msglen
318 self.database.add_message(trg_ID,dbmsg)
319 self.database.update_user_online(self.ID)
320 msg = "OK"+add_nulls(16,"")
321 self.send_msg(msg)
322 return(-1)
323 else:
324 self.error = 5
325 return(0)
326
327 def read_msg(self,data,len_m):
328 if(len(data)!=len_m):
329 self.error = 3
330 return(0)
331 try:
332 mtype = data[:3].decode("utf-8")
333 except:
334 self.error = 1
335 return(0)
336 if(data[-3:].decode("utf-8")!="FIN"):
337 self.error = 3
338 return(0)
339 if(mtype=="MSG"):#messages can be not a unicode str
340 if(self.protocol==1):
341 try:
342 self.ID = int(data[3:11].decode("utf-8"))
343 self.key = int(data[11:19].decode("utf-8"))
344 trg_ID = int(data[19:27].decode("utf-8"))
345 except:
346 self.error = 3
347 return(0)
348 msg = data[27:-3]
349 return(self.process_message(trg_ID,msg))
350 else:
351 self.error = 4 #protocol mismatch
352 return(0)
353 try:
354 cl_data = data.decode("utf-8")
355 except:
356 self.error = 1
357 return(0)
358 if(cl_data[-3:]!="FIN"):
359 self.error = 3
360 return(0)
361 mtype = cl_data[:3]
362 if(mtype=="LOG"):
363 if(self.protocol==1):
364 try:
365 llen = int(cl_data[3:7])
366 plen = int(cl_data[7:11])
367 except:
368 self.error = 3
369 return(0)
370 self.login = cl_data[11:11+llen]
371 self.password = cl_data[11+llen:11+llen+plen]
372 result = self.database.login(self.login,self.password)
373 if(result[0]==0):
374 self.key = result[1]
375 self.ID = self.database.get_ID_by_key(self.key)
376 if(self.ID<0):
377 self.error = 7 #internal error???? must not happen
378 return(0)
379 else:
380 msg = "OK"+add_nulls(8,str(self.key))+add_nulls(8,str(self.ID))
381 self.send_msg(msg)
382 return(-1)
383 else:
384 self.error = 8 #wrong password for existing login
385 return(0)
386 else:
387 self.error = 4
388 return(0)
389 if(mtype=="UPD"):
390 if(self.protocol==1):
391 try:
392 self.key = int(cl_data[3:11])
393 except:
394 self.error = 5
395 return(0)
396 self.ID = self.database.get_ID_by_key(self.key)
397 if(self.ID>0):
398 msgdata = self.database.get_messages(self.ID)
399 if(msgdata==0):
400 self.error = 10
401 return(0)
402 else:
403 msgdata = msgdata
404 msg = "OK"+add_nulls(16,str(len(msgdata)))
405 self.database.update_user_online(self.ID)
406 self.send_msg(msg)
407 self.send_msg(msgdata)
408 return(-1)
409 else:
410 self.error = 5
411 return(0)
412 else:
413 self.error = 4
414 return(0)
415 if(mtype=="WOL"):
416 if(self.protocol==1):
417 onlines = self.database.get_users_online()
418 if(onlines==[]):
419 self.error = 11
420 return(0)
421 outmsg = ""
422 for oid in onlines:
423 outmsg+=add_nulls(8,str(oid))
424 outmsg = outmsg.encode("utf-8")
425 lenmsg = len(outmsg)
426 msg = "OK"+add_nulls(16,str(lenmsg))
427 self.send_msg(msg)
428 self.send_msg(outmsg)
429 return(-1)
430 else:
431 self.error = 4
432 return(0)
433
434 def write_log(self,errtext):
435 if(serv_settings.LOGGING==1 and self.error!=10 and self.error!=11):
436 lname = add_nulls(8,str(self.ID))
437 try:
438 f = open(serv_settings.LOGFOLDER+"/"+lname,"a")
439 except:
440 os.mkdir(serv_settings.LOGFOLDER)
441 f = open(serv_settings.LOGFOLDER+"/"+lname,"a")
442 outstr = time.strftime("***%Y-%m-%d %H:%M:%S*** ")
443 outstr+="Error ID: "+str(self.error)+" "
444 outstr+="Error text: "+errtext+"\n"
445 f.write(outstr)
446 f.close()
447 print(outstr)
448
449 def count_traffic(self,num,traffic_type):
450 ipstr = str(self.addr[0]).replace(".","g")
451 if(serv_settings.LOGGING==1):
452 try:
453 try:
454 f = open(serv_settings.LOGFOLDER+"/"+"traffic"+traffic_type+ipstr+".txt","r")
455 except:
456 f = open(serv_settings.LOGFOLDER+"/"+"traffic"+traffic_type+ipstr+".txt","w")
457 f.close()
458 f = open(serv_settings.LOGFOLDER+"/"+"traffic"+traffic_type+ipstr+".txt","r")
459 except:
460 os.mkdir(serv_settings.LOGFOLDER)
461 f = open(serv_settings.LOGFOLDER+"/"+"traffic"+traffic_type+ipstr+".txt","r")
462 count = f.read()
463 f.close()
464 try:
465 c_bytes = int(count)
466 except:
467 c_bytes = 0
468 c_bytes+=num
469 f = open(serv_settings.LOGFOLDER+"/"+"traffic"+traffic_type+ipstr+".txt","w")
470 f.write(str(c_bytes))
471 f.close()
472
473
474 def work_with_client(self,conn,addr):
475 self.database = dbwork()
476 self.conn = conn
477 self.addr = addr
478 self.ID = ""
479 self.key = ""
480 self.login = ""
481 self.password = ""
482 self.protocol = 0
483 self.error = 0 #zero is for unknown error
484 try:
485 data = self.conn.recv(11)
486 except:
487 print(1)
488 to_recieve = self.read_ask_msg(data)
489 if(to_recieve==0):
490 bmsg = "BA"+add_nulls(4,str(self.error))
491 self.send_close(bmsg.encode("utf-8"))
492 self.write_log("initiation bad from: "+str(self.addr))
493 return
494 elif(to_recieve==-1):
495 self.conn.close()
496 return
497 else:
498 self.send_msg("OK0000".encode("utf-8"))
499 data = conn.recv(to_recieve)
500 to_recieve = self.read_msg(data,to_recieve)
501 if(to_recieve==0):
502 bmsg = "BA"+add_nulls(16,str(self.error))
503 self.send_close(bmsg.encode("utf-8"))
504 self.write_log("shit with message from: "+str(self.addr))
505 else:
506 self.conn.close()
507
508#KEEP IN MIND THAT MULTIPROCESS DOES NOT WORK IN IDLE, START THE SERVER
509#USING A DOUBLECLICK ON PY FILE
510
511def start_process(conne,addre):
512 job = client_job()
513 job.work_with_client(conne,addre)
514
515if(__name__=="__main__"):
516 sock = socket.socket()
517 sock.bind((serv_settings.IP_ADDRESS, serv_settings.PORT))
518 sock.listen(serv_settings.MAX_CLIENTS)
519 while True:
520 conn, addr = sock.accept()
521 answ = Process(target=start_process,args=(conn,addr))
522 answ.start()
523 answ.join()