Renamed Service into ServiceIn
[ais.git] / bin / inputs / tcpout.py
1 #!/usr/bin/env python
2
3 '''
4 Module for receiving AIVDM data from outbound TCP connection.
5 '''
6
7 from __future__ import division
8 import logging
9 import socket
10
11 from ais.inputs.common import DEFAULT_MTU, get_source_by_id4
12 from ais.inputs.virtual import Channel, ServiceIn
13
14 TCP_HEADER_SIZE = 52
15
16 class TcpOutChannel(Channel):
17     '''
18     Channel bound to a TCP server and listen for data there.
19     '''
20     def __init__(self, id4, hostname, port):
21         Channel.__init__(self)
22         self.id4 = id4
23         self.source = get_source_by_id4(id4)
24         self.hostname = hostname
25         self.port = port
26         self.name = '%s:%s' % (self.hostname, self.port)
27         address_out = (self.hostname, self.port)
28
29         # TODO try all IP addresses
30         # see http://docs.python.org/library/socket.html#example
31         try:
32             self.sock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
33             self.sock.connect(address_out)
34             logging.info("Connected to %s using tcp6", address_out)
35         except socket.gaierror, err:
36             logging.error("Can't connet to %s: %s using tcp6", address_out, err)
37             self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
38             self.sock.connect(address_out)
39             logging.info("Connected to %s using tcp4", address_out)
40
41     def fill_buffer(self):
42         '''
43         Grab more bytes into self.data internal buffer.
44         '''
45         data = self.sock.recv(DEFAULT_MTU)
46         if not data:
47             # FIXME: do reconnect
48             assert data, 'Connection closed'
49         stats = self.source.stats
50         stats.npackets += 1
51         stats.nbytes += len(data)
52         stats.nbytes_ethernet += len(data) + TCP_HEADER_SIZE
53         logging.debug('IN %s %s', self.name, repr(data))
54         self.data += data
55
56
57 class TcpOutServiceIn(ServiceIn):
58     '''
59     Service that connects to a TCP server and listen for data there.
60     '''
61     def __init__(self, id4, hostname, port):
62         #ServiceIn.__init__(self, stdout)
63         self.channel = TcpOutChannel(id4, hostname, port)
64         
65     def __repr__(self):
66         return 'TcpOutServiceIn<%s,%s>' \
67             % (self.channel.hostname, self.channel.port)
68
69     def fileno(self):
70         '''
71         Returns file descriptor of underlying socket, for os.select().
72         '''
73         return self.channel.sock.fileno()
74
75     def get_activity(self):
76         '''
77         Pool the channel and returns information when ready.
78         '''
79         channel = self.channel
80         channel.fill_buffer()
81         return channel.name, channel