MCPcopy Create free account
hub / github.com/facebook/time / Connect

Method Connect

ntrip/client.go:123–187  ·  view source on GitHub ↗

Connect establishes a connection to the NTRIP caster. If a proxy is configured, it first establishes an HTTP CONNECT tunnel through the proxy with TLS client certificate authentication. Then it performs the NTRIP handshake (v1 SOURCE or v2 HTTP POST) and waits for the caster's acceptance response be

(ctx context.Context)

Source from the content-addressed store, hash-verified

121// handshake (v1 SOURCE or v2 HTTP POST) and waits for the caster's
122// acceptance response before allowing data writes.
123func (c *Client) Connect(ctx context.Context) error {
124 conn, err := c.dial(ctx)
125 if err != nil {
126 return fmt.Errorf("dialing caster: %w", err)
127 }
128
129 if c.config.Version == 2 {
130 err = c.postHandshake(conn)
131 } else {
132 err = c.sourceHandshake(conn)
133 }
134 if err != nil {
135 conn.Close()
136 return fmt.Errorf("NTRIP handshake: %w", err)
137 }
138
139 // Wait for caster response before allowing data writes.
140 // v1 casters reply "ICY 200 OK", v2 casters reply "HTTP/1.1 200 OK".
141 if err := conn.SetReadDeadline(time.Now().Add(5 * time.Second)); err != nil {
142 conn.Close()
143 return fmt.Errorf("setting read deadline: %w", err)
144 }
145 // TCP may split the response across segments, so read the full status line
146 // rather than relying on whatever a single Read happens to return.
147 reader := bufio.NewReader(conn)
148 statusLine, err := reader.ReadString('\n')
149 if err != nil {
150 conn.Close()
151 return fmt.Errorf("reading caster response: %w", err)
152 }
153 if err := conn.SetReadDeadline(time.Time{}); err != nil {
154 conn.Close()
155 return fmt.Errorf("clearing read deadline: %w", err)
156 }
157 resp := strings.TrimSpace(statusLine)
158 c.logger.Info("received from caster", "data", resp)
159 // The status line is "ICY 200 OK" (v1) or "HTTP/1.1 200 OK" (v2); the code
160 // is the second field. Check it exactly rather than substring-matching
161 // "200", which would also match "1200", "200ms", etc.
162 fields := strings.Fields(resp)
163 if len(fields) < 2 || fields[1] != "200" {
164 conn.Close()
165 return fmt.Errorf("caster rejected: %s", resp)
166 }
167
168 c.conn = conn
169
170 // Drain any further responses from the caster in the background, reusing the
171 // reader so bytes buffered past the status line are not lost.
172 go func() {
173 buf := make([]byte, 1024)
174 for {
175 n, err := reader.Read(buf)
176 if n > 0 {
177 c.logger.Info("received from caster", "data", string(buf[:n]))
178 }
179 if err != nil {
180 c.logger.Debug("caster read closed", "error", err)

Callers 4

connectCasterFunction · 0.95

Calls 5

dialMethod · 0.95
postHandshakeMethod · 0.95
sourceHandshakeMethod · 0.95
CloseMethod · 0.65
ReadMethod · 0.65

Tested by 3