ascii-chat 0.8.38
Real-time terminal-based video chat with ASCII art conversion
Loading...
Searching...
No Matches
upnp.c File Reference

UPnP/NAT-PMP port mapping implementation. More...

Go to the source code of this file.

Functions

asciichat_error_t nat_upnp_open (uint16_t internal_port, const char *description, nat_upnp_context_t **ctx)
 
void nat_upnp_close (nat_upnp_context_t **ctx)
 
bool nat_upnp_is_active (const nat_upnp_context_t *ctx)
 
asciichat_error_t nat_upnp_refresh (nat_upnp_context_t *ctx)
 
asciichat_error_t nat_upnp_get_address (const nat_upnp_context_t *ctx, char *addr, size_t addr_len)
 

Detailed Description

UPnP/NAT-PMP port mapping implementation.

Strategy for enabling direct TCP without WebRTC:

  1. Try UPnP discovery (works on ~90% of consumer routers)
  2. Fall back to NAT-PMP if UPnP fails (Apple/Time Capsule)
  3. If both fail, client falls back to ACDS + WebRTC

This pragmatic approach provides direct connectivity for most home users while maintaining compatibility with stricter NATs via WebRTC fallback.

Definition in file upnp.c.

Function Documentation

◆ nat_upnp_close()

void nat_upnp_close ( nat_upnp_context_t **  ctx)

Definition at line 276 of file upnp.c.

276 {
277 if (!ctx || !(*ctx)) {
278 return;
279 }
280
281 if ((*ctx)->is_mapped) {
282 // Note: In a real implementation, we'd remove the port mapping from the gateway.
283 // For MVP, we just log and let the lease expire naturally (typically 1 hour).
284 log_debug("NAT: Port mapping will expire in ~1 hour (cleanup handled by router)");
285 }
286
287 SAFE_FREE(*ctx);
288 *ctx = NULL;
289}

Referenced by acds_main().

◆ nat_upnp_get_address()

asciichat_error_t nat_upnp_get_address ( const nat_upnp_context_t *  ctx,
char *  addr,
size_t  addr_len 
)

Definition at line 310 of file upnp.c.

310 {
311 if (!ctx || !addr || addr_len < 22) {
312 return SET_ERRNO(ERROR_INVALID_PARAM, "NAT: Invalid arguments for get_address");
313 }
314
315 if (!ctx->is_mapped || ctx->external_ip[0] == '\0') {
316 return SET_ERRNO(ERROR_NETWORK, "NAT: No active mapping to advertise");
317 }
318
319 // Format as "IP:port" (e.g., "203.0.113.42:27224")
320 int written = safe_snprintf(addr, addr_len, "%s:%u", ctx->external_ip, ctx->mapped_port);
321
322 if (written < 0 || (size_t)written >= addr_len) {
323 return SET_ERRNO(ERROR_INVALID_PARAM, "NAT: Address buffer too small");
324 }
325
326 return ASCIICHAT_OK;
327}
int safe_snprintf(char *buffer, size_t buffer_size, const char *format,...)
Safe formatted string printing to buffer.
Definition system.c:456

References safe_snprintf().

Referenced by acds_main(), nat_detect_quality(), and server_main().

◆ nat_upnp_is_active()

bool nat_upnp_is_active ( const nat_upnp_context_t *  ctx)

Definition at line 291 of file upnp.c.

291 {
292 if (!ctx) {
293 return false;
294 }
295 return ctx->is_mapped && ctx->external_ip[0] != '\0';
296}

Referenced by nat_detect_quality().

◆ nat_upnp_open()

asciichat_error_t nat_upnp_open ( uint16_t  internal_port,
const char *  description,
nat_upnp_context_t **  ctx 
)

Definition at line 236 of file upnp.c.

236 {
237 if (!ctx || !description) {
238 return SET_ERRNO(ERROR_INVALID_PARAM, "nat_upnp_open: Invalid arguments");
239 }
240
241 // Allocate context
242 *ctx = SAFE_MALLOC(sizeof(nat_upnp_context_t), nat_upnp_context_t *);
243 if (!(*ctx)) {
244 return ERROR_MEMORY;
245 }
246
247 memset(*ctx, 0, sizeof(nat_upnp_context_t));
248
249 // Try UPnP first (works on ~90% of home routers)
250 log_info("NAT: Attempting UPnP port mapping for port %u...", internal_port);
251 asciichat_error_t result = upnp_try_map_port(internal_port, description, *ctx);
252
253 if (result == ASCIICHAT_OK) {
254 log_info("NAT: ✓ UPnP port mapping successful!");
255 return ASCIICHAT_OK;
256 }
257
258 log_info("NAT: UPnP failed, trying NAT-PMP fallback...");
259 result = natpmp_try_map_port(internal_port, *ctx);
260
261 if (result == ASCIICHAT_OK) {
262 log_info("NAT: ✓ NAT-PMP port mapping successful!");
263 return ASCIICHAT_OK;
264 }
265
266 // Both UPnP and NAT-PMP failed - this is OK, not fatal
267 log_warn("NAT: Both UPnP and NAT-PMP failed. Direct TCP won't work, will use ACDS + WebRTC.");
268 log_warn("NAT: This is normal for strict NATs. No action required.");
269
270 SAFE_FREE(*ctx);
271 *ctx = NULL;
272
273 return SET_ERRNO(ERROR_NETWORK, "NAT: No automatic port mapping available (will use WebRTC)");
274}

Referenced by acds_main(), nat_detect_quality(), and server_main().

◆ nat_upnp_refresh()

asciichat_error_t nat_upnp_refresh ( nat_upnp_context_t *  ctx)

Definition at line 298 of file upnp.c.

298 {
299 if (!ctx || !ctx->is_mapped) {
300 return SET_ERRNO(ERROR_INVALID_PARAM, "NAT: Cannot refresh - no active mapping");
301 }
302
303 log_debug("NAT: Refreshing port mapping (would extend lease in full implementation)");
304
305 // In a real implementation, we'd re-register the port mapping to extend the lease.
306 // For now, we just return success since the lease is 1 hour anyway.
307 return ASCIICHAT_OK;
308}