コード例 #1
0
ファイル: channel.go プロジェクト: yinqiwen/gsnova
func (rc *RemoteChannel) Request(ev event.Event) (event.Event, error) {
	var buf bytes.Buffer
	auth := NewAuthEvent(rc.SecureTransport)
	auth.Index = int64(rc.Index)
	if auth.EncryptMethod == event.Chacha20Encrypter {
		auth.EncryptMethod = event.Salsa20Encrypter
	}
	ctx := randCryptoCtx()
	ctx.Method = auth.EncryptMethod
	auth.IV = ctx.EncryptIV
	event.EncryptEvent(&buf, auth, &ctx)
	event.EncryptEvent(&buf, ev, &ctx)
	//event.EncodeEvent(&buf, ev)
	res, err := rc.C.Request(buf.Bytes())
	if nil != err {
		return nil, err
	}
	rbuf := bytes.NewBuffer(res)
	var rev event.Event
	err, rev = event.DecryptEvent(rbuf, &ctx)
	if nil != err {
		return nil, err
	}
	return rev, nil
}
コード例 #2
0
ファイル: http.go プロジェクト: yinqiwen/gsnova
// handleWebsocket connection. Update to
func httpInvoke(w http.ResponseWriter, r *http.Request) {
	ctx := remote.NewConnContext()
	writeEvents := func(evs []event.Event, buf *bytes.Buffer) error {
		if len(evs) > 0 {
			buf.Reset()
			for _, ev := range evs {
				if nil != ev {
					event.EncryptEvent(buf, ev, &ctx.CryptoContext)
				}
			}
			if buf.Len() > 0 {
				_, err := w.Write(buf.Bytes())
				if nil == err {
					w.(http.Flusher).Flush()
				}
				return err
			}
		}
		return nil
	}
	//reqbuf := readRequestBuffer(r)
	var wbuf bytes.Buffer
	ress, err := handleRequestBody(r, ctx)
	if nil != err {
		log.Printf("[ERROR]connection %s:%d error:%v with path:%s ", ctx.User, ctx.ConnIndex, err, r.URL.Path)
		w.WriteHeader(400)
	} else {
		w.WriteHeader(200)
		if strings.HasSuffix(r.URL.Path, "pull") {
			begin := time.Now()
			period, _ := strconv.Atoi(r.Header.Get("X-PullPeriod"))
			if period <= 0 {
				period = 15
			}
			writeEvents(ress, &wbuf)
			queue := remote.GetEventQueue(ctx.ConnId, true)
			defer remote.ReleaseEventQueue(queue)
			for {
				if time.Now().After(begin.Add(time.Duration(period) * time.Second)) {
					log.Printf("Stop puller after %ds for conn:%d", period, ctx.ConnIndex)
					break
				}
				evs, err := queue.PeekMulti(2, 1*time.Millisecond, false)
				if nil != err {
					continue
				}
				err = writeEvents(evs, &wbuf)
				if nil != err {
					log.Printf("HTTP write error:%v", err)
					return
				}
				queue.DiscardPeeks(false)
			}
		}
	}
}
コード例 #3
0
ファイル: web.go プロジェクト: yinqiwen/gsnova
func httpInvoke(w http.ResponseWriter, r *http.Request) {
	b := make([]byte, r.ContentLength)
	r.Body.Read(b)
	buf := bytes.NewBuffer(b)
	ctx := appengine.NewContext(r)

	var cryptoContext event.CryptoContext
	err, ev := event.DecryptEvent(buf, &cryptoContext)
	if nil != err {
		ctx.Errorf("Decode auth event failed:%v", err)
		return
	}
	//var iv uint64
	if auth, ok := ev.(*event.AuthEvent); ok {
		if !remote.ServerConf.VerifyUser(auth.User) {
			return
		}
		cryptoContext.DecryptIV = auth.IV
		cryptoContext.EncryptIV = auth.IV
		cryptoContext.Method = auth.EncryptMethod
	} else {
		ctx.Errorf("Expected auth event, but got %T", ev)
		return
	}

	err, ev = event.DecryptEvent(buf, &cryptoContext)
	if nil != err {
		ctx.Errorf("Decode http request event failed:%v", err)
		return
	}
	if req, ok := ev.(*event.HTTPRequestEvent); ok {
		res := fetch(ctx, req)
		var resbuf bytes.Buffer
		event.EncryptEvent(&resbuf, res, &cryptoContext)
		headers := w.Header()
		headers.Add("Content-Type", "application/octet-stream")
		headers.Add("Content-Length", strconv.Itoa(resbuf.Len()))
		w.WriteHeader(http.StatusOK)
		w.Write(resbuf.Bytes())
	} else {
		ctx.Errorf("Expected http request event, but got %T", ev)
		return
	}
}
コード例 #4
0
ファイル: http.go プロジェクト: yinqiwen/gsnova
func (hc *httpChannel) chunkPush() {
	u := hc.pushurl
	var ticker *time.Ticker
	closePush := func() {
		//ticker := time.NewTicker(10 * time.Second)
		select {
		case <-ticker.C:
			if hc.pushing {
				//force push channel close
				hc.chunkChan.offer(nil)
			}
		}
	}

	for {
		if len(hc.chunkChan.chunkChannel) == 0 {
			time.Sleep(10 * time.Millisecond)
			continue
		}
		hc.pushing = true
		req := buildHTTPReq(u, hc.chunkChan)
		req.ContentLength = -1
		wAuth := proxy.NewAuthEvent(u.Scheme == "https")
		wAuth.Index = int64(hc.idx)
		wAuth.IV = hc.cryptoCtx.EncryptIV
		var buf bytes.Buffer
		event.EncryptEvent(&buf, wAuth, &hc.cryptoCtx)
		hc.chunkChan.prepend(buf.Bytes())
		period := hc.getHTTPReconnectPeriod()
		ticker = time.NewTicker(time.Duration(period) * time.Second)
		go closePush()
		log.Printf("[%s:%d] chunk push channel start.", hc.addr, hc.idx)
		response, err := hc.paasClient.Do(req)
		if nil != err || response.StatusCode != 200 {
			log.Printf("Failed to write data to PAAS:%s for reason:%v or res:%v", u.String(), err, response)
		} else {
			log.Printf("[%s:%d] chunk push channel stop.", hc.addr, hc.idx)
		}
		ticker.Stop()
		hc.pushing = false
	}

}
コード例 #5
0
ファイル: http.go プロジェクト: yinqiwen/gsnova
func (hc *httpChannel) pull() error {
	if nil == hc.pullurl {
		u, err := url.Parse(hc.addr)
		if nil != err {
			return err
		}
		u.Path = "/http/pull"
		hc.pullurl = u
	}
	if hc.pulling {
		return nil
	}
	readAuth := proxy.NewAuthEvent(hc.pullurl.Scheme == "https")
	readAuth.Index = int64(hc.idx)
	readAuth.IV = hc.cryptoCtx.EncryptIV
	var buf bytes.Buffer
	event.EncryptEvent(&buf, readAuth, &hc.cryptoCtx)
	hc.pulling = true
	log.Printf("[%s:%d] pull channel start.", hc.addr, hc.idx)
	_, err := hc.postURL(buf.Bytes(), hc.pullurl)
	hc.pulling = false
	return err
}
コード例 #6
0
ファイル: server.go プロジェクト: yinqiwen/gsnova
func serveProxyConn(conn net.Conn, vs *vpsServer) {
	if nil != vs {
		atomic.AddInt32(&vs.aliveConns, 1)
	}
	atomic.AddInt32(&totalConn, 1)
	bufconn := bufio.NewReader(conn)

	deferFunc := func() {
		conn.Close()
		atomic.AddInt32(&totalConn, -1)
		if nil != vs {
			atomic.AddInt32(&vs.aliveConns, -1)
		}
	}
	defer deferFunc()

	ctx := remote.NewConnContext()
	writeEvents := func(evs []event.Event, buf *bytes.Buffer) error {
		if len(evs) > 0 {
			buf.Reset()
			for _, ev := range evs {
				if nil != ev {
					event.EncryptEvent(buf, ev, &ctx.CryptoContext)
				}
			}
			if buf.Len() > 0 {
				conn.SetWriteDeadline(time.Now().Add(15 * time.Second))
				b := buf.Bytes()
				_, err := conn.Write(b)

				return err
			}
		}
		return nil
	}

	var rbuf bytes.Buffer
	var wbuf bytes.Buffer

	writeTaskRunning := false
	connClosed := false
	reader := &helper.BufferChunkReader{bufconn, nil}
	for !connClosed {
		conn.SetReadDeadline(time.Now().Add(60 * time.Second))
		rbuf.Grow(8192)
		rbuf.ReadFrom(reader)
		if nil != reader.Err {
			conn.Close()
			connClosed = true
		}
		ress, err := remote.HandleRequestBuffer(&rbuf, ctx)
		if nil != err {
			if err != event.EBNR {
				log.Printf("[ERROR]connection %s:%d error:%v", ctx.User, ctx.ConnIndex, err)
				conn.Close()
				connClosed = true
				return
			}
		} else {
			writeEvents(ress, &wbuf)
			if !writeTaskRunning && len(ctx.User) > 0 && ctx.ConnIndex >= 0 {
				writeTaskRunning = true
				go func() {
					var lastEventTime time.Time
					queue := remote.GetEventQueue(ctx.ConnId, true)
					for !connClosed {
						evs, err := queue.PeekMulti(10, 1*time.Millisecond, false)
						now := time.Now()
						if ctx.Closing {
							evs = []event.Event{&event.ChannelCloseACKEvent{}}
							if remote.ServerConf.MaxDynamicPort > 0 {
								nvs := selectDynamicVPServer()
								if nil != nvs {
									evs = append(evs, &event.PortUnicastEvent{Port: nvs.port})
								}
							}
						} else {
							if nil != err {
								if remote.GetSessionTableSize() > 0 && lastEventTime.Add(10*time.Second).Before(now) {
									evs = []event.Event{event.NewHeartBeatEvent()}
								} else {
									continue
								}
							}
						}

						err = writeEvents(evs, &wbuf)
						if nil != err {
							log.Printf("TCP write error####:%v %d", err, len(evs))
						} else {
							queue.DiscardPeeks(false)
						}
						if ctx.Closing {
							break
						}
						lastEventTime = now
						if nil != err {
							log.Printf("TCP write error:%v", err)
							conn.Close()
							break
						} else {
							//queue.DiscardPeeks(false)
						}
					}
					remote.ReleaseEventQueue(queue)
				}()
			}
		}
	}
}
コード例 #7
0
ファイル: websocket.go プロジェクト: yinqiwen/gsnova
// handleWebsocket connection. Update to
func websocketInvoke(w http.ResponseWriter, r *http.Request) {
	if r.Method != "GET" {
		http.Error(w, "Method not allowed", 405)
		return
	}

	ws, err := upgrader.Upgrade(w, r, nil)
	if err != nil {
		//log.WithField("err", err).Println("Upgrading to websockets")
		http.Error(w, "Error Upgrading to websockets", 400)
		return
	}
	ctx := remote.NewConnContext()
	writeEvents := func(evs []event.Event, wbuf *bytes.Buffer) error {
		if len(evs) > 0 {
			//var buf bytes.Buffer
			wbuf.Reset()
			for _, ev := range evs {
				if nil != ev {
					event.EncryptEvent(wbuf, ev, &ctx.CryptoContext)
				}
			}
			if wbuf.Len() > 0 {
				return ws.WriteMessage(websocket.BinaryMessage, wbuf.Bytes())
			}
			return nil
		}
		return nil
	}
	//log.Printf("###Recv websocket connection")
	buf := bytes.NewBuffer(nil)
	var wbuf bytes.Buffer
	wsClosed := false
	var queue *remote.ConnEventQueue
	for {
		mt, data, err := ws.ReadMessage()
		if err != nil {
			if err != io.EOF {
				log.Printf("Websoket read error:%v", err)
			}
			wsClosed = true
			break
		}
		switch mt {
		case websocket.BinaryMessage:
			if buf.Len() == 0 {
				buf = bytes.NewBuffer(data)
			} else {
				buf.Write(data)
			}
			ress, err := remote.HandleRequestBuffer(buf, ctx)
			if nil != err {
				log.Printf("[ERROR]connection %s:%d error:%v", ctx.User, ctx.ConnIndex, err)
				ws.Close()
				wsClosed = true
			} else {
				writeEvents(ress, &wbuf)
				if nil == queue && len(ctx.User) > 0 && ctx.ConnIndex >= 0 {
					queue = remote.GetEventQueue(ctx.ConnId, true)
					go func() {
						var wwbuf bytes.Buffer
						for !wsClosed {
							evs, err := queue.PeekMulti(2, 1*time.Millisecond, false)
							if ctx.Closing {
								evs = []event.Event{&event.ChannelCloseACKEvent{}}
							} else {
								if nil != err {
									continue
								}
							}
							err = writeEvents(evs, &wwbuf)
							if ctx.Closing {
								break
							}
							if nil != err {
								log.Printf("Websoket write error:%v", err)
								break
							} else {
								queue.DiscardPeeks(false)
							}
						}
						remote.ReleaseEventQueue(queue)
					}()
				}
			}
		default:
			log.Printf("Invalid websocket message type")
			ws.Close()
		}
	}
	wsClosed = true
	log.Printf("Close websocket connection:%d", ctx.ConnIndex)
	//ws.WriteMessage(websocket.CloseMessage, []byte{})
}
コード例 #8
0
ファイル: channel.go プロジェクト: yinqiwen/gsnova
func (rc *RemoteChannel) processWrite() {
	readBufferEv := func(evs []event.Event) []event.Event {
		sev := <-rc.wch
		if nil != sev {
			evs = append(evs, sev)
		}
		return evs
	}
	var sendEvents []event.Event
	var wbuf bytes.Buffer
	for rc.running {
		conn := rc.C
		//disable write if waiting for close CK
		if rc.closeState == stateCloseWaitingACK {
			time.Sleep(1 * time.Millisecond)
			continue
		}

		if len(sendEvents) == 0 {
			if len(rc.wch) > 0 {
				for len(rc.wch) > 0 {
					sendEvents = readBufferEv(sendEvents)
				}
			} else {
				sendEvents = readBufferEv(sendEvents)
			}
		}

		if !rc.running && len(sendEvents) == 0 {
			return
		}
		if conn.Closed() {
			time.Sleep(5 * time.Millisecond)
			continue
		}
		wbuf.Reset()
		//cryptoCtx := rc.cryptoCtx
		if rc.WriteJoinAuth || (rc.connSendedEvents == 0 && rc.OpenJoinAuth) {
			auth := NewAuthEvent(rc.SecureTransport)
			auth.Index = int64(rc.Index)
			auth.IV = rc.cryptoCtx.EncryptIV
			event.EncryptEvent(&wbuf, auth, &rc.cryptoCtx)
			rc.connSendedEvents++
		}

		for _, sev := range sendEvents {
			if auth, ok := sev.(*event.AuthEvent); ok {
				if auth.IV != rc.cryptoCtx.EncryptIV {
					log.Printf("####Got %d %d", rc.cryptoCtx.EncryptIV, auth.IV)
				}
				auth.IV = rc.cryptoCtx.EncryptIV
				//log.Printf("##[%d]Send %T with %d", sev.GetId(), sev, 0)
			}
			event.EncryptEvent(&wbuf, sev, &rc.cryptoCtx)
		}
		if rc.closeState == stateCloseToSendReq {
			closeReq := &event.ChannelCloseReqEvent{}
			event.EncryptEvent(&wbuf, closeReq, &rc.cryptoCtx)
		}
		rc.connSendedEvents += uint32(len(sendEvents))

		if wbuf.Len() > 0 {
			//start := time.Now()
			_, err := conn.Write(wbuf.Bytes())
			if nil != err {
				conn.Close()
				log.Printf("Failed to write tcp messgage:%v", err)
				//resend `sendEvents` in next process
			} else {
				//log.Printf("[%d]%s cost %v to write %d events.", rc.Index, rc.Addr, time.Now().Sub(start), len(sendEvents))
				sendEvents = nil
				//set state if write success
				if rc.closeState == stateCloseToSendReq {
					rc.closeState = stateCloseWaitingACK
				}
			}
		}
	}
}