sctp: Buffer outgoing data, similar to TCP
Instead of sending one APRS-IS line per SCTP message, combine multiple messages in a single SCTP message. This reduces the amount of system calls a lot and improves eventual DTLS performance.
This commit is contained in:
parent
ea9c80b5ea
commit
0075014c40
50
src/sctp.c
50
src/sctp.c
|
|
@ -245,8 +245,6 @@ int sctp_readable(struct worker_t *self, struct client_t *c)
|
||||||
}
|
}
|
||||||
|
|
||||||
//hlog_packet(LOG_DEBUG, iov.iov_base, e, "sctp_readable: got data: ");
|
//hlog_packet(LOG_DEBUG, iov.iov_base, e, "sctp_readable: got data: ");
|
||||||
c->ibuf[e++] = '\r';
|
|
||||||
c->ibuf[e++] = '\n';
|
|
||||||
|
|
||||||
return client_postread(self, c, e);
|
return client_postread(self, c, e);
|
||||||
}
|
}
|
||||||
|
|
@ -268,27 +266,45 @@ int sctp_writable(struct worker_t *self, struct client_t *c)
|
||||||
|
|
||||||
int sctp_client_write(struct worker_t *self, struct client_t *c, char *p, int len)
|
int sctp_client_write(struct worker_t *self, struct client_t *c, char *p, int len)
|
||||||
{
|
{
|
||||||
//hlog_packet(LOG_DEBUG, p, len, "client_write_sctp %d bytes: ", len);
|
//hlog_packet(LOG_DEBUG, p, len, "%s/%s: client_write_sctp %d bytes: ", c->addr_rem, c->username, len);
|
||||||
|
|
||||||
if (len == 0)
|
if (len > 0) {
|
||||||
return 0;
|
c->obuf_writes++;
|
||||||
|
if (client_buffer_outgoing_data(self, c, p, len) == -12)
|
||||||
|
return -12;
|
||||||
|
clientaccount_add( c, IPPROTO_SCTP, 0, 0, len, 0, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
clientaccount_add( c, IPPROTO_SCTP, 0, 0, len, 0, 0, 0);
|
/* Is it over the flush size ? */
|
||||||
|
if (c->obuf_end > c->obuf_flushsize || ((len == 0) && (c->obuf_end > c->obuf_start))) {
|
||||||
|
int to_send = c->obuf_end - c->obuf_start;
|
||||||
|
int i = send(c->fd, c->obuf + c->obuf_start, to_send, 0);
|
||||||
|
|
||||||
int i = send(c->fd, p, len-2, 0);
|
if (i < 0) {
|
||||||
|
hlog(LOG_ERR, "%s/%s: SCTP transmit error to fd %d: %s",
|
||||||
if (i < 0) {
|
c->addr_rem, c->username, c->fd, strerror(errno));
|
||||||
hlog(LOG_ERR, "SCTP transmit error to fd %d / %s: %s",
|
client_close(self, c, errno);
|
||||||
c->fd, c->addr_rem, strerror(errno));
|
return -9;
|
||||||
} else if (i != len -2) {
|
} else if (i != to_send) {
|
||||||
hlog(LOG_ERR, "SCTP transmit incomplete to fd %d / %s: wrote %d of %d bytes, errno: %s",
|
// Incomplete write with SCTP is not great, as we might not have ordered delivery.
|
||||||
c->fd, c->addr_rem, i, len-2, strerror(errno));
|
hlog(LOG_ERR, "%s/%s: SCTP transmit incomplete to fd %d: wrote %d of %d bytes, errno: %s",
|
||||||
} else {
|
c->addr_rem, c->username, c->fd, i, to_send, strerror(errno));
|
||||||
//hlog(LOG_DEBUG, "SCTP transmit ok to %s: %d bytes", c->addr_rem, i);
|
client_close(self, c, errno);
|
||||||
|
return -9;
|
||||||
|
} else {
|
||||||
|
//hlog(LOG_DEBUG, "%s/%s: SCTP transmit ok: %d bytes", c->addr_rem, c->username, i);
|
||||||
|
}
|
||||||
|
c->obuf_start += i;
|
||||||
c->obuf_wtime = tick;
|
c->obuf_wtime = tick;
|
||||||
}
|
}
|
||||||
|
|
||||||
return i;
|
/* All done ? */
|
||||||
|
if (c->obuf_start >= c->obuf_end) {
|
||||||
|
hlog(LOG_DEBUG, "%s/%s: client_write obuf empty", c->addr_rem, c->username, c->addr_rem);
|
||||||
|
c->obuf_start = 0;
|
||||||
|
c->obuf_end = 0;
|
||||||
|
}
|
||||||
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -960,7 +960,7 @@ static char *client_buffer_outgoing_allocate(struct client_t *c, int len)
|
||||||
return c->obuf + c->obuf_end;
|
return c->obuf + c->obuf_end;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int client_buffer_outgoing_data(struct worker_t *self, struct client_t *c, char *p, int len)
|
int client_buffer_outgoing_data(struct worker_t *self, struct client_t *c, char *p, int len)
|
||||||
{
|
{
|
||||||
char *buf_tail = client_buffer_outgoing_allocate(c, len);
|
char *buf_tail = client_buffer_outgoing_allocate(c, len);
|
||||||
|
|
||||||
|
|
@ -1662,7 +1662,7 @@ static void send_keepalives(struct worker_t *self)
|
||||||
c->obuf_flushsize = flushlevel;
|
c->obuf_flushsize = flushlevel;
|
||||||
} else {
|
} else {
|
||||||
/* just fush if there was anything to write */
|
/* just fush if there was anything to write */
|
||||||
if (c->ai_protocol == IPPROTO_TCP) {
|
if (c->ai_protocol == IPPROTO_TCP || c->ai_protocol == IPPROTO_SCTP) {
|
||||||
rc = c->write(self, c, buf, 0);
|
rc = c->write(self, c, buf, 0);
|
||||||
if (rc < -2) continue; // destroyed..
|
if (rc < -2) continue; // destroyed..
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -491,6 +491,7 @@ extern void pbuf_dump(FILE *fp);
|
||||||
extern void pbuf_dupe_dump(FILE *fp);
|
extern void pbuf_dupe_dump(FILE *fp);
|
||||||
|
|
||||||
extern int client_postread(struct worker_t *self, struct client_t *c, int r);
|
extern int client_postread(struct worker_t *self, struct client_t *c, int r);
|
||||||
|
extern int client_buffer_outgoing_data(struct worker_t *self, struct client_t *c, char *p, int len);
|
||||||
|
|
||||||
extern int client_printf(struct worker_t *self, struct client_t *c, const char *fmt, ...);
|
extern int client_printf(struct worker_t *self, struct client_t *c, const char *fmt, ...);
|
||||||
extern int client_write(struct worker_t *self, struct client_t *c, char *p, int len);
|
extern int client_write(struct worker_t *self, struct client_t *c, char *p, int len);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue