X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ian/git?p=secnet.git;a=blobdiff_plain;f=util.c;h=3ae5ff4612447e4388a31e2222ac2340c6327cbb;hp=426fc69c1a9e922931c52c23d88377dbcf743f1d;hb=c921f0c57414017ae53f7a14513e8f2188d4a61e;hpb=61dbc9e060153651a0d4eecac5a5fab1c36fa530 diff --git a/util.c b/util.c index 426fc69..3ae5ff4 100644 --- a/util.c +++ b/util.c @@ -40,6 +40,7 @@ #include "util.h" #include "unaligned.h" #include "magic.h" +#include "ipaddr.h" #define MIN_BUFFER_SIZE 64 #define DEFAULT_BUFFER_SIZE 4096 @@ -70,17 +71,30 @@ char *safe_strdup(const char *s, const char *message) void *safe_malloc(size_t size, const char *message) { void *r; + if (!size) + return 0; r=malloc(size); if (!r) { fatal_perror("%s",message); } return r; } -void *safe_malloc_ary(size_t size, size_t count, const char *message) { +void *safe_realloc_ary(void *p, size_t size, size_t count, + const char *message) { if (count >= INT_MAX/size) { fatal("array allocation overflow: %s", message); } - return safe_malloc(size*count, message); + assert(size && count); + p = realloc(p, size*count); + if (!p) + fatal_perror("%s", message); + return p; +} + +void *safe_malloc_ary(size_t size, size_t count, const char *message) { + if (!size || !count) + return 0; + return safe_realloc_ary(0,size,count,message); } /* Convert a buffer into its MP_INT representation */ @@ -163,13 +177,17 @@ int32_t write_mpbin(MP_INT *a, uint8_t *buffer, int32_t buflen) return i; } -void setcloexec(int fd) { - int r=fcntl(fd, F_GETFD); - if (r<0) fatal_perror("fcntl(,F_GETFD) failed"); - r=fcntl(fd, F_SETFD, r|FD_CLOEXEC); - if (r<0) fatal_perror("fcntl(,F_SETFD,|FD_CLOEXEC) failed"); +#define DEFINE_SETFDFLAG(fn,FL,FLAG) \ +void fn(int fd) { \ + int r=fcntl(fd, F_GET##FL); \ + if (r<0) fatal_perror("fcntl(,F_GET" #FL ") failed"); \ + r=fcntl(fd, F_SET##FL, r|FLAG); \ + if (r<0) fatal_perror("fcntl(,F_SET" #FL ",|" #FLAG ") failed"); \ } +DEFINE_SETFDFLAG(setcloexec,FD,FD_CLOEXEC); +DEFINE_SETFDFLAG(setnonblock,FL,O_NONBLOCK); + void pipe_cloexec(int fd[2]) { int r=pipe(fd); if (r) fatal_perror("pipe"); @@ -478,6 +496,29 @@ extern void slilog_part(struct log_if *lf, int priority, const char *message, .. va_end(ap); } +void string_item_to_iaddr(const item_t *item, uint16_t port, union iaddr *ia, + const char *desc) +{ +#ifndef CONFIG_IPV6 + + ia->sin.sin_family=AF_INET; + ia->sin.sin_addr.s_addr=string_item_to_ipaddr(item,desc); + +#else /* CONFIG_IPV6 => we have adns_text2addr */ + + if (item->type!=t_string) + cfgfatal(item->loc,desc,"expecting a string IP (v4 or v6) address\n"); + socklen_t salen=sizeof(*ia); + int r=adns_text2addr(item->data.string, port, + adns_qf_addrlit_ipv4_quadonly, + &ia->sa, &salen); + assert(r!=ENOSPC); + if (r) cfgfatal(item->loc,desc,"invalid IP (v4 or v6) address: %s\n", + strerror(r)); + +#endif /* CONFIG_IPV6 */ +} + #define IADDR_NBUFS_SHIFT 3 #define IADDR_NBUFS (1 << IADDR_NBUFS_SHIFT) @@ -557,3 +598,89 @@ int iaddr_socklen(const union iaddr *ia) default: abort(); } } + +enum async_linebuf_result +async_linebuf_read(struct pollfd *pfd, struct buffer_if *buf, + const char **emsg_out) +{ + int revents=pfd->revents; + +#define BAD(m) do{ *emsg_out=(m); return async_linebuf_broken; }while(0) +#define BADBIT(b) \ + if (!(revents & b)) ; else BAD(#b) + BADBIT(POLLERR); + BADBIT(POLLHUP); + /* POLLNVAL is handled by the event loop - see afterpoll_fn comment */ +#undef BADBIT + + if (!(revents & POLLIN)) + return async_linebuf_nothing; + + /* + * Data structure: A line which has been returned to the user is + * stored in buf at base before start. But we retain the usual + * buffer meaning of size. So: + * + * | returned : | input read, | unused | + * | to user : \0 | awaiting | buffer | + * | : | processing | space | + * | : | | | + * ^base ^start ^start+size ^base+alloclen + */ + + BUF_ASSERT_USED(buf); + + /* firstly, eat any previous */ + if (buf->start != buf->base) { + memmove(buf->base,buf->start,buf->size); + buf->start=buf->base; + } + + uint8_t *searched=buf->base; + + /* + * During the workings here we do not use start. We set start + * when we return some actual data. So we have this: + * + * | searched | read, might | unused | + * | for \n | contain \n | buffer | + * | none found | but not \0 | space | + * | | | | + * ^base ^searched ^base+size ^base+alloclen + * [^start] ^dataend + * + */ + for (;;) { + uint8_t *dataend=buf->base+buf->size; + char *newline=memchr(searched,'\n',dataend-searched); + if (newline) { + *newline=0; + buf->start=newline+1; + buf->size=dataend-buf->start; + return async_linebuf_ok; + } + searched=dataend; + ssize_t space=(buf->base+buf->alloclen)-dataend; + if (!space) BAD("input line too long"); + ssize_t r=read(pfd->fd,searched,space); + if (r==0) { + *searched=0; + *emsg_out=buf->size?"no newline at eof":0; + buf->start=searched+1; + buf->size=0; + return async_linebuf_eof; + } + if (r<0) { + if (errno==EINTR) + continue; + if (iswouldblock(errno)) + return async_linebuf_nothing; + BAD(strerror(errno)); + } + assert(r<=space); + if (memchr(searched,0,r)) BAD("nul in input data"); + buf->size+=r; + } + +#undef BAD +}