Merge branch 'fix-net-list-corruption'

This commit is contained in:
Oliver Jowett 2014-10-02 21:18:35 +01:00
commit 1cf0097dac
3 changed files with 30 additions and 28 deletions

View file

@ -582,6 +582,7 @@ void backgroundTasks(void) {
if (Modes.net) { if (Modes.net) {
modesReadFromClients(); modesReadFromClients();
modesNetCleanup();
} }
// If Modes.aircrafts is not NULL, remove any stale aircraft // If Modes.aircrafts is not NULL, remove any stale aircraft

View file

@ -459,6 +459,7 @@ void modesReadFromClients (void);
void modesSendAllClients (int service, void *msg, int len); void modesSendAllClients (int service, void *msg, int len);
void modesQueueOutput (struct modesMessage *mm); void modesQueueOutput (struct modesMessage *mm);
void modesReadFromClient(struct client *c, char *sep, int(*handler)(struct client *, char *)); void modesReadFromClient(struct client *c, char *sep, int(*handler)(struct client *, char *));
void modesNetCleanup (void);
#ifdef __cplusplus #ifdef __cplusplus
} }

View file

@ -145,23 +145,11 @@ struct client * modesAcceptClients(void) {
// On error free the client, collect the structure, adjust maxfd if needed. // On error free the client, collect the structure, adjust maxfd if needed.
// //
void modesFreeClient(struct client *c) { void modesFreeClient(struct client *c) {
// Clean up, but defer removing from the list until modesNetCleanup().
// This is because there may be stackframes still pointing at this
// client (unpredictably: reading from client A may cause client B to
// be freed)
// Unhook this client from the linked list of clients
struct client *p = Modes.clients;
if (p) {
if (p == c) {
Modes.clients = c->next;
} else {
while ((p) && (p->next != c)) {
p = p->next;
}
if (p) {
p->next = c->next;
}
}
}
// It's now safe to remove this client
close(c->fd); close(c->fd);
if (c->service == Modes.sbsos) { if (c->service == Modes.sbsos) {
if (Modes.stat_sbs_connections) Modes.stat_sbs_connections--; if (Modes.stat_sbs_connections) Modes.stat_sbs_connections--;
@ -174,7 +162,9 @@ void modesFreeClient(struct client *c) {
if (Modes.debug & MODES_DEBUG_NET) if (Modes.debug & MODES_DEBUG_NET)
printf("Closing client %d\n", c->fd); printf("Closing client %d\n", c->fd);
free(c); // mark it as inactive and ready to be freed
c->fd = -1;
c->service = -1;
} }
// //
//========================================================================= //=========================================================================
@ -182,12 +172,9 @@ void modesFreeClient(struct client *c) {
// Send the specified message to all clients listening for a given service // Send the specified message to all clients listening for a given service
// //
void modesSendAllClients(int service, void *msg, int len) { void modesSendAllClients(int service, void *msg, int len) {
struct client *c = Modes.clients; struct client *c;
while (c) {
// Read next before servicing client incase the service routine deletes the client!
struct client *next = c->next;
for (c = Modes.clients; c; c = c->next) {
if (c->service == service) { if (c->service == service) {
#ifndef _WIN32 #ifndef _WIN32
int nwritten = write(c->fd, msg, len); int nwritten = write(c->fd, msg, len);
@ -198,7 +185,6 @@ void modesSendAllClients(int service, void *msg, int len) {
modesFreeClient(c); modesFreeClient(c);
} }
} }
c = next;
} }
} }
// //
@ -952,10 +938,7 @@ void modesReadFromClients(void) {
struct client *c = modesAcceptClients(); struct client *c = modesAcceptClients();
while (c) { for (; c; c = c->next) {
// Read next before servicing client incase the service routine deletes the client!
struct client *next = c->next;
if (c->service == Modes.ris) { if (c->service == Modes.ris) {
modesReadFromClient(c,"\n",decodeHexMessage); modesReadFromClient(c,"\n",decodeHexMessage);
} else if (c->service == Modes.bis) { } else if (c->service == Modes.bis) {
@ -963,9 +946,26 @@ void modesReadFromClients(void) {
} else if (c->service == Modes.https) { } else if (c->service == Modes.https) {
modesReadFromClient(c,"\r\n\r\n",handleHTTPRequest); modesReadFromClient(c,"\r\n\r\n",handleHTTPRequest);
} }
c = next;
} }
} }
//
// Perform cleanup of any recently-closed clients.
//
void modesNetCleanup(void) {
struct client *c, **prev;
for (prev = &Modes.clients, c = *prev; c; c = *prev) {
if (c->fd == -1) {
// Recently closed, prune from list
*prev = c->next;
free(c);
} else {
prev = &c->next;
}
}
}
// //
// =============================== Network IO =========================== // =============================== Network IO ===========================
// //