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

Host negotiation logic for discovery mode. More...

Go to the source code of this file.

Functions

void negotiate_init (negotiate_ctx_t *ctx, const uint8_t session_id[16], const uint8_t participant_id[16], bool is_initiator)
 Initialize negotiation context.
 
asciichat_error_t negotiate_start_detection (negotiate_ctx_t *ctx, const char *stun_server, uint16_t local_port)
 Start NAT detection phase.
 
asciichat_error_t negotiate_receive_peer_quality (negotiate_ctx_t *ctx, const acip_nat_quality_t *peer_quality)
 Process received peer NAT quality.
 
asciichat_error_t negotiate_determine_result (negotiate_ctx_t *ctx)
 Determine negotiation result.
 
negotiate_state_t negotiate_get_state (const negotiate_ctx_t *ctx)
 Get current negotiation state.
 
bool negotiate_is_complete (const negotiate_ctx_t *ctx)
 Check if negotiation is complete.
 
asciichat_error_t negotiate_get_error (const negotiate_ctx_t *ctx)
 Get negotiation error (if failed)
 
asciichat_error_t negotiate_elect_future_host (const acip_nat_quality_t collected_quality[], const uint8_t participant_ids[][16], size_t num_participants, uint8_t out_future_host_id[16])
 Elect future host from multiple participants (NEW P2P design)
 

Detailed Description

Host negotiation logic for discovery mode.

Definition in file negotiate.c.

Function Documentation

◆ negotiate_determine_result()

asciichat_error_t negotiate_determine_result ( negotiate_ctx_t ctx)

Determine negotiation result.

Called after both parties have exchanged NAT quality. Sets we_are_host and related fields.

Parameters
ctxNegotiation context
Returns
ASCIICHAT_OK on success

Definition at line 111 of file negotiate.c.

111 {
112 if (!ctx) {
113 return SET_ERRNO(ERROR_INVALID_PARAM, "ctx is NULL");
114 }
115
117 return SET_ERRNO(ERROR_INVALID_STATE, "Cannot determine result: detection incomplete");
118 }
119
121
122 // Compare NAT qualities
123 int result = nat_compare_quality(&ctx->our_quality, &ctx->peer_quality, ctx->is_initiator);
124
125 if (result <= 0) {
126 // We should host
127 ctx->we_are_host = true;
129
130 // Set our address as host address
131 if (ctx->our_quality.public_address[0]) {
132 SAFE_STRNCPY(ctx->host_address, ctx->our_quality.public_address, sizeof(ctx->host_address));
133 } else {
134 // Fall back to localhost for testing
135 SAFE_STRNCPY(ctx->host_address, "127.0.0.1", sizeof(ctx->host_address));
136 }
137
138 ctx->host_port = ctx->our_quality.upnp_available ? ctx->our_quality.upnp_mapped_port : ACIP_HOST_DEFAULT_PORT;
139 ctx->connection_type = determine_connection_type(&ctx->our_quality);
140
141 log_info("Negotiation result: WE ARE HOST (addr=%s:%u, type=%d)", ctx->host_address, ctx->host_port,
142 ctx->connection_type);
143 } else {
144 // They should host
145 ctx->we_are_host = false;
147
148 // Set peer address as host address
149 if (ctx->peer_quality.public_address[0]) {
150 SAFE_STRNCPY(ctx->host_address, ctx->peer_quality.public_address, sizeof(ctx->host_address));
151 }
152
153 ctx->host_port = ctx->peer_quality.upnp_available ? ctx->peer_quality.upnp_mapped_port : ACIP_HOST_DEFAULT_PORT;
154 ctx->connection_type = determine_connection_type(&ctx->peer_quality);
155
156 log_info("Negotiation result: THEY ARE HOST (addr=%s:%u, type=%d)", ctx->host_address, ctx->host_port,
157 ctx->connection_type);
158 }
159
161 return ASCIICHAT_OK;
162}
int nat_compare_quality(const nat_quality_t *ours, const nat_quality_t *theirs, bool we_are_initiator)
Compare two NAT qualities and determine who should host.
Definition nat.c:52
@ NEGOTIATE_STATE_WE_HOST
We won, becoming host.
Definition negotiate.h:31
@ NEGOTIATE_STATE_THEY_HOST
They won, connecting as client.
Definition negotiate.h:32
@ NEGOTIATE_STATE_COMPARING
Comparing qualities.
Definition negotiate.h:30
@ NEGOTIATE_STATE_COMPLETE
Negotiation complete.
Definition negotiate.h:34
bool detection_complete
All probes finished.
Definition nat.h:51
char public_address[64]
Public IP address.
Definition nat.h:35
bool upnp_available
UPnP/NAT-PMP mapping succeeded.
Definition nat.h:30
uint16_t upnp_mapped_port
Mapped external port (if upnp_available)
Definition nat.h:31
bool we_are_host
True if we should become host.
Definition negotiate.h:56
uint8_t connection_type
acip_connection_type_t
Definition negotiate.h:59
char host_address[64]
Host's address (ours if we_are_host)
Definition negotiate.h:57
nat_quality_t our_quality
Our NAT quality.
Definition negotiate.h:47
bool peer_quality_received
Have we received peer's quality?
Definition negotiate.h:49
nat_quality_t peer_quality
Peer's NAT quality (when received)
Definition negotiate.h:48
bool is_initiator
Did we create this session?
Definition negotiate.h:44
negotiate_state_t state
Definition negotiate.h:52
uint16_t host_port
Host's port.
Definition negotiate.h:58

References negotiate_ctx_t::connection_type, nat_quality_t::detection_complete, negotiate_ctx_t::host_address, negotiate_ctx_t::host_port, negotiate_ctx_t::is_initiator, nat_compare_quality(), NEGOTIATE_STATE_COMPARING, NEGOTIATE_STATE_COMPLETE, NEGOTIATE_STATE_THEY_HOST, NEGOTIATE_STATE_WE_HOST, negotiate_ctx_t::our_quality, negotiate_ctx_t::peer_quality, negotiate_ctx_t::peer_quality_received, nat_quality_t::public_address, negotiate_ctx_t::state, nat_quality_t::upnp_available, nat_quality_t::upnp_mapped_port, and negotiate_ctx_t::we_are_host.

Referenced by discovery_session_process(), negotiate_receive_peer_quality(), and negotiate_start_detection().

◆ negotiate_elect_future_host()

asciichat_error_t negotiate_elect_future_host ( const acip_nat_quality_t  collected_quality[],
const uint8_t  participant_ids[][16],
size_t  num_participants,
uint8_t  out_future_host_id[16] 
)

Elect future host from multiple participants (NEW P2P design)

Called by quorum leader after collecting NAT quality from all participants. Determines who should become host if current host dies. Uses deterministic algorithm so all participants independently reach same result.

Parameters
collected_qualityArray of NAT quality from all participants
participant_idsArray of participant IDs (in same order as quality array)
num_participantsNumber of participants
out_future_host_idOutput: Elected future host's participant ID
Returns
ASCIICHAT_OK on success
Note
All participants compute this independently on their own collected data and reach the same result (deterministic algorithm).
If only one participant remains, that one is elected.
If all have same quality, uses participant ID lexicographic order as tiebreaker.

Definition at line 182 of file negotiate.c.

184 {
185 if (!collected_quality || !participant_ids || !out_future_host_id) {
186 SET_ERRNO(ERROR_INVALID_PARAM, "Invalid parameters");
187 return ERROR_INVALID_PARAM;
188 }
189
190 if (num_participants == 0 || num_participants > MAX_PARTICIPANTS) {
191 SET_ERRNO(ERROR_INVALID_PARAM, "Invalid participant count");
192 return ERROR_INVALID_PARAM;
193 }
194
195 // Special case: only one participant
196 if (num_participants == 1) {
197 memcpy(out_future_host_id, participant_ids[0], 16);
198 log_info("Only one participant, electing as future host");
199 return ASCIICHAT_OK;
200 }
201
202 // Convert all acip_nat_quality_t to nat_quality_t for comparison
204 for (size_t i = 0; i < num_participants; i++) {
205 nat_quality_from_acip(&collected_quality[i], &qualities[i]);
206 }
207
208 // Find the best candidate by comparing all pairs
209 // Winner is the one who "wins" most comparisons
210 size_t best_idx = 0;
211 int best_wins = 0;
212
213 for (size_t i = 0; i < num_participants; i++) {
214 int wins = 0;
215
216 // Compare against all others
217 for (size_t j = 0; j < num_participants; j++) {
218 if (i == j)
219 continue;
220
221 // Compare: -1 means i wins, 1 means j wins, 0 means tie
222 // Note: we_are_initiator parameter doesn't matter for multiparty comparison
223 // We use false consistently for deterministic results
224 int result = nat_compare_quality(&qualities[i], &qualities[j], false);
225
226 if (result <= 0) {
227 wins++; // i wins or tie
228 }
229 }
230
231 // Select as winner if has more wins than current best
232 // In case of tie, lexicographically smaller participant_id wins (as tiebreaker)
233 if (wins > best_wins || (wins == best_wins && memcmp(participant_ids[i], participant_ids[best_idx], 16) < 0)) {
234 best_wins = wins;
235 best_idx = i;
236 }
237 }
238
239 // Copy elected host ID
240 memcpy(out_future_host_id, participant_ids[best_idx], 16);
241
242 log_info("Future host elected (participant index %zu with %d wins)", best_idx, best_wins);
243 return ASCIICHAT_OK;
244}
void nat_quality_from_acip(const acip_nat_quality_t *acip, nat_quality_t *out)
Convert acip_nat_quality_t to nat_quality_t.
Definition nat.c:487
#define MAX_PARTICIPANTS
Definition session.h:33
NAT quality assessment result.
Definition nat.h:27

References MAX_PARTICIPANTS, nat_compare_quality(), and nat_quality_from_acip().

◆ negotiate_get_error()

asciichat_error_t negotiate_get_error ( const negotiate_ctx_t ctx)

Get negotiation error (if failed)

Parameters
ctxNegotiation context
Returns
Error code or ASCIICHAT_OK if no error

Definition at line 176 of file negotiate.c.

176 {
177 if (!ctx)
178 return ERROR_INVALID_PARAM;
179 return ctx->error;
180}
asciichat_error_t error
Definition negotiate.h:53

References negotiate_ctx_t::error.

◆ negotiate_get_state()

negotiate_state_t negotiate_get_state ( const negotiate_ctx_t ctx)

Get current negotiation state.

Parameters
ctxNegotiation context
Returns
Current state

Definition at line 164 of file negotiate.c.

164 {
165 if (!ctx)
167 return ctx->state;
168}
@ NEGOTIATE_STATE_FAILED
Negotiation failed.
Definition negotiate.h:33

References NEGOTIATE_STATE_FAILED, and negotiate_ctx_t::state.

◆ negotiate_init()

void negotiate_init ( negotiate_ctx_t ctx,
const uint8_t  session_id[16],
const uint8_t  participant_id[16],
bool  is_initiator 
)

Initialize negotiation context.

Parameters
ctxContext to initialize
session_idSession UUID
participant_idOur participant UUID
is_initiatorTrue if we created the session

Definition at line 17 of file negotiate.c.

18 {
19 if (!ctx)
20 return;
21
22 memset(ctx, 0, sizeof(negotiate_ctx_t));
23
24 if (session_id)
25 memcpy(ctx->session_id, session_id, 16);
27 memcpy(ctx->participant_id, participant_id, 16);
28
29 ctx->is_initiator = is_initiator;
31 ctx->peer_quality_received = false;
32 ctx->we_are_host = false;
33
36
37 log_debug("Negotiation initialized (initiator=%d)", is_initiator);
38}
void nat_quality_init(nat_quality_t *quality)
Initialize NAT quality structure with defaults.
Definition nat.c:30
@ NEGOTIATE_STATE_INIT
Initial state.
Definition negotiate.h:27
uint8_t session_id[16]
uint8_t participant_id[16]
Host negotiation context.
Definition negotiate.h:40
uint8_t participant_id[16]
Definition negotiate.h:43
uint8_t session_id[16]
Definition negotiate.h:42

References negotiate_ctx_t::is_initiator, nat_quality_init(), NEGOTIATE_STATE_INIT, negotiate_ctx_t::our_quality, participant_id, negotiate_ctx_t::participant_id, negotiate_ctx_t::peer_quality, negotiate_ctx_t::peer_quality_received, session_id, negotiate_ctx_t::session_id, negotiate_ctx_t::state, and negotiate_ctx_t::we_are_host.

Referenced by discovery_session_process().

◆ negotiate_is_complete()

bool negotiate_is_complete ( const negotiate_ctx_t ctx)

Check if negotiation is complete.

Parameters
ctxNegotiation context
Returns
True if negotiation finished (success or failure)

Definition at line 170 of file negotiate.c.

170 {
171 if (!ctx)
172 return true;
174}

References NEGOTIATE_STATE_COMPLETE, NEGOTIATE_STATE_FAILED, and negotiate_ctx_t::state.

◆ negotiate_receive_peer_quality()

asciichat_error_t negotiate_receive_peer_quality ( negotiate_ctx_t ctx,
const acip_nat_quality_t *  peer_quality 
)

Process received peer NAT quality.

Parameters
ctxNegotiation context
peer_qualityPeer's NAT quality from network
Returns
ASCIICHAT_OK on success

Definition at line 67 of file negotiate.c.

67 {
68 if (!ctx || !peer_quality) {
69 return SET_ERRNO(ERROR_INVALID_PARAM, "ctx or peer_quality is NULL");
70 }
71
72 nat_quality_from_acip(peer_quality, &ctx->peer_quality);
73 ctx->peer_quality_received = true;
74
75 log_info("Received peer NAT quality: tier=%d, upload=%u kbps", nat_compute_tier(&ctx->peer_quality),
77
78 // If our detection is complete, we can determine result
82 }
83
84 // Otherwise, keep waiting for our detection to complete
85 return ASCIICHAT_OK;
86}
int nat_compute_tier(const nat_quality_t *quality)
Compute NAT tier for host selection (0=best, 4=worst)
Definition nat.c:37
asciichat_error_t negotiate_determine_result(negotiate_ctx_t *ctx)
Determine negotiation result.
Definition negotiate.c:111
uint32_t upload_kbps
Upload bandwidth in Kbps.
Definition nat.h:39

References nat_quality_t::detection_complete, nat_compute_tier(), nat_quality_from_acip(), negotiate_determine_result(), NEGOTIATE_STATE_COMPARING, negotiate_ctx_t::our_quality, negotiate_ctx_t::peer_quality, negotiate_ctx_t::peer_quality_received, negotiate_ctx_t::state, and nat_quality_t::upload_kbps.

◆ negotiate_start_detection()

asciichat_error_t negotiate_start_detection ( negotiate_ctx_t ctx,
const char *  stun_server,
uint16_t  local_port 
)

Start NAT detection phase.

Parameters
ctxNegotiation context
stun_serverSTUN server URL
local_portLocal port for detection
Returns
ASCIICHAT_OK on success

Definition at line 40 of file negotiate.c.

40 {
41 if (!ctx) {
42 return SET_ERRNO(ERROR_INVALID_PARAM, "ctx is NULL");
43 }
44
46 log_info("Starting NAT detection for host negotiation...");
47
48 asciichat_error_t result = nat_detect_quality(&ctx->our_quality, stun_server, local_port);
49 if (result != ASCIICHAT_OK) {
51 ctx->error = result;
52 log_error("NAT detection failed");
53 return result;
54 }
55
56 // If we already have peer quality, we can determine result
57 if (ctx->peer_quality_received) {
60 }
61
63 log_info("NAT detection complete, waiting for peer quality...");
64 return ASCIICHAT_OK;
65}
asciichat_error_t nat_detect_quality(nat_quality_t *quality, const char *stun_server, uint16_t local_port)
Detect NAT quality using all available methods.
Definition nat.c:283
@ NEGOTIATE_STATE_WAITING_PEER
Waiting for peer's NAT quality.
Definition negotiate.h:29
@ NEGOTIATE_STATE_DETECTING_NAT
Running NAT detection.
Definition negotiate.h:28

References negotiate_ctx_t::error, nat_detect_quality(), negotiate_determine_result(), NEGOTIATE_STATE_COMPARING, NEGOTIATE_STATE_DETECTING_NAT, NEGOTIATE_STATE_FAILED, NEGOTIATE_STATE_WAITING_PEER, negotiate_ctx_t::our_quality, negotiate_ctx_t::peer_quality_received, and negotiate_ctx_t::state.