1818##
1919
2020from abc import ABC , abstractmethod
21- import urllib .error
22- from . import jsonrpc_helper
23- import socket
24-
25- import urllib .request
26- import urllib .parse
27- import ssl
28-
29- import os
30- import time
31- import errno
3221
3322class Connection (ABC ):
3423 @abstractmethod
@@ -42,167 +31,3 @@ def execute(self, method: str, params: dict):
4231 @abstractmethod
4332 def valid (self ):
4433 pass
45-
46- class Datagram (Connection ):
47- def __init__ (self , ** kwargs ):
48- if "ip" not in kwargs :
49- raise ValueError ("ip is required for Datagram connector" )
50-
51- if "port" not in kwargs :
52- raise ValueError ("port is required for Datagram connector" )
53-
54- self .ip = kwargs ["ip" ]
55- self .port = kwargs ["port" ]
56-
57- def execute (self , method : str , params : dict ):
58- jsoncmd = jsonrpc_helper .get_command (method , params )
59- udp_socket = socket .socket (socket .AF_INET , socket .SOCK_DGRAM )
60- try :
61- udp_socket .sendto (jsoncmd .encode (), (self .ip , self .port ))
62- udp_socket .settimeout (5.0 )
63- reply = udp_socket .recv (1024 )
64- except Exception as e :
65- raise jsonrpc_helper .JSONRPCException (e )
66- finally :
67- udp_socket .close ()
68- return jsonrpc_helper .get_reply (reply )
69-
70- def valid (self ):
71- return (True , None )
72-
73- class HTTP (Connection ):
74- def __init__ (self , ** kwargs ):
75- if "url" not in kwargs :
76- raise ValueError ("url is required for HTTP connector" )
77-
78- self .url = kwargs ["url" ]
79-
80- def execute (self , method : str , params : dict ):
81- jsoncmd = jsonrpc_helper .get_command (method , params )
82- headers = {
83- "Content-Type" : "application/json"
84- }
85- request = urllib .request .Request (self .url , jsoncmd .encode (), headers )
86- url_parsed = urllib .parse .urlparse (self .url )
87- try :
88- if url_parsed .scheme == "https" :
89- reply = urllib .request .urlopen (request , context = ssl ._create_unverified_context ()).read ().decode ()
90- else :
91- reply = urllib .request .urlopen (request ).read ().decode ()
92- except urllib .error .HTTPError as e :
93- raise jsonrpc_helper .JSONRPCException (str (e ))
94- return jsonrpc_helper .get_reply (reply )
95-
96- def valid (self ):
97- try :
98- url_parsed = urllib .parse .urlparse (self .url )
99- if not url_parsed .port :
100- if url_parsed .scheme == "http" :
101- url_parsed .port = 80
102- else :
103- url_parsed .port = 443
104- sock = socket .socket ()
105- sock .connect ((url_parsed .hostname , url_parsed .port ))
106- sock .close ()
107- return (True , None )
108- except Exception as e :
109- msg = "Could not connect to {} ({})" .format (self .url , e )
110- return (False , [msg , "Is OpenSIPS running?" ])
111-
112- class FIFO (Connection ):
113- REPLY_FIFO_FILE_TEMPLATE = "opensips_fifo_reply_{}_{}" \
114-
115- def __init__ (self , ** kwargs ):
116- if "fifo_file" not in kwargs :
117- raise ValueError ("fifo_file is required for FIFO connector" )
118- if "fifo_file_fallback" not in kwargs :
119- raise ValueError ("fifo_file_fallback is required for FIFO connector" )
120- if "fifo_reply_dir" not in kwargs :
121- raise ValueError ("fifo_reply_dir is required for FIFO connector" )
122-
123- self .fifo_file = kwargs ["fifo_file" ]
124- self .fifo_file_fallback = kwargs ["fifo_file_fallback" ]
125- self .fifo_reply_dir = kwargs ["fifo_reply_dir" ]
126-
127- def execute (self , method : str , params : dict ):
128- jsoncmd = jsonrpc_helper .get_command (method , params )
129-
130- reply_fifo_file_name = self .REPLY_FIFO_FILE_TEMPLATE .format (os .getpid (), str (time .time ()).replace ("." , "_" ))
131- reply_fifo_file_path = os .path .join (self .fifo_reply_dir , reply_fifo_file_name )
132-
133- try :
134- os .unlink (reply_fifo_file_path )
135- except OSError as e :
136- if os .path .exists (reply_fifo_file_path ):
137- raise jsonrpc_helper .JSONRPCException (
138- "Could not remove old reply FIFO file {}: {}"
139- .format (reply_fifo_file_path , e ))
140-
141- try :
142- os .mkfifo (reply_fifo_file_path )
143- os .chmod (reply_fifo_file_path , 0o666 )
144- except OSError as e :
145- raise jsonrpc_helper .JSONRPCException (
146- "Could not create reply FIFO file {}: {}"
147- .format (reply_fifo_file_path , e ))
148-
149- if not os .path .exists (self .fifo_file ):
150- raise jsonrpc_helper .JSONRPCException (
151- "FIFO file {} does not exist"
152- .format (self .fifo_file ))
153-
154- fifocmd = ":{}:{}" .format (reply_fifo_file_path , jsoncmd )
155- try :
156- with open (self .fifo_file , "w" ) as fifo :
157- fifo .write (fifocmd )
158- except Exception as e :
159- raise jsonrpc_helper .JSONRPCException (
160- "Could not access FIFO file {}: {}"
161- .format (self .fifo_file , e ))
162-
163- reply = None
164- try :
165- with open (reply_fifo_file_path , "r" ) as reply_fifo :
166- reply = reply_fifo .readline ()
167- except KeyboardInterrupt :
168- exit ()
169- finally :
170- os .unlink (reply_fifo_file_path )
171-
172- return jsonrpc_helper .get_reply (reply )
173-
174- def valid (self ):
175- opensips_fifo = self .fifo_file
176- if not os .path .exists (opensips_fifo ):
177- opensips_fifo = self .fifo_file_fallback
178- if not os .path .exists (opensips_fifo ):
179- return (False , ["FIFO file {} does not exist, nor does fallback file {}"
180- .format (self .fifo_file , self .fifo_file_fallback ), "Is OpenSIPS running?" ])
181- try :
182- open (opensips_fifo , "w" ).close ()
183- except OSError as e :
184- extra = []
185- if e .errno == errno .EACCES :
186- sticky = self .get_sticky (os .path .dirname (opensips_fifo ))
187- if sticky :
188- extra = ["starting with Linux kernel 4.19, processes can " +
189- "no longer read from FIFO files " ,
190- "that are saved in directories with sticky " +
191- "bits (such as {})" .format (sticky ),
192- "and are not owned by the same user the " +
193- "process runs with. " ,
194- "To fix this, either store the file in a non-sticky " +
195- "bit directory (such as /var/run/opensips), " ,
196- "or disable fifo file protection using " +
197- "'sysctl fs.protected_fifos=0' (NOT RECOMMENDED)" ]
198- msg = "Could not access FIFO file {}: {}" .format (opensips_fifo , e )
199- return (False , [msg ] + extra )
200- self .fifo_file = opensips_fifo
201- return (True , None )
202-
203- def get_sticky (self , path ):
204- if path == "/" :
205- return None
206- if os .stat (path ).st_mode & 0o1000 == 0o1000 :
207- return path
208- return self .get_sticky (os .path .split (path )[0 ])
0 commit comments