You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
libsxmp/sxt/socket.c

192 lines
4.3 KiB
C

/*
* Secure eXtended Message Passing framework
* Secure eXtended Transport layer implementation (libsxt).
*
* socket wrapper
*
* (c) Alexander Vdolainen 2016 <avdolainen@zoho.com>
*
* libsxmp is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation, either version 2.1 of the License, or
* (at your option) any later version.
*
* libsxmp is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.";
*
*/
#include <stdint.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <string.h>
#include <poll.h>
#include <sxt/errno.h>
#include <sxt/socket.h>
sxtsocket_t *sxtsocket_new(void)
{
sxtsocket_t *s = malloc(sizeof(sxtsocket_t));
if(!s) return NULL;
s->state = SXTSOCKET_NIL;
return s;
}
int sxtsocket_close(sxtsocket_t *s)
{
if(!s) return SXT_EINVAL;
if(s->state == SXTSOCKET_ACTIVE || s->state == SXTSOCKET_DEAD) {
close(s->fd);
s->state = SXTSOCKET_CLOSED;
}
/* in other cases ignore, already closed or never opened */
return SXT_SUCCESS;
}
int sxtsocket_setnb(sxtsocket_t *s)
{
#ifndef WIN32
int fdmode;
#endif
if(!s || s->state != SXTSOCKET_ACTIVE) return SXT_EINVAL;
#ifndef WIN32
fdmode = fcntl(s->fd, F_GETFL, 0);
fdmode |= O_NDELAY;
if(fcntl(s->fd, F_SETFL, fdmode)) return SXT_EIO;
#endif
return SXT_SUCCESS;
}
ssize_t sxtsocket_read(sxtsocket_t *s, void *buf, size_t bufsize)
{
ssize_t rcnt = -1;
if(!s || s->state != SXTSOCKET_ACTIVE) goto __failed;
rcnt = read(s->fd, buf, bufsize);
__failed:
return rcnt;
}
ssize_t sxtsocket_write(sxtsocket_t *s, void *buf, size_t bufsize)
{
ssize_t wcnt = -1;
if(!s || s->state != SXTSOCKET_ACTIVE) goto __failed;
wcnt = write(s->fd, (const void *)buf, bufsize);
__failed:
return wcnt;
}
int sxtsocket_poll(sxtsocket_t **rsck, int rscksz, sxtsocket_t **wsck,
int wscksz, int tm_msec, int **ra, int **wa)
{
int r = 0, i = 0, err = SXTSCT_ERR, c, ii;
struct pollfd *fds = NULL;
int *rr = NULL, *wr = NULL;
if(!rsck || !wsck) return SXTSCT_ERR;
if(!rscksz || !wscksz) return SXTSCT_ERR;
if(!(fds = malloc(sizeof(struct pollfd)*(rscksz + wscksz)))) return SXTSCT_ERR;
else memset(fds, 0, sizeof(struct pollfd)*(rscksz + wscksz));
/* fill and check given values */
for(i = 0; i < rscksz; i++) {
if(rsck[i]->state != SXTSOCKET_ACTIVE) goto __failed;
fds[i].fd = rsck[i]->fd;
fds[i].events = POLLIN | POLLPRI;
}
for(; i < rscksz + wscksz; i++) {
if(wsck[i - rscksz]->state != SXTSOCKET_ACTIVE) goto __failed;
fds[i].fd = wsck[i - rscksz]->fd;
fds[i].events = POLLOUT;
}
r = poll(fds, rscksz + wscksz, tm_msec);
if(!r) {
err = SXTSCT_TMO;
goto __failed;
} else if(r < 0) goto __failed;
for(i = 0, c = 0; i < rscksz; i++) {
if(fds[i].revents) {
if((fds[i].revents & POLLHUP) || (fds[i].revents & POLLERR))
rsck[i]->state = SXTSOCKET_DEAD;
c++;
}
}
if(c) {
if(!(rr = malloc(sizeof(int)*(c + 1)))) {
err = SXTSCT_ERR;
goto __failed;
}
for(i = 0, ii = 0; i < rscksz; i++) {
if(fds[i].revents) {
rr[ii] = i;
ii++;
}
}
rr[ii] = -1;
err = 0;
err |= SXTSCK_RDR;
}
if((r - c) > 0) {
r -= c;
if(!(wr = malloc(sizeof(int)*(r + 1)))) {
err = SXTSCT_ERR;
goto __failed;
}
for(i = rscksz, ii = 0; i < (rscksz + wscksz); i++) {
if(fds[i].revents) {
if((fds[i].revents & POLLHUP) || (fds[i].revents & POLLERR))
wsck[i - rscksz]->state = SXTSOCKET_DEAD;
wr[ii] = i - rscksz;
ii++;
}
}
wr[ii] = -1;
if(err == SXTSCT_ERR) err = 0;
err |= SXTSCK_WRR;
}
r = 0;
__failed:
if(fds) free(fds);
if(r > 0 && err == SXTSCT_ERR) {
if(rr) free(rr);
if(wr) free(wr);
}
return err;
}
void sxtsocket_free(sxtsocket_t *s)
{
if(!s) return;
else sxtsocket_close(s);
free(s);
return;
}