I'm amazed I let these get swallowed up between chan and endpt. Oh,
well.
Minor interface change: endpt_join wants a channel description string,
but the source (which always does the joining anyway) has one to hand.
The channel structure has grown an error indicator which the endpoint
manager inspects when it's tearing down the connection.
if (w < 0) {
if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)
return;
if (w < 0) {
if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)
return;
goto close;
else if (c->len == CHAN_BUFSZ && !(c->f & CHANF_CLOSE))
sel_addfile(&c->r);
goto close;
else if (c->len == CHAN_BUFSZ && !(c->f & CHANF_CLOSE))
sel_addfile(&c->r);
if (r < 0) {
if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)
return;
if (r < 0) {
if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)
return;
goto close;
else if (c->len == 0 && (c->f & CHANF_READY)) {
sel_addfile(&c->w);
goto close;
else if (c->len == 0 && (c->f & CHANF_READY)) {
sel_addfile(&c->w);
typedef struct tango {
struct tango *next, *prev; /* A big list of all tangos */
endpt *a, *b; /* The two endpoints */
typedef struct tango {
struct tango *next, *prev; /* A big list of all tangos */
endpt *a, *b; /* The two endpoints */
+ char *desc; /* Description of the connection */
unsigned s; /* State of the connection */
chanpair *c; /* The pair of channels */
} tango;
unsigned s; /* State of the connection */
chanpair *c; /* The pair of channels */
} tango;
*/
if (a->f & b->f & EPF_FILE) {
*/
if (a->f & b->f & EPF_FILE) {
+ if (t->c->ab.err)
+ fw_log(-1, "[%s] error: %s", t->desc, strerror(t->c->ab.err));
+ else if (t->c->ba.err)
+ fw_log(-1, "[%s] error: %s", t->desc, strerror(t->c->ba.err));
if (t->s & EPS_AB)
chan_close(&t->c->ab);
if (!(b->f & EPF_PENDING) && (t->s & EPS_BA))
if (t->s & EPS_AB)
chan_close(&t->c->ab);
if (!(b->f & EPF_PENDING) && (t->s & EPS_BA))
t->prev->next = t->next;
else
tangos = t->next;
t->prev->next = t->next;
else
tangos = t->next;
+ if (t->desc)
+ xfree(t->desc);
*
* Arguments: @endpt *a@ = pointer to first endpoint
* @endpt *b@ = pointer to second endpoint
*
* Arguments: @endpt *a@ = pointer to first endpoint
* @endpt *b@ = pointer to second endpoint
+ * @const char *desc@ = description of connection
* which are already joined; in fact, the the right thing to do
* when your endpoint decides that it's not pending any more is
* to join it to its partner again.
* which are already joined; in fact, the the right thing to do
* when your endpoint decides that it's not pending any more is
* to join it to its partner again.
+ *
+ * If the endpoints are already connected then the description
+ * string is ignored. The endpoint manager takes a copy of the
+ * string, so you don't need to keep it around.
-void endpt_join(endpt *a, endpt *b)
+void endpt_join(endpt *a, endpt *b, const char *desc)
a->t = b->t = t;
t->s = EPS_AB | EPS_BA;
t->c = 0;
a->t = b->t = t;
t->s = EPS_AB | EPS_BA;
t->c = 0;
+ t->desc = xstrdup(desc);
if (tangos)
tangos->prev = t;
tangos = t;
if (tangos)
tangos->prev = t;
tangos = t;
ee->ops->close(ee);
goto tidy;
}
ee->ops->close(ee);
goto tidy;
}
+ endpt_join(e, ee, xs->s.desc);
/* --- Dispose of source and target --- */
/* --- Dispose of source and target --- */
ee->ops->close(ee);
goto tidy;
}
ee->ops->close(ee);
goto tidy;
}
+ endpt_join(e, ee, fs->s.desc);
/* --- Dispose of the source and target now --- */
/* --- Dispose of the source and target now --- */
unsigned base, len; /* Base and length of data */
unsigned f; /* Various interesting flags */
void (*func)(void */*p*/); /* Function to call on closure */
unsigned base, len; /* Base and length of data */
unsigned f; /* Various interesting flags */
void (*func)(void */*p*/); /* Function to call on closure */
+ int err; /* What's wrong with the channel */
void *p; /* Argument to pass function */
sel_file r, w; /* Reader and writer selectors */
char buf[CHAN_BUFSZ]; /* The actual data buffer */
void *p; /* Argument to pass function */
sel_file r, w; /* Reader and writer selectors */
char buf[CHAN_BUFSZ]; /* The actual data buffer */
*
* Arguments: @endpt *a@ = pointer to first endpoint
* @endpt *b@ = pointer to second endpoint
*
* Arguments: @endpt *a@ = pointer to first endpoint
* @endpt *b@ = pointer to second endpoint
+ * @const char *desc@ = description of connection
- * Use: Joins two endpoints together.
+ * Use: Joins two endpoints together. It's OK to join endpoints
+ * which are already joined; in fact, the the right thing to do
+ * when your endpoint decides that it's not pending any more is
+ * to join it to its partner again.
+ *
+ * If the endpoints are already connected then the description
+ * string is ignored. The endpoint manager takes a copy of
+ * the string, so you don't need to keep it around.
-extern void endpt_join(endpt */*a*/, endpt */*b*/);
+extern void endpt_join(endpt */*a*/, endpt */*b*/, const char */*desc*/);
/* --- @source_add@ --- *
*
/* --- @source_add@ --- *
*
e->e.in = e->e.out = r;
e->e.f &= ~EPF_PENDING;
if (e->e.other)
e->e.in = e->e.out = r;
e->e.f &= ~EPF_PENDING;
if (e->e.other)
- endpt_join(&e->e, e->e.other);
+ endpt_join(&e->e, e->e.other, 0);
/* --- Let everything else happen --- */
/* --- Let everything else happen --- */
+ endpt_join(&e->e, ee, ss->s.desc);