just trying to compile TPM-Emulator under Ubuntu 32 bit.
Setting export ARCH=i386, having
tomasz#tomasz-VirtualBox:~/Git$ find /usr/include -name socket.h
/usr/include/asm-generic/socket.h
/usr/include/linux/socket.h
/usr/include/i386-linux-gnu/asm/socket.h
/usr/include/i386-linux-gnu/sys/socket.h
/usr/include/i386-linux-gnu/bits/socket.h
I get similiar errors
[ 98%] Generating linux/tpmd_dev.ko
/home/tomasz/Git/tpm-emulator/build/tpmd_dev/linux/tpmd_dev.c: In function ‘tpmd_handle_command’:
/home/tomasz/Git/tpm-emulator/build/tpmd_dev/linux/tpmd_dev.c:111:6: error: ‘struct msghdr’ has no member named ‘msg_iov’
msg.msg_iov = &iov;
^
EDIT: There is a TPM 2.0 compliant TPM Simulator by IBM, here
In the git repo, that you linked a user made a pull request for a fix to your problem. This worked for me (there are some whitespace fixes that I didn't use. If the patch makes problems just make the changes by hand).
--- tpmd_dev.c 2016-01-10 16:36:21.964858503 +0100
+++ tpmd_dev.c 2016-01-10 16:37:09.377204027 +0100
## -25,6 +25,8 ##
#include <linux/net.h>
#include <linux/un.h>
+#include <linux/version.h>
+
#include "config.h"
#define TPM_DEVICE_MINOR 224
## -81,7 +83,7 ##
}
addr.sun_family = AF_UNIX;
strncpy(addr.sun_path, socket_name, sizeof(addr.sun_path));
- res = tpmd_sock->ops->connect(tpmd_sock,
+ res = tpmd_sock->ops->connect(tpmd_sock,
(struct sockaddr*)&addr, sizeof(struct sockaddr_un), 0);
if (res != 0) {
error("sock_connect() failed: %d\n", res);
## -108,9 +110,17 ##
memset(&msg, 0, sizeof(msg));
iov.iov_base = (void*)in;
iov.iov_len = in_size;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,19,0)
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
+#else
+ iov_iter_init(&msg.msg_iter, WRITE, &iov, 1, 1);
+#endif
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4,1,0)
res = sock_sendmsg(tpmd_sock, &msg, in_size);
+#else
+ res = sock_sendmsg(tpmd_sock, &msg);
+#endif
if (res < 0) {
error("sock_sendmsg() failed: %d\n", res);
return res;
## -122,8 +132,12 ##
memset(&msg, 0, sizeof(msg));
iov.iov_base = (void*)tpm_response.data;
iov.iov_len = tpm_response.size;
- msg.msg_iov = &iov;
- msg.msg_iovlen = 1;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,19,0)
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+#else
+ iov_iter_init(&msg.msg_iter, WRITE, &iov, 1, 1);
+#endif
oldmm = get_fs();
set_fs(KERNEL_DS);
res = sock_recvmsg(tpmd_sock, &msg, tpm_response.size, 0);
## -194,7 +208,7 ##
kfree(tpm_response.data);
tpm_response.data = NULL;
}
- if (tpmd_handle_command(buf, count) != 0) {
+ if (tpmd_handle_command(buf, count) != 0) {
count = -EILSEQ;
tpm_response.data = NULL;
}
## -241,8 +255,8 ##
};
static struct miscdevice tpm_dev = {
- .minor = TPM_DEVICE_MINOR,
- .name = TPM_DEVICE_ID,
+ .minor = TPM_DEVICE_MINOR,
+ .name = TPM_DEVICE_ID,
.fops = &fops,
};
Related
Hi I am trying to generate a 32bit hash for the full process name in ebpf. These process names can be long and will not fit on the stack hence the "heap" per cpu array. I am currently using libbpf bootstrap as a prototype from here: https://github.com/libbpf/libbpf-bootstrap.git I am having an issue with the verifier not validating the hash function. What is the problem here? I am stumped.
The meat of the code is:
uint32_t map_id = 0;
char *map_val = bpf_map_lookup_elem(&heap, &map_id);
if (!map_val)
return 0;
int bytes_read = bpf_probe_read_str(map_val, sizeof(e->filename), (void *)ctx + fname_off);
if (bytes_read > 0) {
map_val[ (bytes_read - 1) & (4096 -1) ] = 0;
uint32_t key = hash( (unsigned char*)map_val);
bpf_printk("process_exec count: %u, hash: %lu, full path: %s\n", bytes_read -1, key, map_val);
}
The hash function is:
uint32_t hash(unsigned char *str)
{
int c;
uint32_t hash = 5381;
while ( c = *str++ )
hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
return hash;
}
I get a validator error:
; hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
91: (27) r4 *= 33
; hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
92: (0f) r4 += r1
; while ( c = *str++ )
93: (71) r1 = *(u8 *)(r2 +0)
R0=inv(id=6,smin_value=-4096,smax_value=4095) R1_w=inv(id=0,umax_value=255,var_off=(0x0; 0xff)) R2_w=map_value(id=0,off=4096,ks=4,vs=4096,imm=0) R4_w=inv(id=0) R6=ctx(id=0,off=0,umax_value=65535,var_off=(0x0; 0xffff)) R7=map_value(id=0,off=0,ks=4,vs=4096,imm=0) R8=invP0 R10=fp0 fp-8=mmmm???? fp-16=mmmmmmmm fp-24=mmmm???? fp-32=mmmmmmmm
invalid access to map value, value_size=4096 off=4096 size=1
R2 min value is outside of the allowed memory range
processed 32861 insns (limit 1000000) max_states_per_insn 4 total_states 337 peak_states 337 mark_read 4
-- END PROG LOAD LOG --
libbpf: prog 'handle_exec': failed to load: -13
libbpf: failed to load object 'bootstrap_bpf'
libbpf: failed to load BPF skeleton 'bootstrap_bpf': -13
Failed to load and verify BPF skeleton
Here is the complete diff for my use case:
diff --git a/examples/c/bootstrap.bpf.c b/examples/c/bootstrap.bpf.c
index d0860c0..c93ed58 100644
--- a/examples/c/bootstrap.bpf.c
+++ b/examples/c/bootstrap.bpf.c
## -20,6 +20,13 ## struct {
__uint(max_entries, 256 * 1024);
} rb SEC(".maps");
+struct {
+ __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
+ __uint(key_size, sizeof(u32));
+ __uint(max_entries, 1);
+ __uint(value_size, 4096);
+} heap SEC(".maps");
+
const volatile unsigned long long min_duration_ns = 0;
SEC("tp/sched/sched_process_exec")
## -58,6 +65,22 ## int handle_exec(struct trace_event_raw_sched_process_exec *ctx)
/* successfully submit it to user-space for post-processing */
bpf_ringbuf_submit(e, 0);
+
+
+ uint32_t map_id = 0;
+ char *map_val = bpf_map_lookup_elem(&heap, &map_id);
+ if (!map_val)
+ return 0;
+
+ int bytes_read = bpf_probe_read_str(map_val, sizeof(e->filename), (void *)ctx + fname_off);
+ if (bytes_read > 0) {
+ // tell the validator bytes ready is between 0 and 4095
+ map_val[ (bytes_read - 1) & (4096 -1) ] = 0;
+
+ uint32_t key = hash( (unsigned char*)map_val);
+ bpf_printk("process_exec count: %u, hash: %u, full path: %s\n", bytes_read -1, key, map_val);
+ }
+
return 0;
}
## -109,4 +132,3 ## int handle_exit(struct trace_event_raw_sched_process_template* ctx)
bpf_ringbuf_submit(e, 0);
return 0;
}
-
diff --git a/examples/c/bootstrap.h b/examples/c/bootstrap.h
index b49e022..d268e56 100644
--- a/examples/c/bootstrap.h
+++ b/examples/c/bootstrap.h
## -4,7 +4,7 ##
#define __BOOTSTRAP_H
#define TASK_COMM_LEN 16
-#define MAX_FILENAME_LEN 127
+#define MAX_FILENAME_LEN 4096
struct event {
int pid;
## -16,4 +16,15 ## struct event {
bool exit_event;
};
+static inline
+uint32_t hash(unsigned char *str)
+{
+ int c;
+ uint32_t hash = 5381;
+ while ( c = *str++ )
+ hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
+
+ return hash;
+}
+
#endif /* __BOOTSTRAP_H */
TL;DR. You need to ensure that you are not reading past the end of the map value. So you need to check str never goes past the initial str value + 4095.
Verifier error explanation.
; while ( c = *str++ )
93: (71) r1 = *(u8 *)(r2 +0)
R0=inv(id=6,smin_value=-4096,smax_value=4095) R1_w=inv(id=0,umax_value=255,var_off=(0x0; 0xff)) R2_w=map_value(id=0,off=4096,ks=4,vs=4096,imm=0) R4_w=inv(id=0) R6=ctx(id=0,off=0,umax_value=65535,var_off=(0x0; 0xffff)) R7=map_value(id=0,off=0,ks=4,vs=4096,imm=0) R8=invP0 R10=fp0 fp-8=mmmm???? fp-16=mmmmmmmm fp-24=mmmm???? fp-32=mmmmmmmm
invalid access to map value, value_size=4096 off=4096 size=1
R2 min value is outside of the allowed memory range
The verifier here is telling you that your code may attempt to read one byte (size=1) from the map value, at offset 4096 (off=4096). Since the map value has a size of 4096 (value_size=4096), that would end up reading after the end of the map value, leading to an unbounded memory access. Hence, the verifier rejects it.
I am working on websocket implementation on client side using AT commands.
I've taken this as a baseline and read this.
Hardware : ESP8266+arduino uno.
Code :
String cmd = "AT+CIPSTART=\"TCP\",\""; cmd += SERVER_IP; cmd += "\",81"; //Start a TCP connection. to server SERVER_IP on port 81
if (!sendCommand(cmd, "OK", CONTINUE))
return;
delay(2000);
if (!sendCommand("AT+CIPSTATUS", "OK", CONTINUE))// Check for TCP Connection status.
return;
cmd = "GET 192.168.43.228:81 HTTP/1.1\r\n";
cmd += "Host: 192.168.43.228:81\r\n";
cmd += "Upgrade: websocket\r\n";
cmd += "Connection: Upgrade\r\n\r\n";
if (!sendCommand("AT+CIPSEND=" + String(cmd.length()), ">", CONTINUE)) {
sendCommand("AT+CIPCLOSE", "", CONTINUE);
Serial.println("Connection timeout.");
return;
}
sendCommand(cmd, "OK", CONTINUE);// Send data to server.
delay(1000);
readResponseData("");
Log on arduino side :
ESP8266 Demo
AT+RST
OK
bBֆ#⸮Sc⸮⸮⸮ȤS⸮⸮⸮ɥ⸮⸮⸮⸮H⸮
[System Ready
, Vendo:⸮ݹ⸮⸮⸮ɹcom]
AT+GMR
0018000902
OK
AT+CWMODE?
+CWMODE:1
OK
AT+CWMODE=1
no change
AT+CWMODE=1
no change
AT+CIPMUX=0
OK
AT+CWJAP="AndroidAP","xxxx"
OK
Connected to WiFi.
AT+CWJAP="AndroidAP","xxxxx"
OK
AT+CWSAP=?
no this fun
AT+CIFSR
192.168.43.29
OK
Module is ready.
AT+CIPSTART="TCP","192.168.43.228",81
OK
Linked
AT+CIPSTATUS
STATUS:3
+CIPSTATUS:0,"TCP","192.168.43.228",81,0
OK
AT+CIPSEND=100
>
GET 192.168.43.228:81 HTTP/1.1
Host: 192.168.43.228:81
Upgradewrong syntax
ERROR
SEND OK
OK
Unlink
Server side :
WiFi connected
IP address:
192.168.43.228
Server available at ws://192.168.43.228:81
Accepted new web sockets client at index 0
--
...and nothing else from the server which is supposed sending a message as soon as it accepts the websocket.
Please give me some insight :)
I found one solution.
In fact I was not aware about all the details of RFC4566
After a successful handshake, you need to be inline with the frame requirement. It is not just as raw text :)
For a limited use case (i.e. length<125) here is the overview of the solution:
char str[] = "Hello";
char buf[125];
bool toMask = true;
uint8_t extra = toMask ? 6 : 2;
buildFrame(str, buf, WS_OPCODE_TEXT, toMask);
ESP8266SendData(0, buf, str.length() + extra);
I've tested this to get:
void buildFrame(char *str, uint8_t *ret, uint8_t opcode, bool maskon) {
uint8_t mask[4];
int size = strlen(str);
// Opcode; final fragment
ret[0] = opcode | WS_FIN;
ret[1] = (uint8_t) (size) | (maskon == true ? WS_MASK : 0);
if (maskon) {
mask[0] = random(0, 256);
mask[1] = random(0, 256);
mask[2] = random(0, 256);
mask[3] = random(0, 256);
for (int i = 2; i < 4 + 2; ++i) {
ret[i] = mask[i - 2];
}
for (int i = 6; i < size + 6; i++) {
ret[i] = str[i - 6] ^ mask[(i - 6) % 4];
}
}
else {
for (int i = 2; i < size + 2; ++i) {
ret[i] = (uint8_t) str[i - 2];
}
}
}
For frame decoding :
uint8_t extractPayload(String buffer, String& payload) {
// here only payloads whose size < 125
bool FIN = buffer[0] & WS_FIN;
uint8_t opcode = buffer[0] & ~WS_FIN;
bool hasMask = buffer[1] & WS_MASK;
uint8_t len = buffer[1] & ~WS_MASK;
uint8_t mask[4];
if (hasMask) {
mask[0] = buffer[2];
mask[1] = buffer[3];
mask[2] = buffer[4];
mask[3] = buffer[5];
for (int i = 6; i < len + 6; i++) {
payload += (char) (buffer[i] ^ mask[(i - 6) % 4]);
}
}
else {
payload = buffer.substring(2);
}
Serial.print("FIN = "); Serial.println(FIN, HEX);
Serial.print("Opcode = "); Serial.println(opcode, HEX);
Serial.print("Mask = "); Serial.println(hasMask, HEX);
Serial.print("Payload length = "); Serial.println(len, HEX);
return opcode;
}
Many times I have typical ETL code that looks like this
./call_some_api.py | ./extract_transform | ./load_to_some_sql
What if either of the first two scripts stop sending bytes because of some internal error that causes them to stall. I wish there was another program I could put before ./load_to_some_sql that will detect that 0 bytes has been sent in 5 minutes, and throw an exit code.
Curl has --speed-limit and --speed-time which do exactly this, but it's not generalized for other cli apps.
Is there a way to do this? Have a way to crash if the throughput hits a certain level on a pipe?
I know state machines and other orchestration tools can do this, but in general if there's a way to do it from bash it would be helpful!
If you are interested in inactivity timeout, these can do it.
One liner (mentioned in comments). Adjust $t for inactivity seconds:
perl -e'$t=300;$SIG{ALRM}=sub{die"Timeout\n"};alarm$t;while(<>){print;alarm$t}'
More robust:
#include <sys/epoll.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <stdlib.h>
#include <signal.h>
long secs = 300;
int stdin_mode, stdout_mode;
void my_exit(int code) {
fcntl(STDIN_FILENO, F_SETFL, stdin_mode);
fcntl(STDOUT_FILENO, F_SETFL, stdout_mode);
exit(code);
}
char* progname = "";
void perror_die(char* msg) {
dprintf(STDERR_FILENO, "%s: %s: %m\n", progname, msg);
my_exit(EXIT_FAILURE);
}
int check(int ret, char *msg) {
if (ret == -1) perror_die(msg);
return ret;
}
void usage() {
dprintf(STDERR_FILENO, "Usage:\n-s <secs> inactivity timeout in seconds (default: %ld seconds)\n", secs);
exit(EXIT_SUCCESS);
}
int main(int argc, char* argv[]) {
progname = argv[0];
signal(SIGHUP, SIG_IGN);
stdin_mode = fcntl(STDIN_FILENO, F_GETFL);
stdout_mode = fcntl(STDOUT_FILENO, F_GETFL);
int opt;
while((opt = getopt(argc, argv, "s:h")) != -1)
switch(opt) {
case 's':
secs = strtol(optarg, NULL, 10);
break;
case 'h':
case '?':
usage();
};
if (optind < argc) usage();
int epfd = check(epoll_create(3), "epoll_create");
struct epoll_event ev = {
.events = EPOLLIN | EPOLLET,
.data.fd = STDIN_FILENO
};
check(epoll_ctl(epfd, EPOLL_CTL_ADD, STDIN_FILENO, &ev), "epoll_ctl");
check(fcntl(STDIN_FILENO, F_SETFL, stdin_mode | O_NONBLOCK), "fcntl stdin");
ev.events = 0;
ev.data.fd = STDOUT_FILENO;
int epout = !epoll_ctl(epfd, EPOLL_CTL_ADD, STDOUT_FILENO, &ev);
if (epout)
check(fcntl(STDOUT_FILENO, F_SETFL, stdout_mode | O_NONBLOCK), "fcntl stdout");
char buf[4096];
ssize_t b_read = 0, b_wrote = 0, bytes = 0;
secs *= 1000;
int epres;
while((epres = epoll_wait(epfd, &ev, 1, secs)) == 1) {
if (ev.events & EPOLLERR) {
errno = EPIPE;
break;
}
for(;;) {
if (b_read == 0) {
b_read = read(STDIN_FILENO, buf, sizeof(buf));
if (b_read > 0) bytes += b_read;
else if (b_read == -1) {
if (errno == EAGAIN) {
b_read = 0;
break;
} else perror_die("read");
} else my_exit(EXIT_SUCCESS);
}
if (b_read) {
int w = write(STDOUT_FILENO, buf + b_wrote, b_read - b_wrote);
if (w != -1) b_wrote += w;
else {
if (errno == EAGAIN && epout) {
ev.events = EPOLLOUT | EPOLLONESHOT;
ev.data.fd = STDOUT_FILENO;
check(epoll_ctl(epfd, EPOLL_CTL_MOD, STDOUT_FILENO, &ev), "epoll_ctl");
break;
} else perror_die("write");
}
if (b_wrote == b_read) b_read = b_wrote = 0;
}
}
}
if (epres) perror_die("event loop");
dprintf(STDERR_FILENO, "%s: Timeout reached\n", progname);
my_exit(EXIT_FAILURE);
}
If you are interested in measuring bytes/secs this can do it, on an interval: (calculation could be improved to keep last n secs bandwidth instead of an interval)
#include <sys/epoll.h>
#include <fcntl.h>
#include <sys/timerfd.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <stdlib.h>
#include <signal.h>
ssize_t min_bw = 1000;
long secs = 5;
int stdin_mode, stdout_mode;
void my_exit(int code) {
fcntl(STDIN_FILENO, F_SETFL, stdin_mode);
fcntl(STDOUT_FILENO, F_SETFL, stdout_mode);
exit(code);
}
char* progname = "";
void perror_die(char* msg) {
dprintf(STDERR_FILENO, "%s: %s: %m\n", progname, msg);
my_exit(EXIT_FAILURE);
}
int check(int ret, char *msg) {
if (ret == -1) perror_die(msg);
return ret;
}
void usage() {
dprintf(STDERR_FILENO, "Usage:\n-b <bytes> minimum bytes per (default: %ld bytes)\n-s <secs> seconds (default: %ld seconds)\n", min_bw, secs);
exit(EXIT_SUCCESS);
}
int main(int argc, char* argv[]) {
progname = argv[0];
signal(SIGHUP, SIG_IGN);
stdin_mode = fcntl(STDIN_FILENO, F_GETFL);
stdout_mode = fcntl(STDOUT_FILENO, F_GETFL);
int opt;
while((opt = getopt(argc, argv, "b:s:h")) != -1)
switch(opt) {
case 'b':
min_bw = strtol(optarg, NULL, 10);
break;
case 's':
secs = strtol(optarg, NULL, 10);
break;
case 'h':
case '?':
usage();
};
if (optind < argc) usage();
int epfd = check(epoll_create(3), "epoll_create");
int tmfd = check(timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK), "timerfd_create");
struct itimerspec when = {{secs, 0}, {secs, 0}};
check(timerfd_settime(tmfd, 0, &when, NULL), "timerfd_settime");
struct epoll_event ev = {
.events = EPOLLIN | EPOLLET,
.data.fd = tmfd
};
check(epoll_ctl(epfd, EPOLL_CTL_ADD, tmfd, &ev), "epoll_ctl");
ev.data.fd = STDIN_FILENO;
check(epoll_ctl(epfd, EPOLL_CTL_ADD, STDIN_FILENO, &ev), "epoll_ctl");
check(fcntl(STDIN_FILENO, F_SETFL, stdin_mode | O_NONBLOCK), "fcntl stdin");
ev.events = 0;
ev.data.fd = STDOUT_FILENO;
int epout = !epoll_ctl(epfd, EPOLL_CTL_ADD, STDOUT_FILENO, &ev);
if (epout)
check(fcntl(STDOUT_FILENO, F_SETFL, stdout_mode | O_NONBLOCK), "fcntl stdout");
char tmbuf[64];
char buf[4096];
ssize_t b_read = 0, b_wrote = 0, bytes = 0;
int epres;
while((epres = epoll_wait(epfd, &ev, 1, -1)) == 1) {
if (ev.events & EPOLLERR) {
errno = EPIPE;
break;
}
if (ev.data.fd == tmfd) {
if (bytes < min_bw) {
dprintf(STDERR_FILENO, "Too slow\n");
my_exit(EXIT_FAILURE);
}
check(read(tmfd, tmbuf, sizeof(tmbuf)), "read timerfd");
bytes = 0;
continue;
}
for(;;) {
if (b_read == 0) {
b_read = read(STDIN_FILENO, buf, sizeof(buf));
if (b_read > 0) bytes += b_read;
else if (b_read == -1) {
if (errno == EAGAIN) {
b_read = 0;
break;
} else perror_die("read");
} else my_exit(EXIT_SUCCESS);
}
if (b_read) {
int w = write(STDOUT_FILENO, buf + b_wrote, b_read - b_wrote);
if (w != -1) b_wrote += w;
else {
if (errno == EAGAIN && epout) {
ev.events = EPOLLOUT | EPOLLONESHOT;
ev.data.fd = STDOUT_FILENO;
check(epoll_ctl(epfd, EPOLL_CTL_MOD, STDOUT_FILENO, &ev), "epoll_ctl");
break;
} else perror_die("write");
}
if (b_wrote == b_read) b_read = b_wrote = 0;
}
}
}
perror_die("event loop");
}
Both programs are for linux only.
Provided you have a newish version of Bash, the read builtin can optionally enforce a timeout [docs], which means that it's actually not hard to write a bit of pure Bash code that does exactly what you describe:
... upstream command ... \
| {
while true ; do
read -r -N 1 -t 300 char
result=$?
if (( result > 128 )) ; then
echo 'Read timed out.' >&2
exit 1
elif (( result > 0 )) ; then
exit 0
elif [[ "$char" == '' ]] ; then
printf '\0'
else
printf %s "$char"
fi
done
} \
| ... downstream command ...
(Note: the above reads one character at a time for simplicity's sake; if you expect a high volume of data to pass through this, then you may need to adjust it for better performance.)
But even though the above does exactly what you describe, I'm not sure whether it will really accomplish your goal, because the upstream command won't actually die until it tries to write something and gets SIGPIPE. So even after the above prints Read timed out, Bash will just keep hanging indefinitely, probably until the user hits Ctrl-C. (The same goes for niry's answer, of course.) That's a bit harder to fix; I guess when your command detects a timeout, it will need to find the process-IDs of the upstream commands, and use kill to proactively send them SIGPIPE (or some other signal of your choosing)?
I'm recording RTSP stream from camera into mp4 files in Windows machine and I want to save files in separate folder by day using strftime option (name format like D:/Video/YYYY-MM-DD/). I really want to know that does ffmpeg have ability to create folder by itself or do I have to create it by external programs?
For example, I want to use ffmpeg command like below:
ffmpeg -rtsp_transport tcp -i <rtsp_url> \
-f segment -strftime 1 -segment_time 01:00:00 -segment_atclocktime 1 \
-segment_clocktime_offset 30 -segment_format mp4 \
-an -vcodec copy -reset_timestamps 1 \
D:/Video/%Y-%m-%d/record_%H_%M_%S.mp4
Here is a patch for ffmpeg-3.3.6
diff --git a/libavformat/segment.c b/libavformat/segment.c
index 8ec3653..2d90ef2 100644
--- a/libavformat/segment.c
+++ b/libavformat/segment.c
## -28,6 +28,7 ##
#include <float.h>
#include <time.h>
+#include <unistd.h>
#include "avformat.h"
#include "avio_internal.h"
## -226,6 +227,49 ## static int set_segment_filename(AVFormatContext *s)
return 0;
}
+/* Note: This modifies *dir */
+static int create_dir(char *dir, mode_t mode) {
+ int ret = 0;
+ unsigned int i, dlen;
+ /* Shortcut, there are no deep directories */
+ if (strchr(dir, '/') == NULL)
+ return mkdir(dir, mode);
+ dlen = strlen(dir);
+ /* Skip first char (it can be /) */
+ for (i = 1; i < dlen; i++) {
+ if (dir[i] != '/')
+ continue;
+ dir[i] = '\0';
+ ret = mkdir(dir, mode);
+ dir[i] = '/';
+ if (ret < 0 && errno != EEXIST)
+ goto OUT;
+ }
+ ret = mkdir(dir, mode);
+OUT:
+ return ret;
+}
+
+static int segment_create_directory(AVFormatContext *oc, char *filename) {
+ char *dir, *fname;
+ /* Do nothing when the filename is URL */
+ if (strstr(filename, "://") != NULL)
+ return 0;
+ fname = av_strdup(filename);
+ if (!fname)
+ return AVERROR(ENOMEM);
+ dir = (char *)av_dirname(fname);
+ if (access(dir, W_OK) != F_OK)
+ av_log(oc, AV_LOG_INFO, "Create directory %s\n", dir);
+ if (create_dir(dir, 0777) == -1 && errno != EEXIST) {
+ av_log(oc, AV_LOG_ERROR, "Could not create directory %s\n", dir);
+ av_free(fname);
+ return AVERROR(errno);
+ }
+ av_free(fname);
+ return 0;
+}
+
static int segment_start(AVFormatContext *s, int write_header)
{
SegmentContext *seg = s->priv_data;
## -247,6 +291,9 ## static int segment_start(AVFormatContext *s, int write_header)
if ((err = set_segment_filename(s)) < 0)
return err;
+ if ((err = segment_create_directory(s, oc->filename)) < 0)
+ return err;
+
if ((err = s->io_open(s, &oc->pb, oc->filename, AVIO_FLAG_WRITE, NULL)) < 0) {
av_log(s, AV_LOG_ERROR, "Failed to open segment '%s'\n", oc->filename);
return err;
## -277,6 +324,10 ## static int segment_list_open(AVFormatContext *s)
int ret;
snprintf(seg->temp_list_filename, sizeof(seg->temp_list_filename), seg->use_rename ? "%s.tmp" : "%s", seg->list);
+
+ if ((ret = segment_create_directory(s, seg->temp_list_filename)) < 0)
+ return ret;
+
ret = s->io_open(s, &seg->list_pb, seg->temp_list_filename, AVIO_FLAG_WRITE, NULL);
if (ret < 0) {
av_log(s, AV_LOG_ERROR, "Failed to open segment list '%s'\n", seg->list);
## -746,6 +797,9 ## static int seg_init(AVFormatContext *s)
oc = seg->avf;
if (seg->write_header_trailer) {
+ if ((ret = segment_create_directory(s, seg->header_filename ? seg->header_filename : oc->filename)) < 0)
+ return ret;
+
if ((ret = s->io_open(s, &oc->pb,
seg->header_filename ? seg->header_filename : oc->filename,
AVIO_FLAG_WRITE, NULL)) < 0) {
It can be helpful to creating a patch for last version to support making directories for segmentation.
I'm trying to get the original destination of UDP packet using IP_ORIGDSTADDR. On older kernel that mine, it seems to work (I'm running the currently debian testing kernel, 4.7.0-1-amd64).
#define _DEFAULT_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#define DEFAULT_ADDR "127.0.0.1"
#define DEFAULT_PORT 6666
int main(int ac, char **av)
{
int sock;
struct sockaddr_in sin;
memset(&sin, 0, sizeof sin);
sin.sin_family = AF_INET;
if (inet_aton(ac >= 2 ? av[1] : DEFAULT_ADDR, &sin.sin_addr) < 0) {
fprintf(stderr, "Invalid address\n");
goto err;
}
sin.sin_port = htons(ac >= 3 ? atoi(av[2]) : DEFAULT_PORT);
sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock < 0) {
perror("socket");
goto err;
}
if (bind(sock, (struct sockaddr *) &sin, sizeof sin) < 0) {
perror("bind");
goto close_err;
}
#define SOCK_OPT(l, n, v) do { \
int _v = v; \
socklen_t _s; \
if (setsockopt(sock, l, n, &_v, sizeof _v) < 0) { \
perror("setsockopt "# l "/" # n); \
goto close_err; \
} \
\
_s = sizeof (_v); \
if (getsockopt(sock, l, n, &_v, &_s) < 0) { \
perror("getsockopt "# l "/" # n); \
goto close_err; \
} \
\
if (_v != v) { \
fprintf(stderr, "Unexpected sockopt (expected %d, found %d)\n", v, _v); \
goto close_err; \
} \
\
printf(#l "/" #n " is set to %d\n", _v); \
\
} while (0)
SOCK_OPT(SOL_IP, IP_RECVORIGDSTADDR, 1);
SOCK_OPT(SOL_IP, IP_RECVOPTS, 1);
SOCK_OPT(SOL_IP, IP_PKTINFO, 1);
#undef SOCK_OPT
printf("Reading on %s:%d\n", inet_ntoa(sin.sin_addr), htons(sin.sin_port));
for (;;) {
ssize_t n;
char buf[1024];
char tmp[80];
struct iovec iovec[] = {
{
.iov_base = buf,
.iov_len = sizeof buf - 1,
}
};
struct msghdr msghdr;
struct cmsghdr *cmsg_ptr;
struct sockaddr_storage from = { 0 };
int port;
union cmsg_data {
struct sockaddr_in sin;
struct in_pktinfo pktinfo;
};
char msg_control[CMSG_SPACE(sizeof(union cmsg_data)) * 10] = { 0 };
int found;
memset(&msghdr, 0, sizeof msghdr);
msghdr.msg_name = &from;
msghdr.msg_namelen = sizeof from;
msghdr.msg_iov = iovec;
msghdr.msg_iovlen = sizeof iovec / sizeof iovec[0];
msghdr.msg_control = msg_control;
msghdr.msg_controllen = sizeof msg_control;
msghdr.msg_flags = MSG_EOR | MSG_TRUNC | MSG_CTRUNC | MSG_OOB | MSG_ERRQUEUE;
n = recvmsg(sock, &msghdr, MSG_OOB);
if (n < 0) {
perror("recvmsg");
continue;
}
if (buf[n - 1] == '\n')
n--;
buf[n] = 0;
switch (from.ss_family) {
default:
tmp[0] = 0;
break;
case AF_INET:
inet_ntop(AF_INET, &((struct sockaddr_in *) &from)->sin_addr, tmp, sizeof tmp);
port = htons(((struct sockaddr_in *) &from)->sin_port);
break;
case AF_INET6:
inet_ntop(AF_INET6, &((struct sockaddr_in6 *) &from)->sin6_addr, tmp, sizeof tmp);
port = htons(((struct sockaddr_in6 *) &from)->sin6_port);
break;
}
printf("%s:%d Rx %ldb: %.*s, msg_control = %zdb\n", tmp, port, n, (int) n, buf, sizeof msg_control);
found = 0;
for (cmsg_ptr = CMSG_FIRSTHDR(&msghdr); cmsg_ptr != NULL; cmsg_ptr = CMSG_NXTHDR(&msghdr, cmsg_ptr)) {
union cmsg_data *cmsg_data = (union cmsg_data *) CMSG_DATA(cmsg_ptr);
switch (cmsg_ptr->cmsg_level) {
default:
fprintf(stderr, "Unexecpted level : %d\n", cmsg_ptr->cmsg_level);
break;
case SOL_IP:
switch (cmsg_ptr->cmsg_type) {
default:
fprintf(stderr, "Unexecpted type : %d\n", cmsg_ptr->cmsg_type);
break;
case IP_ORIGDSTADDR:
printf("IP_ORIGDSTADDR: sin_addr = %s, sin_port = %d\n", inet_ntoa(cmsg_data->sin.sin_addr), htons(cmsg_data->sin.sin_port));
found++;
break;
case IP_PKTINFO:
snprintf(tmp, sizeof tmp, "%s", inet_ntoa(cmsg_data->pktinfo.ipi_spec_dst));
printf("IP_PKTINFO: ifindex = %u, spec_dst = %s, addr = %s\n", cmsg_data->pktinfo.ipi_ifindex, tmp, inet_ntoa(cmsg_data->pktinfo.ipi_addr));
break;
}
}
}
if (found != 1)
fprintf(stderr, "*** Warning: No SOL_IP / IP_ORIGDSTADDR found\n");
}
close_err:
close(sock);
err:
return 1;
}
When trying this bunch of code (eg. sending packets using netcat), I dont have any IP_ORIGDSTADDR, but only IP_PKTINFO : I need to have UDP port, only IP_ORIGDSTADDR can provide it.
Does anyone have met this strange behaviour ?