7

I am using socat to intercept UDP messages and send them to a named pipe:

socat UDP-LISTEN:9999,fork PIPE:/tmp/mypipe,append

I am able to tail this pipe and see all the messages it receives.

I would like to pipe the output of tail -f /tmp/mypipe to sed to do some post-processing of the messages, but unfortunately some of them are not newline-terminated. This is a problem because it means multiple distinct UDP messages could be on the same line, and also because tail -f /tmp/mypipe | sed ... does not pass the last line if it is unterminated.

Ideally I would like to be able to add a custom message delimiter as they are sent to my pipe, so that I can easily find the message boundaries. If that's not possible then is there some way I can follow this file and pipe the final (potentially unterminated) line to another program for post-processing?

abc
  • 73
  • 5
  • I was able to get closer to my goal, though it's not perfect. Neither `UDP-LISTEN` nor `UDP-RECV` seemed to work -- when I tried to execute a system command to echo a trailing newline it appears they would hang on `cat;`. Using `UDP-RECVFROM` like so seems to work: `socat -u UDP-RECVFROM:9999,fork SYSTEM:"cat; echo \"\n\""` – abc Jul 27 '18 at 22:21
  • The solution in my comment above appears to suffer from a race condition -- since the receives are forked (as they have to be, else `socat` exits after the first UDP message) the `SYSTEM` commands are not executed atomically. I noticed the `cat` and `echo` getting interleaved when multiple messages came in at the same time. I serialized it by wrapping it in a lock like this: `socat -u UDP-RECVFROM:9999,fork SYSTEM:"(flock -x 200; cat; echo \"\n\";) 200>./udplockfile"` – abc Jul 27 '18 at 22:43

2 Answers2

3

One possibility that does not involve forking is to use the socat verbose output rather than the data. My version of socat -v includes the length of the data in the verbose output, so you know where it ends. For example,

mkfifo mypipe
while sleep 3
do    printf "%sNONEWLINE" $RANDOM
done |
socat -u - UDP4:localhost:9999  &
socat -u -v UDP-RECV:9999 - >/dev/null 2>mypipe  &
cat -uv mypipe

will output before each data item (eg 9430NONEWLINE) a header starting > with the date and a length.

> 2018/07/28 10:29:33.965222  length=13 from=0 to=12
9430NONEWLINE> 2018/07/28 10:29:36.968335  length=14 from=13 to=26
26947NONEWLINE> 2018/07/28 10:29:39.971025  length=14 from=27 to=40
15126NONEWLINE
meuh
  • 49,672
  • 2
  • 52
  • 114
2

Use sed, which can append new line with a single command, to avoid the race condition when using SYSTEM:"cat; echo \"\n\"" output:

socat -u UDP-RECVFROM:9999,fork SYSTEM:"sed -e a\\\\"

ReeseWang
  • 73
  • 6