re-worked SocketService; #999
Costa Tsaousis (ktsaou) committed
Nov 11, 2016 at 01:04 UTC
a07c0acc8429f770d8abbcfea34a705b2d756de3
1 file changed
+93
-53
python.d/python_modules/base.py
+93
-53
@@ -508,6 +508,79 @@ class SocketService(SimpleService):
508
self.__socket_config = None
509
SimpleService.__init__(self, configuration=configuration, name=name)
510
511
+ def _socketerror(self, msg=None):
512
+ if self.unix_socket is not None:
513
+ self.error("unix socket '" + self.unix_socket + "':", msg)
514
+ else:
515
+ if self.__socket_config is not None:
516
+ af, socktype, proto, canonname, sa = self.__socket_config
517
+ self.error("socket to '" + str(sa[0]) + "' port " + str(sa[1]) + ":", msg)
518
+ else:
519
+ self.error("unknown socket:", msg)
520
+
521
+ def _connect2socket(self, res=None):
522
+ """
523
+ Connect to a socket, passing the result of getaddrinfo()
524
+ :return: boolean
525
+ """
526
+ if res is None:
527
+ res = self.__socket_config
528
+ if res is None:
529
+ self.error("Cannot create socket to 'None':")
530
+ return False
531
+
532
+ af, socktype, proto, canonname, sa = res
533
+ try:
534
+ self.debug("creating socket to '" + str(sa[0]) + "', port " + str(sa[1]))
535
+ self._sock = socket.socket(af, socktype, proto)
536
+ except socket.error as e:
537
+ self.error("Failed to create socket to '" + str(sa[0]) + "', port " + str(sa[1]) + ":", str(e))
538
+ self._sock = None
539
+ self.__socket_config = None
540
+ return False
541
+
542
+ try:
543
+ self.debug("connecting socket to '" + str(sa[0]) + "', port " + str(sa[1]))
544
+ self._sock.connect(sa)
545
+ except socket.error as e:
546
+ self.error("Failed to connect to '" + str(sa[0]) + "', port " + str(sa[1]) + ":", str(e))
547
+ self._disconnect()
548
+ self.__socket_config = None
549
+ return False
550
+
551
+ self.debug("connected to '" + str(sa[0]) + "', port " + str(sa[1]))
552
+ self.__socket_config = res
553
+ return True
554
+
555
+ def _connect2unixsocket(self, path=None):
556
+ """
557
+ Connect to a unix socket, given its filename
558
+ :return: boolean
559
+ """
560
+ if path is None:
561
+ self.error("cannot connect to unix socket 'None'")
562
+ return False
563
+
564
+ try:
565
+ self.debug("attempting DGRAM unix socket '" + str(path) + "'")
566
+ self._sock = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)
567
+ self._sock.connect(path)
568
+ self.debug("connected DGRAM unix socket '" + str(path) + "'")
569
+ return True
570
+ except socket.error as e:
571
+ self.error("Failed to connect DGRAM unix socket '" + str(path) + "':", str(e))
572
+
573
+ try:
574
+ self.debug("attempting STREAM unix socket '" + str(path) + "'")
575
+ self._sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
576
+ self._sock.connect(path)
577
+ self.debug("connected STREAM unix socket '" + str(path) + "'")
578
+ return True
579
+ except socket.error as e:
580
+ self.error("Failed to connect STREAM unix socket '" + str(path) + "':", str(e))
581
+ self._sock = None
582
+ return False
583
+
584
def _connect(self):
585
"""
586
Recreate socket and connect to it since sockets cannot be reused after closing
@@ -515,59 +588,24 @@ class SocketService(SimpleService):
588
:return:
589
"""
590
try:
518
- if self.unix_socket is None:
519
- if self.__socket_config is None:
520
- # establish ipv6 or ipv4 connection.
521
- for res in socket.getaddrinfo(self.host, self.port, socket.AF_UNSPEC, socket.SOCK_STREAM):
522
- self.debug("connecting socket to host '" + str(self.host) + "', port " + str(self.port))
523
- try:
524
- # noinspection SpellCheckingInspection
525
- af, socktype, proto, canonname, sa = res
526
- self._sock = socket.socket(af, socktype, proto)
527
- except socket.error as e:
528
- self.debug("Cannot create socket:", str(e))
529
- self._sock = None
530
- continue
531
- try:
532
- self._sock.connect(sa)
533
- except socket.error as e:
534
- self.debug("Cannot connect to socket:", str(e))
535
- self._disconnect()
536
- continue
537
- self.__socket_config = res
538
- break
539
- else:
540
- # connect to socket with previously established configuration
541
- try:
542
- af, socktype, proto, canonname, sa = self.__socket_config
543
- self._sock = socket.socket(af, socktype, proto)
544
- self._sock.connect(sa)
545
- except socket.error as e:
546
- self.debug("Cannot create or connect to socket:", str(e))
547
- self._disconnect()
591
+ if self.unix_socket is not None:
592
+ _connect2unixsocket(self.unix_socket)
593
+
594
else:
549
- # connect to unix socket
550
- try:
551
- self.debug("connecting unix socket '" + str(self.unix_socket) + "'")
552
- self._sock = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)
553
- self._sock.connect(self.unix_socket)
554
- except socket.error:
555
- self._sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
556
- self._sock.connect(self.unix_socket)
595
+ if self.__socket_config is not None:
596
+ self._connect2socket()
597
+ else:
598
+ for res in socket.getaddrinfo(self.host, self.port, socket.AF_UNSPEC, socket.SOCK_STREAM):
599
+ if self._connect2socket(res): break
600
601
except Exception as e:
559
- self.error(str(e),
560
- "Cannot create socket with following configuration: host:", str(self.host),
561
- "port:", str(self.port),
562
- "socket:", str(self.unix_socket))
602
self._sock = None
603
+ self.__socket_config = None
604
605
if self._sock is not None:
606
self._sock.setblocking(0)
607
self._sock.settimeout(5)
568
- self.debug("connected with timeout " + str(self._sock.gettimeout()))
569
- else:
570
- self.debug("not connected")
608
+ self.debug("set socket timeout to: " + str(self._sock.gettimeout()))
609
610
def _disconnect(self):
611
"""
@@ -576,7 +614,7 @@ class SocketService(SimpleService):
614
"""
615
if self._sock is not None:
616
try:
579
- self.debug("disconnecting")
617
+ self.error("closing socket")
618
self._sock.shutdown(2) # 0 - read, 1 - write, 2 - all
619
self._sock.close()
620
except Exception:
@@ -594,11 +632,8 @@ class SocketService(SimpleService):
632
self.debug("sending request")
633
self._sock.send(self.request)
634
except Exception as e:
635
+ self._socketerror("error sending request:" + str(e))
636
self._disconnect()
598
- self.error(str(e),
599
- "used configuration: host:", str(self.host),
600
- "port:", str(self.port),
601
- "socket:", str(self.unix_socket))
637
return False
638
return True
639
@@ -610,22 +645,25 @@ class SocketService(SimpleService):
645
data = ""
646
while True:
647
try:
613
- self.debug("receiving response")
648
+ self.debug("waiting response")
649
ready_to_read, _, in_error = select.select([self._sock], [], [], 5)
650
except Exception as e:
616
- self.error("timeout while waiting for response:", str(e))
651
+ self._socketerror("timeout while waiting for response:" + str(e))
652
self._disconnect()
653
break
654
+
655
if len(ready_to_read) > 0:
656
+ self.debug("receiving response")
657
buf = self._sock.recv(4096)
658
if buf is None or len(buf) == 0: # handle server disconnect
659
+ self.debug("server closed the connection")
660
self._disconnect()
661
break
662
data += buf.decode(errors='ignore')
663
if self._check_raw_data(data):
664
break
665
else:
628
- self.error("Socket timed out.")
666
+ self._socketerror("timeout")
667
self._disconnect()
668
break
669
@@ -638,6 +676,8 @@ class SocketService(SimpleService):
676
"""
677
if self._sock is None:
678
self._connect()
679
+ if self._sock is None:
680
+ return None
681
682
# Send request if it is needed
683
if not self._send():