| 
									
										
										
										
											2017-03-15 08:49:31 +08:00
										 |  |  | package sftp | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-06 05:19:14 +08:00
										 |  |  | import ( | 
					
						
							|  |  |  | 	"encoding" | 
					
						
							| 
									
										
										
										
											2018-01-26 09:44:22 +08:00
										 |  |  | 	"sort" | 
					
						
							| 
									
										
										
										
											2017-04-06 05:19:14 +08:00
										 |  |  | 	"sync" | 
					
						
							|  |  |  | ) | 
					
						
							| 
									
										
										
										
											2017-03-15 08:49:31 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-16 02:23:19 +08:00
										 |  |  | // The goal of the packetManager is to keep the outgoing packets in the same
 | 
					
						
							| 
									
										
										
										
											2018-07-26 07:03:30 +08:00
										 |  |  | // order as the incoming as is requires by section 7 of the RFC.
 | 
					
						
							| 
									
										
										
										
											2017-03-15 08:49:31 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-26 07:03:30 +08:00
										 |  |  | type packetManager struct { | 
					
						
							|  |  |  | 	requests    chan orderedPacket | 
					
						
							|  |  |  | 	responses   chan orderedPacket | 
					
						
							|  |  |  | 	fini        chan struct{} | 
					
						
							|  |  |  | 	incoming    orderedPackets | 
					
						
							|  |  |  | 	outgoing    orderedPackets | 
					
						
							|  |  |  | 	sender      packetSender // connection object
 | 
					
						
							|  |  |  | 	working     *sync.WaitGroup | 
					
						
							|  |  |  | 	packetCount uint32 | 
					
						
							| 
									
										
										
										
											2020-03-18 16:36:07 +08:00
										 |  |  | 	// it is not nil if the allocator is enabled
 | 
					
						
							| 
									
										
										
										
											2020-03-15 02:42:19 +08:00
										 |  |  | 	alloc *allocator | 
					
						
							| 
									
										
										
										
											2017-03-15 08:49:31 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-26 07:03:30 +08:00
										 |  |  | type packetSender interface { | 
					
						
							|  |  |  | 	sendPacket(encoding.BinaryMarshaler) error | 
					
						
							| 
									
										
										
										
											2017-03-15 08:49:31 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-21 06:23:55 +08:00
										 |  |  | func newPktMgr(sender packetSender) *packetManager { | 
					
						
							|  |  |  | 	s := &packetManager{ | 
					
						
							| 
									
										
										
										
											2018-07-26 07:03:30 +08:00
										 |  |  | 		requests:  make(chan orderedPacket, SftpServerWorkerCount), | 
					
						
							|  |  |  | 		responses: make(chan orderedPacket, SftpServerWorkerCount), | 
					
						
							| 
									
										
										
										
											2017-03-15 08:49:31 +08:00
										 |  |  | 		fini:      make(chan struct{}), | 
					
						
							| 
									
										
										
										
											2018-07-26 07:03:30 +08:00
										 |  |  | 		incoming:  make([]orderedPacket, 0, SftpServerWorkerCount), | 
					
						
							|  |  |  | 		outgoing:  make([]orderedPacket, 0, SftpServerWorkerCount), | 
					
						
							| 
									
										
										
										
											2017-03-15 08:49:31 +08:00
										 |  |  | 		sender:    sender, | 
					
						
							| 
									
										
										
										
											2017-04-06 05:19:14 +08:00
										 |  |  | 		working:   &sync.WaitGroup{}, | 
					
						
							| 
									
										
										
										
											2017-03-15 08:49:31 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-04-24 04:47:05 +08:00
										 |  |  | 	go s.controller() | 
					
						
							| 
									
										
										
										
											2017-03-15 08:49:31 +08:00
										 |  |  | 	return s | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-26 07:03:30 +08:00
										 |  |  | //// packet ordering
 | 
					
						
							| 
									
										
										
										
											2019-08-30 23:04:37 +08:00
										 |  |  | func (s *packetManager) newOrderID() uint32 { | 
					
						
							| 
									
										
										
										
											2018-07-26 07:03:30 +08:00
										 |  |  | 	s.packetCount++ | 
					
						
							|  |  |  | 	return s.packetCount | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2018-01-26 09:44:22 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-15 02:42:19 +08:00
										 |  |  | // returns the next orderID without incrementing it.
 | 
					
						
							| 
									
										
										
										
											2020-03-18 16:36:07 +08:00
										 |  |  | // This is used before receiving a new packet, with the allocator enabled, to associate
 | 
					
						
							| 
									
										
										
										
											2020-03-15 02:42:19 +08:00
										 |  |  | // the slice allocated for the received packet with the orderID that will be used to mark
 | 
					
						
							|  |  |  | // the allocated slices for reuse once the request is served
 | 
					
						
							|  |  |  | func (s *packetManager) getNextOrderID() uint32 { | 
					
						
							|  |  |  | 	return s.packetCount + 1 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-26 07:03:30 +08:00
										 |  |  | type orderedRequest struct { | 
					
						
							|  |  |  | 	requestPacket | 
					
						
							|  |  |  | 	orderid uint32 | 
					
						
							| 
									
										
										
										
											2018-01-26 09:44:22 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-26 07:03:30 +08:00
										 |  |  | func (s *packetManager) newOrderedRequest(p requestPacket) orderedRequest { | 
					
						
							| 
									
										
										
										
											2019-08-30 23:04:37 +08:00
										 |  |  | 	return orderedRequest{requestPacket: p, orderid: s.newOrderID()} | 
					
						
							| 
									
										
										
										
											2018-07-26 07:03:30 +08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2019-08-30 23:04:37 +08:00
										 |  |  | func (p orderedRequest) orderID() uint32       { return p.orderid } | 
					
						
							|  |  |  | func (p orderedRequest) setOrderID(oid uint32) { p.orderid = oid } | 
					
						
							| 
									
										
										
										
											2018-01-26 09:44:22 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-26 07:03:30 +08:00
										 |  |  | type orderedResponse struct { | 
					
						
							|  |  |  | 	responsePacket | 
					
						
							|  |  |  | 	orderid uint32 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (s *packetManager) newOrderedResponse(p responsePacket, id uint32, | 
					
						
							|  |  |  | ) orderedResponse { | 
					
						
							|  |  |  | 	return orderedResponse{responsePacket: p, orderid: id} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2019-08-30 23:04:37 +08:00
										 |  |  | func (p orderedResponse) orderID() uint32       { return p.orderid } | 
					
						
							|  |  |  | func (p orderedResponse) setOrderID(oid uint32) { p.orderid = oid } | 
					
						
							| 
									
										
										
										
											2018-07-26 07:03:30 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | type orderedPacket interface { | 
					
						
							|  |  |  | 	id() uint32 | 
					
						
							| 
									
										
										
										
											2019-08-30 23:04:37 +08:00
										 |  |  | 	orderID() uint32 | 
					
						
							| 
									
										
										
										
											2018-07-26 07:03:30 +08:00
										 |  |  | } | 
					
						
							|  |  |  | type orderedPackets []orderedPacket | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (o orderedPackets) Sort() { | 
					
						
							|  |  |  | 	sort.Slice(o, func(i, j int) bool { | 
					
						
							| 
									
										
										
										
											2019-08-30 23:04:37 +08:00
										 |  |  | 		return o[i].orderID() < o[j].orderID() | 
					
						
							| 
									
										
										
										
											2018-01-26 09:44:22 +08:00
										 |  |  | 	}) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-26 07:03:30 +08:00
										 |  |  | //// packet registry
 | 
					
						
							| 
									
										
										
										
											2017-03-15 08:49:31 +08:00
										 |  |  | // register incoming packets to be handled
 | 
					
						
							| 
									
										
										
										
											2018-07-26 07:03:30 +08:00
										 |  |  | func (s *packetManager) incomingPacket(pkt orderedRequest) { | 
					
						
							| 
									
										
										
										
											2017-04-06 05:19:14 +08:00
										 |  |  | 	s.working.Add(1) | 
					
						
							| 
									
										
										
										
											2018-07-26 07:03:30 +08:00
										 |  |  | 	s.requests <- pkt | 
					
						
							| 
									
										
										
										
											2017-03-15 08:49:31 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // register outgoing packets as being ready
 | 
					
						
							| 
									
										
										
										
											2018-07-26 07:03:30 +08:00
										 |  |  | func (s *packetManager) readyPacket(pkt orderedResponse) { | 
					
						
							| 
									
										
										
										
											2017-03-15 08:49:31 +08:00
										 |  |  | 	s.responses <- pkt | 
					
						
							| 
									
										
										
										
											2017-04-06 05:19:14 +08:00
										 |  |  | 	s.working.Done() | 
					
						
							| 
									
										
										
										
											2017-03-15 08:49:31 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-24 04:47:05 +08:00
										 |  |  | // shut down packetManager controller
 | 
					
						
							| 
									
										
										
										
											2017-08-21 06:23:55 +08:00
										 |  |  | func (s *packetManager) close() { | 
					
						
							| 
									
										
										
										
											2017-04-24 04:47:05 +08:00
										 |  |  | 	// pause until current packets are processed
 | 
					
						
							|  |  |  | 	s.working.Wait() | 
					
						
							| 
									
										
										
										
											2017-03-15 08:49:31 +08:00
										 |  |  | 	close(s.fini) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-24 04:47:05 +08:00
										 |  |  | // Passed a worker function, returns a channel for incoming packets.
 | 
					
						
							| 
									
										
										
										
											2018-07-26 07:03:30 +08:00
										 |  |  | // Keep process packet responses in the order they are received while
 | 
					
						
							|  |  |  | // maximizing throughput of file transfers.
 | 
					
						
							|  |  |  | func (s *packetManager) workerChan(runWorker func(chan orderedRequest), | 
					
						
							|  |  |  | ) chan orderedRequest { | 
					
						
							| 
									
										
										
										
											2017-04-24 04:47:05 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-21 03:39:58 +08:00
										 |  |  | 	// multiple workers for faster read/writes
 | 
					
						
							| 
									
										
										
										
											2018-07-26 07:03:30 +08:00
										 |  |  | 	rwChan := make(chan orderedRequest, SftpServerWorkerCount) | 
					
						
							| 
									
										
										
										
											2017-08-13 20:00:08 +08:00
										 |  |  | 	for i := 0; i < SftpServerWorkerCount; i++ { | 
					
						
							| 
									
										
										
										
											2017-07-04 08:53:55 +08:00
										 |  |  | 		runWorker(rwChan) | 
					
						
							| 
									
										
										
										
											2017-04-24 04:47:05 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-21 03:39:58 +08:00
										 |  |  | 	// single worker to enforce sequential processing of everything else
 | 
					
						
							| 
									
										
										
										
											2018-07-26 07:03:30 +08:00
										 |  |  | 	cmdChan := make(chan orderedRequest) | 
					
						
							| 
									
										
										
										
											2017-07-04 08:53:55 +08:00
										 |  |  | 	runWorker(cmdChan) | 
					
						
							| 
									
										
										
										
											2017-04-24 04:47:05 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-26 07:03:30 +08:00
										 |  |  | 	pktChan := make(chan orderedRequest, SftpServerWorkerCount) | 
					
						
							| 
									
										
										
										
											2017-04-24 04:47:05 +08:00
										 |  |  | 	go func() { | 
					
						
							|  |  |  | 		for pkt := range pktChan { | 
					
						
							| 
									
										
										
										
											2018-07-26 07:03:30 +08:00
										 |  |  | 			switch pkt.requestPacket.(type) { | 
					
						
							| 
									
										
										
										
											2018-08-21 03:39:58 +08:00
										 |  |  | 			case *sshFxpReadPacket, *sshFxpWritePacket: | 
					
						
							|  |  |  | 				s.incomingPacket(pkt) | 
					
						
							|  |  |  | 				rwChan <- pkt | 
					
						
							|  |  |  | 				continue | 
					
						
							| 
									
										
										
										
											2017-04-24 04:47:05 +08:00
										 |  |  | 			case *sshFxpClosePacket: | 
					
						
							| 
									
										
										
										
											2018-08-21 03:39:58 +08:00
										 |  |  | 				// wait for reads/writes to finish when file is closed
 | 
					
						
							|  |  |  | 				// incomingPacket() call must occur after this
 | 
					
						
							| 
									
										
										
										
											2017-04-24 04:47:05 +08:00
										 |  |  | 				s.working.Wait() | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			s.incomingPacket(pkt) | 
					
						
							| 
									
										
										
										
											2018-08-21 03:39:58 +08:00
										 |  |  | 			// all non-RW use sequential cmdChan
 | 
					
						
							|  |  |  | 			cmdChan <- pkt | 
					
						
							| 
									
										
										
										
											2017-04-24 04:47:05 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		close(rwChan) | 
					
						
							|  |  |  | 		close(cmdChan) | 
					
						
							|  |  |  | 		s.close() | 
					
						
							|  |  |  | 	}() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return pktChan | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-15 08:49:31 +08:00
										 |  |  | // process packets
 | 
					
						
							| 
									
										
										
										
											2017-04-24 04:47:05 +08:00
										 |  |  | func (s *packetManager) controller() { | 
					
						
							| 
									
										
										
										
											2017-03-15 08:49:31 +08:00
										 |  |  | 	for { | 
					
						
							|  |  |  | 		select { | 
					
						
							|  |  |  | 		case pkt := <-s.requests: | 
					
						
							| 
									
										
										
										
											2019-08-30 23:04:37 +08:00
										 |  |  | 			debug("incoming id (oid): %v (%v)", pkt.id(), pkt.orderID()) | 
					
						
							| 
									
										
										
										
											2018-07-26 07:03:30 +08:00
										 |  |  | 			s.incoming = append(s.incoming, pkt) | 
					
						
							|  |  |  | 			s.incoming.Sort() | 
					
						
							| 
									
										
										
										
											2017-03-15 08:49:31 +08:00
										 |  |  | 		case pkt := <-s.responses: | 
					
						
							| 
									
										
										
										
											2019-08-30 23:04:37 +08:00
										 |  |  | 			debug("outgoing id (oid): %v (%v)", pkt.id(), pkt.orderID()) | 
					
						
							| 
									
										
										
										
											2017-03-15 08:49:31 +08:00
										 |  |  | 			s.outgoing = append(s.outgoing, pkt) | 
					
						
							| 
									
										
										
										
											2018-07-26 07:03:30 +08:00
										 |  |  | 			s.outgoing.Sort() | 
					
						
							| 
									
										
										
										
											2017-03-15 08:49:31 +08:00
										 |  |  | 		case <-s.fini: | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		s.maybeSendPackets() | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // send as many packets as are ready
 | 
					
						
							|  |  |  | func (s *packetManager) maybeSendPackets() { | 
					
						
							|  |  |  | 	for { | 
					
						
							|  |  |  | 		if len(s.outgoing) == 0 || len(s.incoming) == 0 { | 
					
						
							|  |  |  | 			debug("break! -- outgoing: %v; incoming: %v", | 
					
						
							|  |  |  | 				len(s.outgoing), len(s.incoming)) | 
					
						
							|  |  |  | 			break | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		out := s.outgoing[0] | 
					
						
							|  |  |  | 		in := s.incoming[0] | 
					
						
							| 
									
										
										
										
											2018-07-26 07:03:30 +08:00
										 |  |  | 		// debug("incoming: %v", ids(s.incoming))
 | 
					
						
							|  |  |  | 		// debug("outgoing: %v", ids(s.outgoing))
 | 
					
						
							| 
									
										
										
										
											2019-08-30 23:04:37 +08:00
										 |  |  | 		if in.orderID() == out.orderID() { | 
					
						
							| 
									
										
										
										
											2018-07-26 07:03:30 +08:00
										 |  |  | 			debug("Sending packet: %v", out.id()) | 
					
						
							|  |  |  | 			s.sender.sendPacket(out.(encoding.BinaryMarshaler)) | 
					
						
							| 
									
										
										
										
											2020-03-15 02:42:19 +08:00
										 |  |  | 			if s.alloc != nil { | 
					
						
							|  |  |  | 				// mark for reuse the slices allocated for this request
 | 
					
						
							|  |  |  | 				s.alloc.ReleasePages(in.orderID()) | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2017-03-15 08:49:31 +08:00
										 |  |  | 			// pop off heads
 | 
					
						
							|  |  |  | 			copy(s.incoming, s.incoming[1:])            // shift left
 | 
					
						
							| 
									
										
										
										
											2018-11-21 08:02:25 +08:00
										 |  |  | 			s.incoming[len(s.incoming)-1] = nil         // clear last
 | 
					
						
							| 
									
										
										
										
											2017-03-15 08:49:31 +08:00
										 |  |  | 			s.incoming = s.incoming[:len(s.incoming)-1] // remove last
 | 
					
						
							|  |  |  | 			copy(s.outgoing, s.outgoing[1:])            // shift left
 | 
					
						
							| 
									
										
										
										
											2018-11-21 08:02:25 +08:00
										 |  |  | 			s.outgoing[len(s.outgoing)-1] = nil         // clear last
 | 
					
						
							| 
									
										
										
										
											2017-03-15 08:49:31 +08:00
										 |  |  | 			s.outgoing = s.outgoing[:len(s.outgoing)-1] // remove last
 | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			break | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-26 07:03:30 +08:00
										 |  |  | // func oids(o []orderedPacket) []uint32 {
 | 
					
						
							|  |  |  | // 	res := make([]uint32, 0, len(o))
 | 
					
						
							|  |  |  | // 	for _, v := range o {
 | 
					
						
							|  |  |  | // 		res = append(res, v.orderId())
 | 
					
						
							|  |  |  | // 	}
 | 
					
						
							|  |  |  | // 	return res
 | 
					
						
							|  |  |  | // }
 | 
					
						
							|  |  |  | // func ids(o []orderedPacket) []uint32 {
 | 
					
						
							|  |  |  | // 	res := make([]uint32, 0, len(o))
 | 
					
						
							|  |  |  | // 	for _, v := range o {
 | 
					
						
							|  |  |  | // 		res = append(res, v.id())
 | 
					
						
							|  |  |  | // 	}
 | 
					
						
							|  |  |  | // 	return res
 | 
					
						
							|  |  |  | // }
 |