예제 #1
0
func gethHttpHandler(codec codec.Codec, a shared.EthereumApi) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
		w.Header().Set("Content-Type", "application/json")

		// Limit request size to resist DoS
		if req.ContentLength > maxHttpSizeReqLength {
			err := fmt.Errorf("Request too large")
			response := shared.NewRpcErrorResponse(-1, shared.JsonRpcVersion, -32700, err)
			httpSend(w, &response)
			return
		}

		defer req.Body.Close()
		payload, err := ioutil.ReadAll(req.Body)
		if err != nil {
			err := fmt.Errorf("Could not read request body")
			response := shared.NewRpcErrorResponse(-1, shared.JsonRpcVersion, -32700, err)
			httpSend(w, &response)
			return
		}

		c := codec.New(nil)
		var rpcReq shared.Request
		if err = c.Decode(payload, &rpcReq); err == nil {
			reply, err := a.Execute(&rpcReq)
			res := shared.NewRpcResponse(rpcReq.Id, rpcReq.Jsonrpc, reply, err)
			httpSend(w, &res)
			return
		}

		var reqBatch []shared.Request
		if err = c.Decode(payload, &reqBatch); err == nil {
			resBatch := make([]*interface{}, len(reqBatch))
			resCount := 0

			for i, rpcReq := range reqBatch {
				reply, err := a.Execute(&rpcReq)
				if rpcReq.Id != nil { // this leaves nil entries in the response batch for later removal
					resBatch[i] = shared.NewRpcResponse(rpcReq.Id, rpcReq.Jsonrpc, reply, err)
					resCount += 1
				}
			}

			// make response omitting nil entries
			resBatch = resBatch[:resCount]
			httpSend(w, resBatch)
			return
		}

		// invalid request
		err = fmt.Errorf("Could not decode request")
		res := shared.NewRpcErrorResponse(-1, shared.JsonRpcVersion, -32600, err)
		httpSend(w, res)
	})
}
예제 #2
0
func startIpc(cfg IpcConfig, codec codec.Codec, api shared.EthereumApi) error {
	os.Remove(cfg.Endpoint) // in case it still exists from a previous run

	l, err := Listen(cfg.Endpoint)
	if err != nil {
		return err
	}
	os.Chmod(cfg.Endpoint, 0600)

	go func() {
		for {
			conn, err := l.Accept()
			if err != nil {
				glog.V(logger.Error).Infof("Error accepting ipc connection - %v\n", err)
				continue
			}

			go func(conn net.Conn) {
				codec := codec.New(conn)

				for {
					req, err := codec.ReadRequest()
					if err == io.EOF {
						codec.Close()
						return
					} else if err != nil {
						glog.V(logger.Error).Infof("IPC recv err - %v\n", err)
						codec.Close()
						return
					}

					var rpcResponse interface{}
					res, err := api.Execute(req)

					rpcResponse = shared.NewRpcResponse(req.Id, req.Jsonrpc, res, err)
					err = codec.WriteResponse(rpcResponse)
					if err != nil {
						glog.V(logger.Error).Infof("IPC send err - %v\n", err)
						codec.Close()
						return
					}
				}
			}(conn)
		}
	}()

	glog.V(logger.Info).Infof("IPC service started (%s)\n", cfg.Endpoint)

	return nil
}
예제 #3
0
func handle(id int, conn net.Conn, api shared.EthereumApi, c codec.Codec) {
	codec := c.New(conn)

	defer func() {
		if r := recover(); r != nil {
			glog.Errorf("panic: %v\n", r)
		}
		codec.Close()
	}()

	for {
		requests, isBatch, err := codec.ReadRequest()
		if err == io.EOF {
			return
		} else if err != nil {
			glog.V(logger.Debug).Infof("Closed IPC Conn %06d recv err - %v\n", id, err)
			return
		}

		if isBatch {
			responses := make([]*interface{}, len(requests))
			responseCount := 0
			for _, req := range requests {
				res, err := api.Execute(req)
				if req.Id != nil {
					rpcResponse := shared.NewRpcResponse(req.Id, req.Jsonrpc, res, err)
					responses[responseCount] = rpcResponse
					responseCount += 1
				}
			}

			err = codec.WriteResponse(responses[:responseCount])
			if err != nil {
				glog.V(logger.Debug).Infof("Closed IPC Conn %06d send err - %v\n", id, err)
				return
			}
		} else {
			var rpcResponse interface{}
			res, err := api.Execute(requests[0])

			rpcResponse = shared.NewRpcResponse(requests[0].Id, requests[0].Jsonrpc, res, err)
			err = codec.WriteResponse(rpcResponse)
			if err != nil {
				glog.V(logger.Debug).Infof("Closed IPC Conn %06d send err - %v\n", id, err)
				return
			}
		}
	}
}