 9bdcbe0447
			
		
	
	9bdcbe0447
	
	
	
		
			
			Major integrations and fixes: - Added BACKBEAT SDK integration for P2P operation timing - Implemented beat-aware status tracking for distributed operations - Added Docker secrets support for secure license management - Resolved KACHING license validation via HTTPS/TLS - Updated docker-compose configuration for clean stack deployment - Disabled rollback policies to prevent deployment failures - Added license credential storage (CHORUS-DEV-MULTI-001) Technical improvements: - BACKBEAT P2P operation tracking with phase management - Enhanced configuration system with file-based secrets - Improved error handling for license validation - Clean separation of KACHING and CHORUS deployment stacks 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
		
			
				
	
	
		
			90 lines
		
	
	
		
			1.8 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			90 lines
		
	
	
		
			1.8 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package natpmp
 | |
| 
 | |
| import (
 | |
| 	"fmt"
 | |
| 	"net"
 | |
| 	"time"
 | |
| )
 | |
| 
 | |
| const nAT_PMP_PORT = 5351
 | |
| const nAT_TRIES = 9
 | |
| const nAT_INITIAL_MS = 250
 | |
| 
 | |
| // A caller that implements the NAT-PMP RPC protocol.
 | |
| type network struct {
 | |
| 	gateway net.IP
 | |
| }
 | |
| 
 | |
| func (n *network) call(msg []byte, timeout time.Duration) (result []byte, err error) {
 | |
| 	var server net.UDPAddr
 | |
| 	server.IP = n.gateway
 | |
| 	server.Port = nAT_PMP_PORT
 | |
| 	conn, err := net.DialUDP("udp", nil, &server)
 | |
| 	if err != nil {
 | |
| 		return
 | |
| 	}
 | |
| 	defer conn.Close()
 | |
| 
 | |
| 	// 16 bytes is the maximum result size.
 | |
| 	result = make([]byte, 16)
 | |
| 
 | |
| 	var finalTimeout time.Time
 | |
| 	if timeout != 0 {
 | |
| 		finalTimeout = time.Now().Add(timeout)
 | |
| 	}
 | |
| 
 | |
| 	needNewDeadline := true
 | |
| 
 | |
| 	var tries uint
 | |
| 	for tries = 0; (tries < nAT_TRIES && finalTimeout.IsZero()) || time.Now().Before(finalTimeout); {
 | |
| 		if needNewDeadline {
 | |
| 			nextDeadline := time.Now().Add((nAT_INITIAL_MS << tries) * time.Millisecond)
 | |
| 			err = conn.SetDeadline(minTime(nextDeadline, finalTimeout))
 | |
| 			if err != nil {
 | |
| 				return
 | |
| 			}
 | |
| 			needNewDeadline = false
 | |
| 		}
 | |
| 		_, err = conn.Write(msg)
 | |
| 		if err != nil {
 | |
| 			return
 | |
| 		}
 | |
| 		var bytesRead int
 | |
| 		var remoteAddr *net.UDPAddr
 | |
| 		bytesRead, remoteAddr, err = conn.ReadFromUDP(result)
 | |
| 		if err != nil {
 | |
| 			if err.(net.Error).Timeout() {
 | |
| 				tries++
 | |
| 				needNewDeadline = true
 | |
| 				continue
 | |
| 			}
 | |
| 			return
 | |
| 		}
 | |
| 		if !remoteAddr.IP.Equal(n.gateway) {
 | |
| 			// Ignore this packet.
 | |
| 			// Continue without increasing retransmission timeout or deadline.
 | |
| 			continue
 | |
| 		}
 | |
| 		// Trim result to actual number of bytes received
 | |
| 		if bytesRead < len(result) {
 | |
| 			result = result[:bytesRead]
 | |
| 		}
 | |
| 		return
 | |
| 	}
 | |
| 	err = fmt.Errorf("Timed out trying to contact gateway")
 | |
| 	return
 | |
| }
 | |
| 
 | |
| func minTime(a, b time.Time) time.Time {
 | |
| 	if a.IsZero() {
 | |
| 		return b
 | |
| 	}
 | |
| 	if b.IsZero() {
 | |
| 		return a
 | |
| 	}
 | |
| 	if a.Before(b) {
 | |
| 		return a
 | |
| 	}
 | |
| 	return b
 | |
| }
 |