mirror of
https://repo.or.cz/socat.git
synced 2024-12-22 15:32:35 +00:00
Align buffer for read() with flag O_DIRECT
This commit is contained in:
parent
de2f2c471b
commit
55518fa690
7 changed files with 124 additions and 34 deletions
6
CHANGES
6
CHANGES
|
@ -21,6 +21,12 @@ Corrections:
|
|||
Mitigated race condition of quickly terminating SYSTEM or EXEC child
|
||||
processes.
|
||||
|
||||
Option o-direct might require alignment of read/write buffer to, e.g.,
|
||||
512 bytes, Socat now takes care of this when allocating the buffer.
|
||||
With this fix read() succeeds, however, write() still might fail when
|
||||
not writing complete pages.
|
||||
Test: O_DIRECT
|
||||
|
||||
Porting:
|
||||
In gcc version 10 the default changed from -fcommon to -fno-common.
|
||||
Consequently, linking filan and procan failed with error
|
||||
|
|
|
@ -69,6 +69,9 @@
|
|||
/* Define if you have the socket function. */
|
||||
#undef HAVE_SOCKET
|
||||
|
||||
/* Define if you have the posix_memalign function. */
|
||||
#undef HAVE_PROTOTYPE_LIB_posix_memalign
|
||||
|
||||
/* Define if you have the strdup function. */
|
||||
#undef HAVE_PROTOTYPE_LIB_strdup
|
||||
|
||||
|
|
|
@ -785,6 +785,7 @@ AC_CHECK_FUNCS(cfsetispeed cfgetispeed cfsetospeed cfgetospeed)
|
|||
###################################
|
||||
# check for prototype and existence of functions that return a pointer
|
||||
# defines in config.h: HAVE_PROTOTYPE_LIB_$1
|
||||
AC_CHECK_PROTOTYPE_LIB(posix_memalign)
|
||||
AC_CHECK_PROTOTYPE_LIB(strdup)
|
||||
AC_CHECK_PROTOTYPE_LIB(strerror)
|
||||
AC_CHECK_PROTOTYPE_LIB(strstr)
|
||||
|
@ -794,7 +795,6 @@ AC_CHECK_PROTOTYPE_LIB(memrchr)
|
|||
AC_CHECK_PROTOTYPE_LIB(if_indextoname)
|
||||
AC_CHECK_PROTOTYPE_LIB(ptsname)
|
||||
|
||||
|
||||
AC_MSG_CHECKING(for long long)
|
||||
AC_CACHE_VAL(sc_cv_type_longlong,
|
||||
[AC_TRY_COMPILE([],[long long s;],
|
||||
|
|
77
socat.c
77
socat.c
|
@ -57,7 +57,7 @@ void socat_opt_hint(FILE *fd, char a, char b);
|
|||
void socat_version(FILE *fd);
|
||||
int socat(const char *address1, const char *address2);
|
||||
int _socat(void);
|
||||
int cv_newline(unsigned char **buff, ssize_t *bytes, int lineterm1, int lineterm2);
|
||||
int cv_newline(unsigned char *buff, ssize_t *bytes, int lineterm1, int lineterm2);
|
||||
void socat_signal(int sig);
|
||||
static int socat_sigchild(struct single *file);
|
||||
|
||||
|
@ -708,7 +708,7 @@ int childleftdata(xiofile_t *xfd) {
|
|||
}
|
||||
|
||||
int xiotransfer(xiofile_t *inpipe, xiofile_t *outpipe,
|
||||
unsigned char **buff, size_t bufsiz, bool righttoleft);
|
||||
unsigned char *buff, size_t bufsiz, bool righttoleft);
|
||||
|
||||
bool mayrd1; /* sock1 has read data or eof, according to poll() */
|
||||
bool mayrd2; /* sock2 has read data or eof, according to poll() */
|
||||
|
@ -765,8 +765,21 @@ int _socat(void) {
|
|||
Error2("buffer size option (-b) to big - "F_Zu" (max is "F_Zu")", socat_opts.bufsiz, (SIZE_MAX-1)/2);
|
||||
socat_opts.bufsiz = (SIZE_MAX-1)/2;
|
||||
}
|
||||
|
||||
#if HAVE_PROTOTYPE_LIB_posix_memalign
|
||||
/* Operations on files with flag O_DIRECT might need buffer alignment.
|
||||
Without this, eg.read() fails with "Invalid argument" */
|
||||
{
|
||||
int _errno;
|
||||
if ((_errno = Posix_memalign((void **)&buff, getpagesize(), 2*socat_opts.bufsiz+1)) != 0) {
|
||||
Error1("posix_memalign(): %s", strerror(_errno));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
#else /* !HAVE_PROTOTYPE_LIB_posix_memalign */
|
||||
buff = Malloc(2*socat_opts.bufsiz+1);
|
||||
if (buff == NULL) return -1;
|
||||
#endif /* !HAVE_PROTOTYPE_LIB_posix_memalign */
|
||||
|
||||
if (socat_opts.logopt == 'm' && xioinqopt('l', NULL, 0) == 'm') {
|
||||
Info("switching to syslog");
|
||||
|
@ -988,7 +1001,7 @@ int _socat(void) {
|
|||
|
||||
if (mayrd1 && maywr2) {
|
||||
mayrd1 = false;
|
||||
if ((bytes1 = xiotransfer(sock1, sock2, &buff, socat_opts.bufsiz, false))
|
||||
if ((bytes1 = xiotransfer(sock1, sock2, buff, socat_opts.bufsiz, false))
|
||||
< 0) {
|
||||
if (errno != EAGAIN) {
|
||||
closing = MAX(closing, 1);
|
||||
|
@ -1020,7 +1033,7 @@ int _socat(void) {
|
|||
|
||||
if (mayrd2 && maywr1) {
|
||||
mayrd2 = false;
|
||||
if ((bytes2 = xiotransfer(sock2, sock1, &buff, socat_opts.bufsiz, true))
|
||||
if ((bytes2 = xiotransfer(sock2, sock1, buff, socat_opts.bufsiz, true))
|
||||
< 0) {
|
||||
if (errno != EAGAIN) {
|
||||
closing = MAX(closing, 1);
|
||||
|
@ -1106,7 +1119,7 @@ int _socat(void) {
|
|||
xioclose(sock1);
|
||||
xioclose(sock2);
|
||||
|
||||
free(buff);
|
||||
free(buff);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1194,10 +1207,10 @@ static int
|
|||
*/
|
||||
/* inpipe, outpipe must be single descriptors (not dual!) */
|
||||
int xiotransfer(xiofile_t *inpipe, xiofile_t *outpipe,
|
||||
unsigned char **buff, size_t bufsiz, bool righttoleft) {
|
||||
unsigned char *buff, size_t bufsiz, bool righttoleft) {
|
||||
ssize_t bytes, writt = 0;
|
||||
|
||||
bytes = xioread(inpipe, *buff, bufsiz);
|
||||
bytes = xioread(inpipe, buff, bufsiz);
|
||||
if (bytes < 0) {
|
||||
if (errno != EAGAIN)
|
||||
XIO_RDSTREAM(inpipe)->eof = 2;
|
||||
|
@ -1215,7 +1228,7 @@ int xiotransfer(xiofile_t *inpipe, xiofile_t *outpipe,
|
|||
/* handle escape char */
|
||||
if (XIO_RDSTREAM(inpipe)->escape != -1) {
|
||||
/* check input data for escape char */
|
||||
unsigned char *ptr = *buff;
|
||||
unsigned char *ptr = buff;
|
||||
size_t ctr = 0;
|
||||
while (ctr < bytes) {
|
||||
if (*ptr == XIO_RDSTREAM(inpipe)->escape) {
|
||||
|
@ -1251,8 +1264,8 @@ int xiotransfer(xiofile_t *inpipe, xiofile_t *outpipe,
|
|||
size_t j;
|
||||
size_t N = 16;
|
||||
const unsigned char *end, *s, *t;
|
||||
s = *buff;
|
||||
end = (*buff)+bytes;
|
||||
s = buff;
|
||||
end = buff+bytes;
|
||||
xioprintblockheader(stderr, bytes, righttoleft);
|
||||
while (s < end) {
|
||||
/*! prefix? */
|
||||
|
@ -1298,8 +1311,8 @@ int xiotransfer(xiofile_t *inpipe, xiofile_t *outpipe,
|
|||
size_t i = 0;
|
||||
xioprintblockheader(stderr, bytes, righttoleft);
|
||||
while (i < (size_t)bytes) {
|
||||
int c = (*buff)[i];
|
||||
if (i > 0 && (*buff)[i-1] == '\n')
|
||||
int c = buff[i];
|
||||
if (i > 0 && buff[i-1] == '\n')
|
||||
/*! prefix? */;
|
||||
switch (c) {
|
||||
case '\a' : fputs("\\a", stderr); break;
|
||||
|
@ -1323,12 +1336,12 @@ int xiotransfer(xiofile_t *inpipe, xiofile_t *outpipe,
|
|||
/* print prefix */
|
||||
xioprintblockheader(stderr, bytes, righttoleft);
|
||||
for (i = 0; i < bytes; ++i) {
|
||||
fprintf(stderr, " %02x", (*buff)[i]);
|
||||
fprintf(stderr, " %02x", buff[i]);
|
||||
}
|
||||
fputc('\n', stderr);
|
||||
}
|
||||
|
||||
writt = xiowrite(outpipe, *buff, bytes);
|
||||
writt = xiowrite(outpipe, buff, bytes);
|
||||
if (writt < 0) {
|
||||
/* EAGAIN when nonblocking but a mandatory lock is on file.
|
||||
the problem with EAGAIN is that the read cannot be repeated,
|
||||
|
@ -1355,11 +1368,9 @@ int xiotransfer(xiofile_t *inpipe, xiofile_t *outpipe,
|
|||
/* converts the newline characters (or character sequences) from the one
|
||||
specified in lineterm1 to that of lineterm2. Possible values are
|
||||
LINETERM_CR, LINETERM_CRNL, LINETERM_RAW.
|
||||
buff points to the malloc()'ed data, input and output. It may be subject to
|
||||
realloc(). bytes specifies the number of bytes input and output */
|
||||
int cv_newline(unsigned char **buff, ssize_t *bufsiz,
|
||||
bytes specifies the number of bytes input and output */
|
||||
int cv_newline(unsigned char *buff, ssize_t *bytes,
|
||||
int lineterm1, int lineterm2) {
|
||||
ssize_t *bytes = bufsiz;
|
||||
/* must perform newline changes */
|
||||
if (lineterm1 <= LINETERM_CR && lineterm2 <= LINETERM_CR) {
|
||||
/* no change in data length */
|
||||
|
@ -1369,23 +1380,23 @@ int cv_newline(unsigned char **buff, ssize_t *bufsiz,
|
|||
} else {
|
||||
from = '\r'; to = '\n';
|
||||
}
|
||||
z = *buff + *bytes;
|
||||
p = *buff;
|
||||
z = buff + *bytes;
|
||||
p = buff;
|
||||
while (p < z) {
|
||||
if (*p == from) *p = to;
|
||||
++p;
|
||||
}
|
||||
|
||||
} else if (lineterm1 == LINETERM_CRNL) {
|
||||
/* buffer becomes shorter */
|
||||
/* buffer might become shorter */
|
||||
unsigned char to, *s, *t, *z;
|
||||
if (lineterm2 == LINETERM_RAW) {
|
||||
to = '\n';
|
||||
} else {
|
||||
to = '\r';
|
||||
}
|
||||
z = *buff + *bytes;
|
||||
s = t = *buff;
|
||||
z = buff + *bytes;
|
||||
s = t = buff;
|
||||
while (s < z) {
|
||||
if (*s == '\r') {
|
||||
++s;
|
||||
|
@ -1397,20 +1408,24 @@ int cv_newline(unsigned char **buff, ssize_t *bufsiz,
|
|||
*t++ = *s++;
|
||||
}
|
||||
}
|
||||
*bufsiz = t - *buff;
|
||||
*bytes = t - buff;
|
||||
} else {
|
||||
/* buffer becomes longer, must alloc another space */
|
||||
unsigned char *buf2;
|
||||
/* buffer becomes longer (up to double length), must alloc another space */
|
||||
static unsigned char *buf2; /*! not threadsafe */
|
||||
unsigned char from; unsigned char *s, *t, *z;
|
||||
|
||||
if (lineterm1 == LINETERM_RAW) {
|
||||
from = '\n';
|
||||
} else {
|
||||
from = '\r';
|
||||
}
|
||||
if ((buf2 = Malloc(2*socat_opts.bufsiz/*sic!*/+1)) == NULL) {
|
||||
return -1;
|
||||
if (buf2 == NULL) {
|
||||
if ((buf2 = Malloc(socat_opts.bufsiz)) == NULL) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
s = *buff; t = buf2; z = *buff + *bytes;
|
||||
memcpy(buf2, buff, *bytes);
|
||||
s = buf2; t = buff; z = buf2 + *bytes;
|
||||
while (s < z) {
|
||||
if (*s == from) {
|
||||
*t++ = '\r'; *t++ = '\n';
|
||||
|
@ -1420,9 +1435,7 @@ int cv_newline(unsigned char **buff, ssize_t *bufsiz,
|
|||
*t++ = *s++;
|
||||
}
|
||||
}
|
||||
free(*buff);
|
||||
*buff = buf2;
|
||||
*bufsiz = t - buf2;;
|
||||
*bytes = t - buff;;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
10
sycls.c
10
sycls.c
|
@ -23,6 +23,16 @@
|
|||
|
||||
#if WITH_SYCLS
|
||||
|
||||
#if HAVE_PROTOTYPE_LIB_posix_memalign
|
||||
int Posix_memalign(void **memptr, size_t alignment, size_t size) {
|
||||
int result;
|
||||
Debug3("posix_memalign(%p, "F_Zu", F_Zu)", memptr, alignment, size);
|
||||
result = posix_memalign(memptr, alignment, size);
|
||||
Debug1("posix_memalign(...) -> %d", result);
|
||||
return result;
|
||||
}
|
||||
#endif /* HAVE_PROTOTYPE_LIB_posix_memalign */
|
||||
|
||||
mode_t Umask(mode_t mask) {
|
||||
mode_t result;
|
||||
int _errno;
|
||||
|
|
2
sycls.h
2
sycls.h
|
@ -11,6 +11,7 @@ struct utsname;
|
|||
struct flock;
|
||||
struct addrinfo;
|
||||
|
||||
int Posix_memalign(void **memptr, size_t alignment, size_t size);
|
||||
mode_t Umask(mode_t mask);
|
||||
#endif /* WITH_SYCLS */
|
||||
int Open(const char *pathname, int flags, mode_t mode);
|
||||
|
@ -175,6 +176,7 @@ void Add_history(const char *string);
|
|||
|
||||
#else /* !WITH_SYCLS */
|
||||
|
||||
#define Posix_memalign(m,a,s) posix_memalign(m,a,s)
|
||||
#define Umask(m) umask(m)
|
||||
#define Creat(p,m) creat(p,m)
|
||||
#define Lseek(f,o,w) lseek(f,o,w)
|
||||
|
|
58
test.sh
58
test.sh
|
@ -13614,7 +13614,7 @@ NAME=SCTP_SERVICENAME
|
|||
case "$TESTS" in
|
||||
*%$N%*|*%functions%*|*%socket%*|*%sctp%*|*%$NAME%*)
|
||||
TEST="$NAME: Service name resolution works with SCTP"
|
||||
# invoke socat with address SCTP4-CONNECT:$LOCALHOST:http; when this does fails with
|
||||
# invoke socat with address SCTP4-CONNECT:$LOCALHOST:http; when this fails with
|
||||
# "Connection refused", or does not fail at all, the test succeeded
|
||||
if ! eval $NUMCOND; then :;
|
||||
elif ! runssctp4 "$((PORT))" >/dev/null; then
|
||||
|
@ -13647,6 +13647,62 @@ esac
|
|||
N=$((N+1))
|
||||
|
||||
|
||||
# Test the o-direct option on reading
|
||||
NAME=O_DIRECT
|
||||
case "$TESTS" in
|
||||
*%$N%*|*%functions%*|*%engine%*|*%file%*|*%$NAME%*)
|
||||
TEST="$NAME: echo via file with o-direct"
|
||||
# Write data to a file and read it with options o-direct (and ignoreeof)
|
||||
# When the data read is the same as the data written the test succeeded.
|
||||
if ! eval $NUMCOND; then :;
|
||||
elif ! testoptions o-direct >/dev/null; then
|
||||
$PRINTF "test $F_n $TEST... ${YELLOW}o-direct not available${NORMAL}\n" $N
|
||||
numCANT=$((numCANT+1))
|
||||
listCANT="$listCANT $N"
|
||||
else
|
||||
tf="$td/test$N.file"
|
||||
to="$td/test$N.stdout"
|
||||
te="$td/test$N.stderr"
|
||||
tdiff="$td/test$N.diff"
|
||||
da="test$N $(date) $RANDOM"
|
||||
$PRINTF "test $F_n $TEST... " $N
|
||||
CMD="$TRACE $SOCAT $opts - $tf,o-direct,ignoreeof!!$tf"
|
||||
echo "$da" |$CMD >"$to" 2>"$te"
|
||||
rc=$?
|
||||
if [ $rc -ne 0 ] && grep -q "Invalid argument" "$te" && [ $UNAME = Linux ]; then
|
||||
case $(stat -f /tmp/gerhard/ |grep -o "Type: [^[:space:]]*" |cut -c 7-) in
|
||||
ext2/ext3|xfs|reiserfs)
|
||||
$PRINTF "${FAILED}\n"
|
||||
echo "$CMD" >&2
|
||||
cat "$te" >&2
|
||||
numFAIL=$((numFAIL+1))
|
||||
listFAIL="$listFAIL $N" ;;
|
||||
*) $PRINTF "${YELLOW}inable file system${NORMAL}\n"
|
||||
numCANT=$((numCANT+1))
|
||||
listCANT="$listCANT $N" ;;
|
||||
esac
|
||||
elif [ $rc -ne 0 ]; then
|
||||
$PRINTF "${FAILED}:\n"
|
||||
echo "$CMD" >&2
|
||||
cat "$te" >&2
|
||||
numFAIL=$((numFAIL+1))
|
||||
listFAIL="$listFAIL $N"
|
||||
elif ! echo "$da" |diff - "$to" >$tdiff; then
|
||||
$PRINTF "${FAILED}\n"
|
||||
echo "$CMD" >&2
|
||||
cat "$te" >&2
|
||||
cat "$tdiff" >&2
|
||||
numFAIL=$((numFAIL+1))
|
||||
listFAIL="$listFAIL $N"
|
||||
else
|
||||
$PRINTF "$OK\n"
|
||||
numOK=$((numOK+1))
|
||||
fi # command ok
|
||||
fi ;; # NUMCOND, feats
|
||||
esac
|
||||
N=$((N+1))
|
||||
|
||||
|
||||
##################################################################################
|
||||
#=================================================================================
|
||||
# here come tests that might affect your systems integrity. Put normal tests
|
||||
|
|
Loading…
Reference in a new issue