]> www.average.org Git - loctrkd.git/blob - gps303/__main__.py
WIP to reorganise to microservices
[loctrkd.git] / gps303 / __main__.py
1 from getopt import getopt
2 from logging import getLogger, StreamHandler, DEBUG, INFO
3 from logging.handlers import SysLogHandler
4 from select import poll, POLLIN, POLLERR, POLLHUP, POLLPRI
5 from socket import socket, AF_INET, SOCK_STREAM, SOL_SOCKET, SO_REUSEADDR
6 import sys
7 from time import time
8
9 from .config import readconfig
10 from .gps303proto import handle_packet, make_response, LOGIN, set_config
11 from .evstore import initdb, stow
12 from .lookaside import prepare_response
13
14 CONF = "/etc/gps303.conf"
15
16 log = getLogger("gps303")
17
18 if __name__.endswith("__main__"):
19     opts, _ = getopt(sys.argv[1:], "c:d")
20     opts = dict(opts)
21     conf = readconfig(opts["-c"] if "-c" in opts else CONF)
22
23     if sys.stdout.isatty():
24         log.addHandler(StreamHandler(sys.stderr))
25     else:
26         log.addHandler(SysLogHandler(address="/dev/log"))
27     log.setLevel(DEBUG if "-d" in opts else INFO)
28     log.info("starting with options: %s", opts)
29
30     initdb(conf.get("daemon", "dbfn"))
31     set_config(conf)
32
33     ctlsock = socket(AF_INET, SOCK_STREAM)
34     ctlsock.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
35     ctlsock.bind(("", conf.getint("daemon", "port")))
36     ctlsock.listen(5)
37     ctlfd = ctlsock.fileno()
38     pollset = poll()
39     pollset.register(ctlfd, POLLIN | POLLERR | POLLHUP | POLLPRI)
40     clnt_dict = {}
41     while True:
42         try:
43             events = pollset.poll(1000)
44         except KeyboardInterrupt:
45             log.info("Exiting")
46             sys.exit(0)
47         for fd, ev in events:
48             if fd == ctlfd:
49                 if ev & POLLIN:
50                     clntsock, clntaddr = ctlsock.accept()
51                     clntfd = clntsock.fileno()
52                     clnt_dict[clntfd] = (clntsock, clntaddr, None)
53                     pollset.register(
54                         clntfd, POLLIN | POLLERR | POLLHUP | POLLPRI
55                     )
56                     log.debug(
57                         "accepted connection from %s as fd %d",
58                         clntaddr,
59                         clntfd,
60                     )
61                 if ev & ~POLLIN:
62                     log.debug("unexpected event on ctlfd: %s", ev)
63             else:
64                 try:
65                     clntsock, clntaddr, imei = clnt_dict[fd]
66                 except KeyError:  # this socket closed already
67                     continue
68                 if ev & POLLIN:
69                     packet = clntsock.recv(4096)
70                     when = time()
71                     if packet:
72                         msg = handle_packet(packet)
73                         log.debug("%s from %s fd %d", msg, clntaddr, fd)
74                         if isinstance(msg, LOGIN):
75                             imei = msg.imei
76                             clnt_dict[fd] = (clntsock, clntaddr, imei)
77                         stow(
78                             clntaddr,
79                             when,
80                             imei,
81                             msg.length,
82                             msg.PROTO,
83                             msg.payload,
84                         )
85                         kwargs = prepare_response(conf, msg)
86                         response = make_response(msg, **kwargs)
87                         if response:
88                             try:
89                                 # Ignore possibility of blocking
90                                 clntsock.send(make_response(msg))
91                             except OSError as e:
92                                 log.debug("sending to fd %d error %s", fd, e)
93                     else:
94                         # TODO: Also disconnect on HIBERNATION
95                         log.info("disconnect fd %d imei %s", fd, imei)
96                         pollset.unregister(fd)
97                         clntsock.close()
98                         del clnt_dict[fd]
99                 if ev & ~POLLIN:
100                     log.warning("unexpected event", ev, "on fd", fd)