diff --git a/include/sxt/socket.h b/include/sxt/socket.h index fb9e633..7584467 100644 --- a/include/sxt/socket.h +++ b/include/sxt/socket.h @@ -28,11 +28,13 @@ enum { SXTSOCKET_NIL = 0, SXTSOCKET_ACTIVE, SXTSOCKET_DEAD, + SXTSOCKET_CLOSED, }; #define SXTSCK_RDR (1 << 1) #define SXTSCK_WRR (1 << 2) #define SXTSCT_TMO (1 << 3) +#define SXTSCT_ERR (1 << 4) typedef struct __sxtsocket_type { uint8_t state; @@ -40,17 +42,18 @@ typedef struct __sxtsocket_type { } sxtsocket_t; /* API */ -sxtsocket_t *sxtsocket_new(); +sxtsocket_t *sxtsocket_new(void); int sxtsocket_close(sxtsocket_t *); int sxtsocket_setnb(sxtsocket_t *); -size_t sxtsocket_read(sxtsocket_t *, void *, size_t); +ssize_t sxtsocket_read(sxtsocket_t *, void *, size_t); -size_t sxtsocket_write(sxtsocket_t *, void *, size_t); +ssize_t sxtsocket_write(sxtsocket_t *, void *, size_t); -int sxtsocket_poll(sxtsocket_t **, int, sxtsocket_t **, int, void *); +int sxtsocket_poll(sxtsocket_t **, int, sxtsocket_t **, int, int, int **, + int **); void sxtsocket_free(sxtsocket_t *); diff --git a/sxt/Makefile.am b/sxt/Makefile.am index 6debbc9..f9f6d9c 100644 --- a/sxt/Makefile.am +++ b/sxt/Makefile.am @@ -16,7 +16,8 @@ lib_LTLIBRARIES = libsxt.la libsxt_la_SOURCES = \ core.c base64.c misc.c safebuffer.c rdb.c ppkp_ops.c \ bcrypt.c blowfish.c ciphers.c lcrypt.c \ - fe25519.c ge25519.c sc25519.c ed25519.c + fe25519.c ge25519.c sc25519.c ed25519.c \ + socket.c libsxt_la_LDFLAGS = diff --git a/sxt/socket.c b/sxt/socket.c new file mode 100644 index 0000000..71134ca --- /dev/null +++ b/sxt/socket.c @@ -0,0 +1,191 @@ +/* + * Secure eXtended Message Passing framework + * Secure eXtended Transport layer implementation (libsxt). + * + * socket wrapper + * + * (c) Alexander Vdolainen 2016 + * + * 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 3 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 ."; + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +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; +}