2
0
mirror of https://github.com/msantos/xmppipe synced 2024-11-16 00:12:59 +00:00
xmppipe/src/xmppipe_event.c
2023-10-13 07:29:46 -04:00

151 lines
3.9 KiB
C

/* Copyright (c) 2015-2023, Michael Santos <michael.santos@gmail.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "xmppipe.h"
#include <netinet/in.h>
#include <resolv.h>
#include <sys/select.h>
static int handle_stdin(xmppipe_state_t *state, int fd, char *buf, size_t len);
void event_loop(xmppipe_state_t *state) {
int fd = STDIN_FILENO;
int eof = 0;
char *buf;
if (xmppipe_set_nonblock(fd) < 0)
return;
buf = xmppipe_calloc(state->bufsz, 1);
for (;;) {
if (state->status == XMPPIPE_S_DISCONNECTED)
goto XMPPIPE_EXIT;
if (state->sm_enabled) {
if (state->sm_ack_sent > state->sm_request)
errx(EXIT_FAILURE, "h too large: sent=%u, server responded=%u",
state->sm_request, state->sm_ack_sent);
if ((state->sm_request_unack > state->sm_unacked) ||
(state->sm_request - state->sm_ack_sent > state->sm_fc)) {
if (state->verbose)
(void)fprintf(stderr, "WAIT: request=%u ack_sent=%u unack=%u\n",
state->sm_request, state->sm_ack_sent,
state->sm_request_unack);
goto XMPPIPE_POLL;
}
}
if (eof) {
if (state->opt & XMPPIPE_OPT_EOF)
goto XMPPIPE_POLL;
if (state->sm_enabled && (state->sm_ack_sent < state->sm_request)) {
if (state->verbose)
(void)fprintf(stderr, "POLLING: request: %d ack: %d\n",
state->sm_request, state->sm_ack_sent);
goto XMPPIPE_POLL;
} else
goto XMPPIPE_EXIT;
}
switch (handle_stdin(state, fd, buf, state->bufsz - 1)) {
case -1:
goto XMPPIPE_EXIT;
case 0:
if (!(state->opt & XMPPIPE_OPT_EOF) && !state->sm_enabled)
goto XMPPIPE_EXIT;
eof = 1;
break;
case 1:
break;
default:
(void)memset(buf, '\0', state->bufsz);
break;
}
state->interval += state->poll;
XMPPIPE_POLL:
if (state->keepalive > 0 && state->interval > state->keepalive) {
xmppipe_ping(state);
state->interval = 0;
}
if (state->keepalive_fail > state->keepalive_limit)
errx(EXIT_FAILURE, "no response to keepalives");
xmpp_run_once(state->ctx, state->poll);
state->interval += state->poll;
if ((state->opt & XMPPIPE_OPT_SIGPIPE) &&
state->status == XMPPIPE_S_READY_EMPTY)
goto XMPPIPE_EXIT;
}
XMPPIPE_EXIT:
free(buf);
return;
}
static int handle_stdin(xmppipe_state_t *state, int fd, char *buf, size_t len) {
fd_set rfds;
struct timeval tv = {0};
ssize_t n = 0;
int rv;
tv.tv_usec = state->poll * 1000;
FD_ZERO(&rfds);
FD_SET(fd, &rfds);
rv = select(fd + 1, &rfds, NULL, NULL, &tv);
if (rv < 0) {
warn("select");
return -1;
}
if (FD_ISSET(fd, &rfds)) {
n = read(fd, buf, len);
if (n <= 0)
return n;
if (state->verbose > 2)
(void)fprintf(stderr, "STDIN:%s\n", buf);
/* read and discard the data */
if ((state->opt & XMPPIPE_OPT_DISCARD) && state->occupants == 0) {
if (state->opt & XMPPIPE_OPT_DISCARD_TO_STDOUT) {
char *enc = NULL;
enc = xmppipe_fmt_encode(buf);
(void)printf("!:%s\n", enc);
free(enc);
}
return 2;
}
xmppipe_send_stanza(state, buf, n);
state->interval = 0;
return 3;
}
return 1;
}