Coverage for pyilper/piltcpip.py: 81%
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1#!/usr/bin/python3
2# -*- coding: utf-8 -*-
3# pyILPER 1.2.1 for Linux
4#
5# An emulator for virtual HP-IL devices for the PIL-Box
6# derived from ILPER 1.4.5 for Windows
7# Copyright (c) 2008-2013 Jean-Francois Garnier
8# C++ version (c) 2013 Christoph Gießelink
9# Python Version (c) 2015 Joachim Siebold
10#
11# This program is free software; you can redistribute it and/or
12# modify it under the terms of the GNU General Public License
13# as published by the Free Software Foundation; either version 2
14# of the License, or (at your option) any later version.
15#
16# This program is distributed in the hope that it will be useful,
17# but WITHOUT ANY WARRANTY; without even the implied warranty of
18# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19# GNU General Public License for more details.
20#
21# You should have received a copy of the GNU General Public License
22# along with this program; if not, write to the Free Software
23# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24#
25# tcpip object class ---------------------------------------------
26#
27# Initial version derived from ILPER 1.43
28#
29# Changelog
30#
31# 24.09.2015 cg
32# - added real IPv4/IPv6 dual stack mode
33# - reconnecting server and client work now
34# - broken loop don't crash connection any more
35# - removed some unused class variables
36# 05.10.2015 jsi
37# - class statement syntax update
38# 26.10.2015 cg
39# - stop endless loop in sendFrame() when client connection fail
40# 22.11.2015 cg
41# - removed remainder call of setsrqbit()
42# 23.11.2015 jsi
43# - removed all of the SSRQ/CSRQ approach
44# 29.11.2015 jsi
45# - removed activity timer
46# 07.02.2016 jsi
47# - setpilbox call removed
48# 13.10.2016 jsi
49# - remove unregister function
50# - store tab name if device is registered
51# 30.10.2016 jsi
52# - getDevices added (removed by mistake)
53# 22.12.2016 jsi
54# - raise TcpIpError missing second param added
55# 06.01.2017 jsi:
56# - check for ConnectionError exception when sendig frame to catch all exceptions
57# 16.01.2017 jsi:
58# - check for incoming connections to indicate isConnected
59# - close_outsocket method added
60# 07.01.2017 jsi:
61# - timeout parameter added
62# - refactoring: move code of process() and sendFrame() and device list handling
63# to thread object
64# 03.02.2020 jsi:
65# - fixed Python 3.8 syntax warning
67import select
68import socket
70class TcpIpError(Exception):
71 def __init__(self,msg,add_msg=None):
72 self.msg = msg
73 if add_msg is None:
74 self.add_msg=""
75 else:
76 self.add_msg = add_msg
78class cls_piltcpip:
80 def __init__(self,port,remotehost,remoteport):
81 self.__port__=port # port for input connection
82 self.__remotehost__=remotehost # host for output connection
83 self.__remoteport__=remoteport # port for output connection
85 self.__devices__ = [] # list of virtual devices
87 self.__serverlist__ = []
88 self.__clientlist__= []
89 self.__outsocket__= None
90 self.__outconnected__= False
91 self.__inconnected__= False
93 def isConnected(self):
94 return self.__outconnected__ and self.__inconnected__
96#
97# Connect to Network
98#
99 def open(self):
100#
101# open network connections
102#
103 host= None
104 self.__serverlist__.clear()
105 self.__clientlist__.clear()
106 for res in socket.getaddrinfo(host, self.__port__, socket.AF_UNSPEC,
107 socket.SOCK_STREAM, 0, socket.AI_PASSIVE):
108 af, socktype, proto, canonname, sa = res
109 try:
110 s = socket.socket(af, socktype, proto)
111 except OSError as msg:
112 s = None
113 continue
114 try:
115 s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
116 s.bind(sa)
117 s.listen(1)
118 self.__serverlist__.append(s)
119 except OSError as msg:
120 s.close()
121 continue
122 if len(self.__serverlist__) == 0:
123 raise TcpIpError("cannot bind to port","")
125 def openclient(self):
126#
127# connect to remote host
128#
129 self.__outsocket__ = None
130 self.__outconnected__= False
131 for res in socket.getaddrinfo(self.__remotehost__, self.__remoteport__, socket.AF_UNSPEC, socket.SOCK_STREAM):
132 af, socktype, proto, canonname, sa = res
133 try:
134 self.__outsocket__ = socket.socket(af, socktype, proto)
135 except OSError as msg:
136 self.__outsocket__ = None
137 continue
138 try:
139 self.__outsocket__.connect(sa)
140 self.__outconnected__= True
141 except OSError as msg:
142 self.__outsocket__.close()
143 self.__outsocket__ = None
144 continue
145 break
146 return self.__outconnected__
148#
149# Disconnect from Network
150#
151 def close(self):
152 for s in self.__clientlist__:
153 s.close()
154 for s in self.__serverlist__:
155 s.close()
156 if self.__outconnected__:
157 self.__outsocket__.shutdown(socket.SHUT_WR)
158 self.__outsocket__.close()
159 self.__outsocket__= None
160 self.__outconnected__= False
162#
163# Close output socket
164#
165 def close_outsocket(self):
166 if self.__outconnected__:
167 self.__outsocket__.shutdown(socket.SHUT_WR)
168 self.__outsocket__.close()
169 self.__outsocket__= None
170 self.__outconnected__= False
171#
172# Read HP-IL frame from PIL-Box (2 byte), handle connect to server socket
173#
174 def read(self,timeout):
175 readable,writable,errored=select.select(self.__serverlist__ + self.__clientlist__,[],[],timeout)
176 for s in readable:
177 if self.__serverlist__.count(s) > 0:
178 cs,addr = s.accept()
179 self.__clientlist__.append(cs)
180 self.__inconnected__= True
181 else:
182 bytrx = s.recv(2)
183 if bytrx:
184 return (socket.ntohs((bytrx[1] << 8) | bytrx[0]))
185 else:
186 self.__clientlist__.remove(s)
187 s.close()
188 self.__inconnected__= False
189 return None
190#
191# send a IL frame to the virtual loop
192#
193 def write(self,frame):
194 bRetry = True
195 b=bytearray(2)
196 f=socket.htons(frame)
197 b[0]= f & 0xFF
198 b[1]= f >> 8
199 while bRetry:
200 if self.isConnected():
201 try:
202 self.__outsocket__.send(b)
203 break
204 except ConnectionError:
205 self.__outsocket__.shutdown(socket.SHUT_WR)
206 self.__outsocket__.close()
207 self.__outsocket__= None
208 self.__outconnected__ = False
209 else:
210 bRetry = self.openclient()