Ejemplo n.º 1
0
    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)
Ejemplo n.º 2
0
	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)