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 }
// 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) } } } }
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 } }
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 } }
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 }
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) }() } } } }
// 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{}) }
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 } } } } }