-
Notifications
You must be signed in to change notification settings - Fork 2
/
server_tcp.py
291 lines (234 loc) · 11.7 KB
/
server_tcp.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
#! /usr/bin/python
from dis import dis
import sys
#===============================================================================
"""
Copyright (c) 2013 http://www.itfac.mrt.ac.lk
<email>syscall@knnect.com</email>
<summary>
Port listener to handle GPS data send from GPS/GPRS devices.
This is an Open source project and you may take this program as u wish with some rights reserved by www.itfac.mrt.ac.lk
</summary>
"""
#===============================================================================
"""
-------------------------------
For documentation purpose
-------------------------------
-------------what is socket.accept()-------------
Accept a connection. The socket must be bound to an address and listening for connections. The return value is a pair (conn, address) where conn is a new socket object usable to send and receive data on the connection, and address is the address bound to the socket on the other end of the connection.
A pair (host, port) is used for the AF_INET address family, where host is a string representing either a hostname in Internet domain notation like 'daring.cwi.nl' or an IPv4 address like '100.50.200.5', and port is an integer.
So the second value is the port number used by the client side for the connection. When a TCP/IP connection is established, the client picks an outgoing port number to communicate with the server; the server return packets are to be addressed to that port number.
-------------Luhn algorithm-------------
From Wikipedia, the free encyclopedia
The Luhn algorithm or Luhn formula, also known as the "modulus 10" or "mod 10" algorithm, is a simple checksum formula used to validate a variety of identification numbers,
such as credit card numbers, IMEI numbers, National Provider Identifier numbers in US and Canadian Social Insurance Numbers.
It was created by IBM scientist Hans Peter Luhn and described in U.S. Patent No. 2,950,048, filed on January 6, 1954, and granted on August 23, 1960.
The algorithm is in the public domain and is in wide use today. It is specified in ISO/IEC 7812-1.[1] It is not intended to be a cryptographically secure hash function;
it was designed to protect against accidental errors,
not malicious attacks. Most credit cards and many government identification numbers use the algorithm as a simple method of distinguishing valid numbers from collections of random digits.
-------------------Benefits of Asynchronous Sockets and Linux epoll----------------------
When a program uses blocking sockets it often uses one thread (or even a dedicated process) to carry out the communication on each of those sockets.
The main program thread will contain the listening server socket which accepts incoming connections from clients.
It will accept these connections one at a time, passing the newly created socket off to a separate thread which will then interact with the client.
Because each of these threads only communicates with one client, any blockage does not prohibit other threads from carrying out their respective tasks.
"""
#===============================================================================
# coding style CC python ie: variableName, ClassName ,functionName, _specialVariableName_
#===============================================================================
import threading
# import Queue
from gpsString import *
import socket # documentation http://docs.python.org/2/howto/sockets.html , http://docs.python.org/2/library/socket.html
from fileinput import filename
try:
# try to install MySQLdb module
import MySQLdb # Documentation http://mysql-python.sourceforge.net/MySQLdb.html
except ImportError:
# apt get code apt-get install python-mysqldb
print "Import failed MySql Database module "
import time
from datetime import datetime
import os # for configure linux server
import logging # reffrence doc http://docs.python.org/2/howto/logging.html
logging.basicConfig(filename="server_tcp.log", format='The event %(levelname)s was occored in %(asctime)s : PID : %(process)d when executing : %(funcName)s @ line number : %(lineno)d', level=logging.DEBUG)
# global variables for use
def main():
startupAnimation()
configInfoDict = configServer()
# log programm activities
logging.info("main process started")
# Set up the Socket:
while True:
try:
serverSocket = createSocket(int(configInfoDict.get("serverPort")), configInfoDict.get("serverIP"))
if serverSocket:
break
except socket.error:
print "Delaying connection for 5 seconds due to previously failed connection attempt..."
time.sleep(5)
continue
while True:
print "Current Connections= {}".format(threading.activeCount() - 1)
newConnection(serverSocket.accept(), configInfoDict.get("databaseIP"), configInfoDict.get("dbUser"), configInfoDict.get("dbPassword")).start()
# new Connection object for every connection creat between GPS/GPRS device and local server
class newConnection(threading.Thread):
def __init__(self, detailsPair, databaseIP, dbUser, dbPassword):
channel , address = detailsPair
self.channel = channel
self.connectionImei = None
self.address = address
# self.approvedImei = False # this has been moved to gpsObject class
self.splitedGpsData = ''
self.connectToDB(databaseIP, dbUser, dbPassword)
threading.Thread.__init__(self)
def connectToDB(self, databaseIP, dbUser, dbPassword):
# Open database connection
self.connection = MySQLdb.connect(databaseIP, dbUser, dbPassword)
self.connection.select_db("syscall")
self.cursor = self.connection.cursor()
def disconnect(self, reson="No reson specified"):
logging.warn("Connection has been disconnected due to >" + reson)
self.connection.commit()
if self.cursor:
self.cursor.close()
if self.channel:
self.channel.shutdown(2)
self.channel.close()
return False
def reciveGpsData(self):
try_count = 0
while True:
try:
try_count += 1
print "{}try to read data from device".format(try_count)
recivedDataFromGpsDevice = self.channel.recv(4096) # 4096 is the buffer size
return recivedDataFromGpsDevice
# print recivedDataFromGpsDevice # for debuging only
except socket.error as e:
logging.error(e)
print "Error connection to vehicle (disconnect without FIN packet) error = {}".format(e)
if try_count < 2:
continue
return ''
# this method is called when thread is created
def run(self):
# allow viewing server connection log via web page
print "Device connected from {} via its port {}".format(self.address[0], self.address[1])
gpsObject = gpsString(self.reciveGpsData())
# Change mode to blocking after connecting device
self.channel.setblocking(0) # set channel(or socket) to non-blocking mode
self.channel.settimeout(14) # wait 15 second blocked if not receve data rise exception
print "---------Initial check complete---------\n gpsObject is {}".format(gpsObject.isValidGpsString) # for debuging use only
# check this algo short curcuite matter?
if not (gpsObject.isValidGpsString and gpsObject.validateVehicleFromDB(self.cursor)): # pass the connection cursor to validator
print "Recived GPS String is invalid" # for debuging purpose
self.disconnect("Recived GPS String is invalid")
return False
print "-----Continue to recive data IMEI number is valid and approved -----"
# finally if everything went correctly , set online status 1 to that truck
connectionImei = gpsObject.imei # this `connectionImei` i s created to use on when device disconnected from device
self.connectionImei = connectionImei
# current_status = 1 means online 0 means offline
setOnlineFlag = """insert into vehicle_status values("{}",now(),null,1) ON DUPLICATE KEY update connected_on = now() , current_status = 1""".format(gpsObject.imei)
print setOnlineFlag
print "Vehicle Flag set to online"
print self.cursor.execute(setOnlineFlag)
self.connection.commit() # commit changes to DB imediatly
while True:
# recivedDataFromGpsDevice = self.channel.recv(2048) # 2048 is the buffer size
gpsObject = gpsString(self.reciveGpsData())
if not gpsObject.isValidGpsString:
# ping = self.channel.send("1") # FIXME have to ping to server and confirm its disconnected befor we drop connection
print "Device has been disconnected from remote end no retrying "
setOnlineFlag = """update vehicle_status set disconnected_on = now(),current_status = 0 where imei = "{}" """.format(connectionImei)
self.cursor.execute(setOnlineFlag)
self.connection.commit()
self.disconnect("Device has been disconnected from remote end DB Flag set To Disconnected")
print ("Device has been disconnected from remote end DB Flag set To Disconnected")
return False
elif not gpsObject.isConnectedToSatellites:
print "Device is not connected to GPS Satellites"
continue # waiting to connect device to GPS Satellites
print "Receiving GPS coordinates....(Thread Name: {})".format(self.getName())
try:
# print sat_time
sql = """ insert into coordinates(sat_time,sat_status,latitude,longitude,speed,bearing,imei,location_area_code,cell_id) values("{}",'{}',{},{},{},{},"{}","{}","{}")""".format(gpsObject.sat_time, gpsObject.sat_status, gpsObject.latitude, gpsObject.longitude, gpsObject.speed, gpsObject.bearing, gpsObject.imei, gpsObject.location_area_code, gpsObject.cell_id)
except ValueError:
sql = ""
print "SQL ValueError"
continue
try:
# Execute the SQL command
self.cursor.execute(sql)
except :
# Roll back in case there is any error
print sql
print "Mysql Execution Error"
self.connection.rollback()
# this class is for future advancements
class vehicle():
pass
def createSocket(portNumber=9090, serverIP=""):
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
serverIP = ""
port = portNumber
server.bind((serverIP, port))
server.listen(5)
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
print "Socket created on IP {} port {} ".format(serverIP, port)
return server
# Server configuration
def configServer():
"""
Import configuration file and set parameters
"""
try:
config = open(r"./server.conf", "r+")
except IOError, e:
print e
return 0
configLines = []
try:
while True:
configLines.append(config.next())
except StopIteration:
pass
finally:
config.close()
configInfo = {}
for line in configLines:
if line[0] == "#" or line[0] == "\n":
continue
configLineArgumentList = line[:-1].split("=")
key = configLineArgumentList[0]
value = configLineArgumentList[1]
configInfo.update({key:value})
logging.info("Configuration done sucssesfully")
return configInfo
#===============================================================================
# Standard boilerplate to call the main() function to begin the program.
#===============================================================================
def startupAnimation():
print ''
print ' ____ _____ ____ ____ '
time.sleep(0.1)
print ' / \ | | / \ / \ / \ | | '
time.sleep(0.1)
print '| | | | | | | \ | | | '
time.sleep(0.1)
print '| \____/| | \____/ \___/\ |_ |_ v0.5'
time.sleep(0.1)
print '|______ | |_______ '
time.sleep(0.1)
print ' \ | \ '
time.sleep(0.1)
print ' | | | '
time.sleep(0.1)
print ' ______/ _____/ \_____/ '
time.sleep(0.1)
print 'Contact us for any bug reports at syscall@knnect.com '
time.sleep(0.1)
print '\n'
if __name__ == "__main__":
main()