def do_GET(self): self.connection.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) global dsp_plugin, clients_mutex, clients, avatar_ctime, sw_version, receiver_failed rootdir = 'htdocs' self.path = self.path.replace("..", "") path_temp_parts = self.path.split("?") self.path = path_temp_parts[0] request_param = path_temp_parts[1] if ( len(path_temp_parts) > 1) else "" access_log("GET " + self.path + " from " + self.client_address[0]) try: if self.path == "/": self.path = "/index.wrx" # there's even another cool tip at http://stackoverflow.com/questions/4419650/how-to-implement-timeout-in-basehttpserver-basehttprequesthandler-python #if self.path[:5]=="/lock": cma("do_GET /lock/") # to test mutex_watchdog_thread. Do not uncomment in production environment! if self.path[:4] == "/ws/": if receiver_failed: self.send_error(500, "Internal server error") try: # ========= WebSocket handshake ========= ws_success = True try: rxws.handshake(self) cma("do_GET /ws/") client_i = get_client_by_id(self.path[4:], False) myclient = clients[client_i] except rxws.WebSocketException: ws_success = False except ClientNotFoundException: ws_success = False finally: if clients_mutex.locked(): cmr() if not ws_success: self.send_error(400, 'Bad request.') return # ========= Client handshake ========= if myclient.ws_started: print "[openwebrx-httpd] error: second WS connection with the same client id, throwing it." self.send_error( 400, 'Bad request.') #client already started return rxws.send(self, "CLIENT DE SERVER openwebrx.py") client_ans = rxws.recv(self, True) if client_ans[:16] != "SERVER DE CLIENT": rxws.send("ERR Bad answer.") return myclient.ws_started = True #send default parameters rxws.send( self, "MSG center_freq={0} bandwidth={1} fft_size={2} fft_fps={3} audio_compression={4} fft_compression={5} max_clients={6} setup" .format(str(cfg.shown_center_freq), str(cfg.samp_rate), cfg.fft_size, cfg.fft_fps, cfg.audio_compression, cfg.fft_compression, cfg.max_clients)) # ========= Initialize DSP ========= dsp = getattr(plugins.dsp, cfg.dsp_plugin).plugin.dsp_plugin() dsp_initialized = False dsp.set_audio_compression(cfg.audio_compression) dsp.set_format_conversion(cfg.format_conversion) dsp.set_offset_freq(0) dsp.set_bpf(-4000, 4000) dsp.nc_port = cfg.iq_server_port apply_csdr_cfg_to_dsp(dsp) myclient.dsp = dsp access_log("Started streaming to client: " + self.client_address[0] + "#" + myclient.id + " (users now: " + str(len(clients)) + ")") myclient.loopstat = 0 while True: if myclient.closed[0]: print "[openwebrx-httpd:ws] client closed by other thread" break # ========= send audio ========= if dsp_initialized: myclient.loopstat = 10 temp_audio_data = dsp.read(256) myclient.loopstat = 11 rxws.send(self, temp_audio_data, "AUD ") # ========= send spectrum ========= while not myclient.spectrum_queue.empty(): myclient.loopstat = 20 spectrum_data = myclient.spectrum_queue.get() #spectrum_data_mid=len(spectrum_data[0])/2 #rxws.send(self, spectrum_data[0][spectrum_data_mid:]+spectrum_data[0][:spectrum_data_mid], "FFT ") # (it seems GNU Radio exchanges the first and second part of the FFT output, we correct it) myclient.loopstat = 21 rxws.send(self, spectrum_data[0], "FFT ") # ========= send smeter_level ========= smeter_level = None while True: try: myclient.loopstat = 30 smeter_level = dsp.get_smeter_level() if smeter_level == None: break except: break if smeter_level != None: myclient.loopstat = 31 rxws.send(self, "MSG s={0}".format(smeter_level)) # ========= send bcastmsg ========= if myclient.bcastmsg != "": myclient.loopstat = 40 rxws.send(self, myclient.bcastmsg) myclient.bcastmsg = "" # ========= process commands ========= while True: myclient.loopstat = 50 rdata = rxws.recv(self, False) if not rdata: break #try: elif rdata[:3] == "SET": print "[openwebrx-httpd:ws,%d] command: %s" % ( client_i, rdata) pairs = rdata[4:].split(" ") bpf_set = False new_bpf = dsp.get_bpf() filter_limit = dsp.get_output_rate() / 2 for pair in pairs: param_name, param_value = pair.split("=") if param_name == "low_cut" and -filter_limit <= float( param_value) <= filter_limit: bpf_set = True new_bpf[0] = int(param_value) elif param_name == "high_cut" and -filter_limit <= float( param_value) <= filter_limit: bpf_set = True new_bpf[1] = int(param_value) elif param_name == "offset_freq" and -cfg.samp_rate / 2 <= float( param_value) <= cfg.samp_rate / 2: myclient.loopstat = 510 dsp.set_offset_freq(int(param_value)) elif param_name == "squelch_level" and float( param_value) >= 0: myclient.loopstat = 520 dsp.set_squelch_level( float(param_value)) elif param_name == "mod": if (dsp.get_demodulator() != param_value): myclient.loopstat = 530 if dsp_initialized: dsp.stop() dsp.set_demodulator(param_value) if dsp_initialized: dsp.start() elif param_name == "output_rate": if not dsp_initialized: myclient.loopstat = 540 dsp.set_output_rate( int(param_value)) myclient.loopstat = 541 dsp.set_samp_rate(cfg.samp_rate) elif param_name == "action" and param_value == "start": if not dsp_initialized: myclient.loopstat = 550 dsp.start() dsp_initialized = True else: print "[openwebrx-httpd:ws] invalid parameter" if bpf_set: myclient.loopstat = 560 dsp.set_bpf(*new_bpf) #code.interact(local=locals()) except: exc_type, exc_value, exc_traceback = sys.exc_info() if exc_value[0] == 32: #"broken pipe", client disconnected pass elif exc_value[ 0] == 11: #"resource unavailable" on recv, client disconnected pass else: print "[openwebrx-httpd] error in /ws/ handler: ", exc_type, exc_value traceback.print_tb(exc_traceback) #stop dsp for the disconnected client try: dsp.stop() del dsp except: print "[openwebrx-httpd] error in dsp.stop()" #delete disconnected client try: cma("do_GET /ws/ delete disconnected") id_to_close = get_client_by_id(myclient.id, False) close_client(id_to_close, False) except: exc_type, exc_value, exc_traceback = sys.exc_info() print "[openwebrx-httpd] client cannot be closed: ", exc_type, exc_value traceback.print_tb(exc_traceback) finally: cmr() myclient.loopstat = 1000 return elif self.path in ("/status", "/status/"): #self.send_header('Content-type','text/plain') getbands = lambda: str( int(cfg.shown_center_freq - cfg.samp_rate / 2) ) + "-" + str(int(cfg.shown_center_freq + cfg.samp_rate / 2)) self.wfile.write( "status=" + ("inactive" if receiver_failed else "active") + "\nname=" + cfg.receiver_name + "\nsdr_hw=" + cfg.receiver_device + "\nop_email=" + cfg.receiver_admin + "\nbands=" + getbands() + "\nusers=" + str(len(clients)) + "\nusers_max=" + str(cfg.max_clients) + "\navatar_ctime=" + avatar_ctime + "\ngps=" + str(cfg.receiver_gps) + "\nasl=" + str(cfg.receiver_asl) + "\nloc=" + cfg.receiver_location + "\nsw_version=" + sw_version + "\nantenna=" + cfg.receiver_ant + "\n") print "[openwebrx-httpd] GET /status/ from", self.client_address[ 0] else: f = open(rootdir + self.path) data = f.read() extension = self.path[(len(self.path) - 4):len(self.path)] extension = extension[2:] if extension[ 1] == '.' else extension[1:] checkresult = check_server() if extension == "wrx" and (checkresult or receiver_failed): self.send_302("inactive.html") return anyStringsPresentInUserAgent = lambda a: reduce( lambda x, y: x or y, map(lambda b: self.headers['user-agent'].count(b), a), False) if extension == "wrx" and ( (not anyStringsPresentInUserAgent( ("Chrome", "Firefox", "Googlebot", "iPhone", "iPad", "iPod"))) if 'user-agent' in self.headers.keys() else True) and (not request_param.count("unsupported")): self.send_302("upgrade.html") return if extension == "wrx": cleanup_clients(False) if cfg.max_clients <= len(clients): self.send_302("retry.html") return self.send_response(200) if (("wrx", "html", "htm").count(extension)): self.send_header('Content-type', 'text/html') elif (extension == "js"): self.send_header('Content-type', 'text/javascript') elif (extension == "css"): self.send_header('Content-type', 'text/css') self.end_headers() if extension == "wrx": replace_dictionary = ( ("%[RX_PHOTO_DESC]", cfg.photo_desc), ("%[CLIENT_ID]", generate_client_id(self.client_address[0])) if "%[CLIENT_ID]" in data else "", ("%[WS_URL]", "ws://" + cfg.server_hostname + ":" + str(cfg.web_port) + "/ws/"), ("%[RX_TITLE]", cfg.receiver_name), ("%[RX_LOC]", cfg.receiver_location), ("%[RX_QRA]", cfg.receiver_qra), ("%[RX_ASL]", str(cfg.receiver_asl)), ("%[RX_GPS]", str(cfg.receiver_gps[0]) + "," + str(cfg.receiver_gps[1])), ("%[RX_PHOTO_HEIGHT]", str(cfg.photo_height)), ("%[RX_PHOTO_TITLE]", cfg.photo_title), ("%[RX_ADMIN]", cfg.receiver_admin), ("%[RX_ANT]", cfg.receiver_ant), ("%[RX_DEVICE]", cfg.receiver_device), ("%[AUDIO_BUFSIZE]", str(cfg.client_audio_buffer_size)), ("%[START_OFFSET_FREQ]", str(cfg.start_freq - cfg.center_freq)), ("%[START_MOD]", cfg.start_mod), ("%[WATERFALL_COLORS]", cfg.waterfall_colors), ("%[WATERFALL_MIN_LEVEL]", str(cfg.waterfall_min_level)), ("%[WATERFALL_MAX_LEVEL]", str(cfg.waterfall_max_level))) for rule in replace_dictionary: while data.find(rule[0]) != -1: data = data.replace(rule[0], rule[1]) self.wfile.write(data) f.close() return except IOError: self.send_error(404, 'Invalid path.') except: exc_type, exc_value, exc_traceback = sys.exc_info() print "[openwebrx-httpd] error (@outside):", exc_type, exc_value traceback.print_tb(exc_traceback)
def do_GET(self): self.connection.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) global dsp_plugin, clients_mutex, clients, avatar_ctime, sw_version, receiver_failed rootdir = 'htdocs' self.path=self.path.replace("..","") path_temp_parts=self.path.split("?") self.path=path_temp_parts[0] request_param=path_temp_parts[1] if(len(path_temp_parts)>1) else "" access_log("GET "+self.path+" from "+self.client_address[0]) try: if self.path=="/": self.path="/index.wrx" # there's even another cool tip at http://stackoverflow.com/questions/4419650/how-to-implement-timeout-in-basehttpserver-basehttprequesthandler-python #if self.path[:5]=="/lock": cma("do_GET /lock/") # to test mutex_watchdog_thread. Do not uncomment in production environment! if self.path[:4]=="/ws/": if receiver_failed: self.send_error(500,"Internal server error") try: # ========= WebSocket handshake ========= ws_success=True try: rxws.handshake(self) cma("do_GET /ws/") client_i=get_client_by_id(self.path[4:], False) myclient=clients[client_i] except rxws.WebSocketException: ws_success=False except ClientNotFoundException: ws_success=False finally: if clients_mutex.locked(): cmr() if not ws_success: self.send_error(400, 'Bad request.') return # ========= Client handshake ========= if myclient.ws_started: print "[openwebrx-httpd] error: second WS connection with the same client id, throwing it." self.send_error(400, 'Bad request.') #client already started return rxws.send(self, "CLIENT DE SERVER openwebrx.py") client_ans=rxws.recv(self, True) if client_ans[:16]!="SERVER DE CLIENT": rxws.send("ERR Bad answer.") return myclient.ws_started=True #send default parameters rxws.send(self, "MSG center_freq={0} bandwidth={1} fft_size={2} fft_fps={3} audio_compression={4} fft_compression={5} max_clients={6} setup".format(str(cfg.shown_center_freq),str(cfg.samp_rate),cfg.fft_size,cfg.fft_fps,cfg.audio_compression,cfg.fft_compression,cfg.max_clients)) # ========= Initialize DSP ========= dsp=getattr(plugins.dsp,cfg.dsp_plugin).plugin.dsp_plugin() dsp_initialized=False dsp.set_audio_compression(cfg.audio_compression) dsp.set_format_conversion(cfg.format_conversion) dsp.set_offset_freq(0) dsp.set_bpf(-4000,4000) dsp.nc_port=cfg.iq_server_port apply_csdr_cfg_to_dsp(dsp) myclient.dsp=dsp access_log("Started streaming to client: "+self.client_address[0]+"#"+myclient.id+" (users now: "+str(len(clients))+")") while True: if myclient.closed[0]: print "[openwebrx-httpd:ws] client closed by other thread" break # ========= send audio ========= if dsp_initialized: temp_audio_data=dsp.read(256) rxws.send(self, temp_audio_data, "AUD ") # ========= send spectrum ========= while not myclient.spectrum_queue.empty(): spectrum_data=myclient.spectrum_queue.get() #spectrum_data_mid=len(spectrum_data[0])/2 #rxws.send(self, spectrum_data[0][spectrum_data_mid:]+spectrum_data[0][:spectrum_data_mid], "FFT ") # (it seems GNU Radio exchanges the first and second part of the FFT output, we correct it) rxws.send(self, spectrum_data[0],"FFT ") # ========= send smeter_level ========= smeter_level=None while True: try: smeter_level=dsp.get_smeter_level() if smeter_level == None: break except: break if smeter_level!=None: rxws.send(self, "MSG s={0}".format(smeter_level)) # ========= send bcastmsg ========= if myclient.bcastmsg!="": rxws.send(self,myclient.bcastmsg) myclient.bcastmsg="" # ========= process commands ========= while True: rdata=rxws.recv(self, False) if not rdata: break #try: elif rdata[:3]=="SET": print "[openwebrx-httpd:ws,%d] command: %s"%(client_i,rdata) pairs=rdata[4:].split(" ") bpf_set=False new_bpf=dsp.get_bpf() filter_limit=dsp.get_output_rate()/2 for pair in pairs: param_name, param_value = pair.split("=") if param_name == "low_cut" and -filter_limit <= float(param_value) <= filter_limit: bpf_set=True new_bpf[0]=int(param_value) elif param_name == "high_cut" and -filter_limit <= float(param_value) <= filter_limit: bpf_set=True new_bpf[1]=int(param_value) elif param_name == "offset_freq" and -cfg.samp_rate/2 <= float(param_value) <= cfg.samp_rate/2: dsp.set_offset_freq(int(param_value)) elif param_name == "squelch_level" and float(param_value) >= 0: dsp.set_squelch_level(float(param_value)) elif param_name=="mod": if (dsp.get_demodulator()!=param_value): if dsp_initialized: dsp.stop() dsp.set_demodulator(param_value) if dsp_initialized: dsp.start() elif param_name == "output_rate": if not dsp_initialized: dsp.set_output_rate(int(param_value)) dsp.set_samp_rate(cfg.samp_rate) elif param_name=="action" and param_value=="start": if not dsp_initialized: dsp.start() dsp_initialized=True else: print "[openwebrx-httpd:ws] invalid parameter" if bpf_set: dsp.set_bpf(*new_bpf) #code.interact(local=locals()) except: exc_type, exc_value, exc_traceback = sys.exc_info() if exc_value[0]==32: #"broken pipe", client disconnected pass elif exc_value[0]==11: #"resource unavailable" on recv, client disconnected pass else: print "[openwebrx-httpd] error in /ws/ handler: ",exc_type,exc_value traceback.print_tb(exc_traceback) #stop dsp for the disconnected client try: dsp.stop() del dsp except: print "[openwebrx-httpd] error in dsp.stop()" #delete disconnected client try: cma("do_GET /ws/ delete disconnected") id_to_close=get_client_by_id(myclient.id,False) close_client(id_to_close,False) except: exc_type, exc_value, exc_traceback = sys.exc_info() print "[openwebrx-httpd] client cannot be closed: ",exc_type,exc_value traceback.print_tb(exc_traceback) finally: cmr() return elif self.path in ("/status", "/status/"): #self.send_header('Content-type','text/plain') getbands=lambda: str(int(cfg.shown_center_freq-cfg.samp_rate/2))+"-"+str(int(cfg.shown_center_freq+cfg.samp_rate/2)) self.wfile.write("status="+("inactive" if receiver_failed else "active")+"\nname="+cfg.receiver_name+"\nsdr_hw="+cfg.receiver_device+"\nop_email="+cfg.receiver_admin+"\nbands="+getbands()+"\nusers="+str(len(clients))+"\nusers_max="+str(cfg.max_clients)+"\navatar_ctime="+avatar_ctime+"\ngps="+str(cfg.receiver_gps)+"\nasl="+str(cfg.receiver_asl)+"\nloc="+cfg.receiver_location+"\nsw_version="+sw_version+"\nantenna="+cfg.receiver_ant+"\n") print "[openwebrx-httpd] GET /status/ from",self.client_address[0] else: f=open(rootdir+self.path) data=f.read() extension=self.path[(len(self.path)-4):len(self.path)] extension=extension[2:] if extension[1]=='.' else extension[1:] checkresult=check_server() if extension == "wrx" and (checkresult or receiver_failed): self.send_302("inactive.html") return anyStringsPresentInUserAgent=lambda a: reduce(lambda x,y:x or y, map(lambda b:self.headers['user-agent'].count(b), a), False) if extension == "wrx" and ( (not anyStringsPresentInUserAgent(("Chrome","Firefox","Googlebot","iPhone","iPad","iPod"))) if 'user-agent' in self.headers.keys() else True ) and (not request_param.count("unsupported")): self.send_302("upgrade.html") return if extension == "wrx" and len(clients)==0 and powerstate==0: poweron() self.send_302("poweron.html") return if extension == "wrx" and cfg.max_clients<=len(clients): self.send_302("retry.html") return if extension == "wrx": cleanup_clients() if extension == "wrx" and cfg.max_clients<=len(clients): self.send_response(302) #backported max_clients fix self.send_header('Content-type','text/html') self.send_header("Location", "http://{0}:{1}/retry.html".format(cfg.server_hostname,cfg.web_port)) self.end_headers() self.wfile.write("<html><body><h1>Object moved</h1>Please <a href=\"/retry.html\">click here</a> to continue.</body></html>") return self.send_response(200) if(("wrx","html","htm").count(extension)): self.send_header('Content-type','text/html') elif(extension=="js"): self.send_header('Content-type','text/javascript') elif(extension=="css"): self.send_header('Content-type','text/css') self.end_headers() if extension == "wrx": replace_dictionary=( ("%[RX_PHOTO_DESC]",cfg.photo_desc), ("%[CLIENT_ID]", generate_client_id(self.client_address[0])) if "%[CLIENT_ID]" in data else "", ("%[WS_URL]","ws://"+cfg.server_hostname+":"+str(cfg.web_port)+"/ws/"), ("%[RX_TITLE]",cfg.receiver_name), ("%[RX_LOC]",cfg.receiver_location), ("%[RX_QRA]",cfg.receiver_qra), ("%[RX_ASL]",str(cfg.receiver_asl)), ("%[RX_GPS]",str(cfg.receiver_gps[0])+","+str(cfg.receiver_gps[1])), ("%[RX_PHOTO_HEIGHT]",str(cfg.photo_height)),("%[RX_PHOTO_TITLE]",cfg.photo_title), ("%[RX_ADMIN]",cfg.receiver_admin), ("%[RX_ANT]",cfg.receiver_ant), ("%[RX_DEVICE]",cfg.receiver_device), ("%[AUDIO_BUFSIZE]",str(cfg.client_audio_buffer_size)), ("%[START_OFFSET_FREQ]",str(cfg.start_freq-cfg.center_freq)), ("%[START_MOD]",cfg.start_mod), ("%[WATERFALL_COLORS]",cfg.waterfall_colors), ("%[WATERFALL_MIN_LEVEL]",str(cfg.waterfall_min_level)), ("%[WATERFALL_MAX_LEVEL]",str(cfg.waterfall_max_level)) ) for rule in replace_dictionary: while data.find(rule[0])!=-1: data=data.replace(rule[0],rule[1]) self.wfile.write(data) f.close() return except IOError: self.send_error(404, 'Invalid path.') except: exc_type, exc_value, exc_traceback = sys.exc_info() print "[openwebrx-httpd] error (@outside):", exc_type, exc_value traceback.print_tb(exc_traceback)