21#if defined(ARDUINO) && PC_NEED_CLIENT
24#include "lwip/priv/tcpip_priv.h"
36 volatile bool connected;
49static pc_client_ctx s_client;
57static err_t cc_recv(
void *arg,
struct tcp_pcb *tpcb,
struct pbuf *p, err_t err)
60 ClientConn *c = (ClientConn *)arg;
79 for (
struct pbuf *q = p; q; q = q->next)
81 h = pc_ring_write_span(c->rx,
PC_CLIENT_RX_BUF, h, (
const uint8_t *)q->payload, q->len);
93static err_t cc_connected(
void *arg,
struct tcp_pcb *tpcb, err_t err)
96 ClientConn *c = (ClientConn *)arg;
111static void cc_err(
void *arg, err_t err)
114 ClientConn *c = (ClientConn *)arg;
126 struct tcpip_api_call_data base;
134 struct tcpip_api_call_data base;
142 struct tcpip_api_call_data base;
147static err_t cc_do_connect(
struct tcpip_api_call_data *cd)
149 CcConnCall *k = (CcConnCall *)cd;
150 ClientConn *c = k->c;
151 c->pcb = tcp_new_ip_type(IPADDR_TYPE_V4);
158 tcp_recv(c->pcb, cc_recv);
159 tcp_err(c->pcb, cc_err);
160#if PC_ENABLE_DIFFSERV
164 uint8_t dscp = pc_diffserv_default_dscp();
167 c->pcb->tos = pc_dscp_to_tos(dscp);
171 k->result = tcp_connect(c->pcb, &k->addr, k->port, cc_connected);
175static err_t cc_do_send(
struct tcpip_api_call_data *cd)
177 CcSendCall *k = (CcSendCall *)cd;
178 ClientConn *c = k->c;
181 k->result = ERR_CONN;
184 k->result = tcp_write(c->pcb, k->data, k->len, TCP_WRITE_FLAG_COPY);
185 if (k->result == ERR_OK)
192static err_t cc_do_close(
struct tcpip_api_call_data *cd)
194 CcSendCall *k = (CcSendCall *)cd;
195 ClientConn *c = k->c;
198 tcp_arg(c->pcb,
nullptr);
199 tcp_recv(c->pcb,
nullptr);
200 tcp_err(c->pcb,
nullptr);
201 if (tcp_close(c->pcb) != ERR_OK)
210static err_t cc_do_recved(
struct tcpip_api_call_data *cd)
212 CcRecvedCall *k = (CcRecvedCall *)cd;
215 tcp_recved(k->c->pcb, k->len);
222int pc_client_open(
const char *host, uint16_t port, uint32_t timeout_ms)
227 if (!s_client.cc[i].in_use)
238 ClientConn *c = &s_client.cc[cid];
240 c->connected =
false;
249 if (!pc_dns_resolver_resolve(host, &ip))
254 uint32_t deadline =
pc_millis() + timeout_ms;
257 memset(&k, 0,
sizeof(k));
259 IP_ADDR4(&k.addr, (uint8_t)(ip >> 24), (uint8_t)(ip >> 16), (uint8_t)(ip >> 8), (uint8_t)ip);
261 tcpip_api_call(cc_do_connect, &k.base);
262 if (k.result != ERR_OK)
267 while (!c->connected && !c->closed && (int32_t)(deadline -
pc_millis()) > 0)
281 return cid >= 0 && cid <
PC_CLIENT_CONNS && s_client.cc[cid].in_use && s_client.cc[cid].connected &&
282 !s_client.cc[cid].closed;
291 return s_client.cc[cid].closed;
301 memset(&k, 0,
sizeof(k));
302 k.c = &s_client.cc[cid];
304 k.len = (u16_t)(len > 0xFFFF ? 0xFFFF : len);
305 tcpip_api_call(cc_do_send, &k.base);
306 return k.result == ERR_OK;
315 ClientConn *c = &s_client.cc[cid];
325 ClientConn *c = &s_client.cc[cid];
326 size_t n = pc_ring_read(c->rx,
PC_CLIENT_RX_BUF, c->head, c->tail, buf, cap);
331 memset(&k, 0,
sizeof(k));
334 tcpip_api_call(cc_do_recved, &k.base);
346 memset(&k, 0,
sizeof(k));
347 k.c = &s_client.cc[cid];
348 tcpip_api_call(cc_do_close, &k.base);
349 s_client.cc[cid].in_use =
false;
bool pc_client_send(int, const void *, size_t)
Queue len wire bytes for transmission (marshaled tcp_write + output).
size_t pc_client_read(int, uint8_t *, size_t)
Drain up to cap buffered wire bytes into buf; returns the count.
bool pc_client_is_closed(int)
True once the peer closed (FIN) or the connection errored.
int pc_client_open(const char *, uint16_t, uint32_t)
Resolve host (dotted-quad fast path, else DNS) and connect to host : port, blocking up to timeout_ms.
size_t pc_client_available(int)
Wire bytes currently buffered and ready to read.
bool pc_client_connected(int)
True once the TCP handshake has completed for cid.
void pc_client_close(int)
Tear down the connection (marshaled) and return the slot to the pool.
Layer 4 outbound TCP client transport - the client-side peer of the (server) transport in tcp....
Pluggable monotonic clock for all library timing.
void pcdelay(uint32_t ms)
Block for at least ms milliseconds - the library's single delay primitive.
uint32_t pc_millis(void)
The library's monotonic time at 1000 Hz (milliseconds).
Layer 4 (Transport) - DiffServ QoS marking (RFC 2474) for outbound traffic.
DNS resolver with answer verification (PC_ENABLE_DNS_RESOLVER).
#define PC_CLIENT_CONNS
Reverse-SSH tunnel: max concurrent forwarded-tcpip channels bridged at once. A relay that forwards to...
Shared single-producer / single-consumer byte-ring primitive.