Browse Source

Initial import

Georgi Chorbadzhiyski 10 years ago
commit
a6396d5815
14 changed files with 1446 additions and 0 deletions
  1. 3
    0
      .gitignore
  2. 3
    0
      .gitmodules
  3. 340
    0
      COPYING
  4. 2
    0
      ChangeLog
  5. 112
    0
      Makefile
  6. 1
    0
      RELEASE
  7. 2
    0
      TODO
  8. 1
    0
      libfuncs
  9. 208
    0
      process.c
  10. 313
    0
      tsdumper2.c
  11. 105
    0
      tsdumper2.h
  12. 150
    0
      udp.c
  13. 167
    0
      util.c
  14. 39
    0
      util.h

+ 3
- 0
.gitignore View File

@@ -0,0 +1,3 @@
1
+*.o
2
+*.d
3
+tsdumper2

+ 3
- 0
.gitmodules View File

@@ -0,0 +1,3 @@
1
+[submodule "libfuncs"]
2
+	path = libfuncs
3
+	url = git://github.com/gfto/libfuncs.git

+ 340
- 0
COPYING View File

@@ -0,0 +1,340 @@
1
+                    GNU GENERAL PUBLIC LICENSE
2
+                       Version 2, June 1991
3
+
4
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
5
+ 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
6
+ Everyone is permitted to copy and distribute verbatim copies
7
+ of this license document, but changing it is not allowed.
8
+
9
+                            Preamble
10
+
11
+  The licenses for most software are designed to take away your
12
+freedom to share and change it.  By contrast, the GNU General Public
13
+License is intended to guarantee your freedom to share and change free
14
+software--to make sure the software is free for all its users.  This
15
+General Public License applies to most of the Free Software
16
+Foundation's software and to any other program whose authors commit to
17
+using it.  (Some other Free Software Foundation software is covered by
18
+the GNU Library General Public License instead.)  You can apply it to
19
+your programs, too.
20
+
21
+  When we speak of free software, we are referring to freedom, not
22
+price.  Our General Public Licenses are designed to make sure that you
23
+have the freedom to distribute copies of free software (and charge for
24
+this service if you wish), that you receive source code or can get it
25
+if you want it, that you can change the software or use pieces of it
26
+in new free programs; and that you know you can do these things.
27
+
28
+  To protect your rights, we need to make restrictions that forbid
29
+anyone to deny you these rights or to ask you to surrender the rights.
30
+These restrictions translate to certain responsibilities for you if you
31
+distribute copies of the software, or if you modify it.
32
+
33
+  For example, if you distribute copies of such a program, whether
34
+gratis or for a fee, you must give the recipients all the rights that
35
+you have.  You must make sure that they, too, receive or can get the
36
+source code.  And you must show them these terms so they know their
37
+rights.
38
+
39
+  We protect your rights with two steps: (1) copyright the software, and
40
+(2) offer you this license which gives you legal permission to copy,
41
+distribute and/or modify the software.
42
+
43
+  Also, for each author's protection and ours, we want to make certain
44
+that everyone understands that there is no warranty for this free
45
+software.  If the software is modified by someone else and passed on, we
46
+want its recipients to know that what they have is not the original, so
47
+that any problems introduced by others will not reflect on the original
48
+authors' reputations.
49
+
50
+  Finally, any free program is threatened constantly by software
51
+patents.  We wish to avoid the danger that redistributors of a free
52
+program will individually obtain patent licenses, in effect making the
53
+program proprietary.  To prevent this, we have made it clear that any
54
+patent must be licensed for everyone's free use or not licensed at all.
55
+
56
+  The precise terms and conditions for copying, distribution and
57
+modification follow.
58
+
59
+                    GNU GENERAL PUBLIC LICENSE
60
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
61
+
62
+  0. This License applies to any program or other work which contains
63
+a notice placed by the copyright holder saying it may be distributed
64
+under the terms of this General Public License.  The "Program", below,
65
+refers to any such program or work, and a "work based on the Program"
66
+means either the Program or any derivative work under copyright law:
67
+that is to say, a work containing the Program or a portion of it,
68
+either verbatim or with modifications and/or translated into another
69
+language.  (Hereinafter, translation is included without limitation in
70
+the term "modification".)  Each licensee is addressed as "you".
71
+
72
+Activities other than copying, distribution and modification are not
73
+covered by this License; they are outside its scope.  The act of
74
+running the Program is not restricted, and the output from the Program
75
+is covered only if its contents constitute a work based on the
76
+Program (independent of having been made by running the Program).
77
+Whether that is true depends on what the Program does.
78
+
79
+  1. You may copy and distribute verbatim copies of the Program's
80
+source code as you receive it, in any medium, provided that you
81
+conspicuously and appropriately publish on each copy an appropriate
82
+copyright notice and disclaimer of warranty; keep intact all the
83
+notices that refer to this License and to the absence of any warranty;
84
+and give any other recipients of the Program a copy of this License
85
+along with the Program.
86
+
87
+You may charge a fee for the physical act of transferring a copy, and
88
+you may at your option offer warranty protection in exchange for a fee.
89
+
90
+  2. You may modify your copy or copies of the Program or any portion
91
+of it, thus forming a work based on the Program, and copy and
92
+distribute such modifications or work under the terms of Section 1
93
+above, provided that you also meet all of these conditions:
94
+
95
+    a) You must cause the modified files to carry prominent notices
96
+    stating that you changed the files and the date of any change.
97
+
98
+    b) You must cause any work that you distribute or publish, that in
99
+    whole or in part contains or is derived from the Program or any
100
+    part thereof, to be licensed as a whole at no charge to all third
101
+    parties under the terms of this License.
102
+
103
+    c) If the modified program normally reads commands interactively
104
+    when run, you must cause it, when started running for such
105
+    interactive use in the most ordinary way, to print or display an
106
+    announcement including an appropriate copyright notice and a
107
+    notice that there is no warranty (or else, saying that you provide
108
+    a warranty) and that users may redistribute the program under
109
+    these conditions, and telling the user how to view a copy of this
110
+    License.  (Exception: if the Program itself is interactive but
111
+    does not normally print such an announcement, your work based on
112
+    the Program is not required to print an announcement.)
113
+
114
+These requirements apply to the modified work as a whole.  If
115
+identifiable sections of that work are not derived from the Program,
116
+and can be reasonably considered independent and separate works in
117
+themselves, then this License, and its terms, do not apply to those
118
+sections when you distribute them as separate works.  But when you
119
+distribute the same sections as part of a whole which is a work based
120
+on the Program, the distribution of the whole must be on the terms of
121
+this License, whose permissions for other licensees extend to the
122
+entire whole, and thus to each and every part regardless of who wrote it.
123
+
124
+Thus, it is not the intent of this section to claim rights or contest
125
+your rights to work written entirely by you; rather, the intent is to
126
+exercise the right to control the distribution of derivative or
127
+collective works based on the Program.
128
+
129
+In addition, mere aggregation of another work not based on the Program
130
+with the Program (or with a work based on the Program) on a volume of
131
+a storage or distribution medium does not bring the other work under
132
+the scope of this License.
133
+
134
+  3. You may copy and distribute the Program (or a work based on it,
135
+under Section 2) in object code or executable form under the terms of
136
+Sections 1 and 2 above provided that you also do one of the following:
137
+
138
+    a) Accompany it with the complete corresponding machine-readable
139
+    source code, which must be distributed under the terms of Sections
140
+    1 and 2 above on a medium customarily used for software interchange; or,
141
+
142
+    b) Accompany it with a written offer, valid for at least three
143
+    years, to give any third party, for a charge no more than your
144
+    cost of physically performing source distribution, a complete
145
+    machine-readable copy of the corresponding source code, to be
146
+    distributed under the terms of Sections 1 and 2 above on a medium
147
+    customarily used for software interchange; or,
148
+
149
+    c) Accompany it with the information you received as to the offer
150
+    to distribute corresponding source code.  (This alternative is
151
+    allowed only for noncommercial distribution and only if you
152
+    received the program in object code or executable form with such
153
+    an offer, in accord with Subsection b above.)
154
+
155
+The source code for a work means the preferred form of the work for
156
+making modifications to it.  For an executable work, complete source
157
+code means all the source code for all modules it contains, plus any
158
+associated interface definition files, plus the scripts used to
159
+control compilation and installation of the executable.  However, as a
160
+special exception, the source code distributed need not include
161
+anything that is normally distributed (in either source or binary
162
+form) with the major components (compiler, kernel, and so on) of the
163
+operating system on which the executable runs, unless that component
164
+itself accompanies the executable.
165
+
166
+If distribution of executable or object code is made by offering
167
+access to copy from a designated place, then offering equivalent
168
+access to copy the source code from the same place counts as
169
+distribution of the source code, even though third parties are not
170
+compelled to copy the source along with the object code.
171
+
172
+  4. You may not copy, modify, sublicense, or distribute the Program
173
+except as expressly provided under this License.  Any attempt
174
+otherwise to copy, modify, sublicense or distribute the Program is
175
+void, and will automatically terminate your rights under this License.
176
+However, parties who have received copies, or rights, from you under
177
+this License will not have their licenses terminated so long as such
178
+parties remain in full compliance.
179
+
180
+  5. You are not required to accept this License, since you have not
181
+signed it.  However, nothing else grants you permission to modify or
182
+distribute the Program or its derivative works.  These actions are
183
+prohibited by law if you do not accept this License.  Therefore, by
184
+modifying or distributing the Program (or any work based on the
185
+Program), you indicate your acceptance of this License to do so, and
186
+all its terms and conditions for copying, distributing or modifying
187
+the Program or works based on it.
188
+
189
+  6. Each time you redistribute the Program (or any work based on the
190
+Program), the recipient automatically receives a license from the
191
+original licensor to copy, distribute or modify the Program subject to
192
+these terms and conditions.  You may not impose any further
193
+restrictions on the recipients' exercise of the rights granted herein.
194
+You are not responsible for enforcing compliance by third parties to
195
+this License.
196
+
197
+  7. If, as a consequence of a court judgment or allegation of patent
198
+infringement or for any other reason (not limited to patent issues),
199
+conditions are imposed on you (whether by court order, agreement or
200
+otherwise) that contradict the conditions of this License, they do not
201
+excuse you from the conditions of this License.  If you cannot
202
+distribute so as to satisfy simultaneously your obligations under this
203
+License and any other pertinent obligations, then as a consequence you
204
+may not distribute the Program at all.  For example, if a patent
205
+license would not permit royalty-free redistribution of the Program by
206
+all those who receive copies directly or indirectly through you, then
207
+the only way you could satisfy both it and this License would be to
208
+refrain entirely from distribution of the Program.
209
+
210
+If any portion of this section is held invalid or unenforceable under
211
+any particular circumstance, the balance of the section is intended to
212
+apply and the section as a whole is intended to apply in other
213
+circumstances.
214
+
215
+It is not the purpose of this section to induce you to infringe any
216
+patents or other property right claims or to contest validity of any
217
+such claims; this section has the sole purpose of protecting the
218
+integrity of the free software distribution system, which is
219
+implemented by public license practices.  Many people have made
220
+generous contributions to the wide range of software distributed
221
+through that system in reliance on consistent application of that
222
+system; it is up to the author/donor to decide if he or she is willing
223
+to distribute software through any other system and a licensee cannot
224
+impose that choice.
225
+
226
+This section is intended to make thoroughly clear what is believed to
227
+be a consequence of the rest of this License.
228
+
229
+  8. If the distribution and/or use of the Program is restricted in
230
+certain countries either by patents or by copyrighted interfaces, the
231
+original copyright holder who places the Program under this License
232
+may add an explicit geographical distribution limitation excluding
233
+those countries, so that distribution is permitted only in or among
234
+countries not thus excluded.  In such case, this License incorporates
235
+the limitation as if written in the body of this License.
236
+
237
+  9. The Free Software Foundation may publish revised and/or new versions
238
+of the General Public License from time to time.  Such new versions will
239
+be similar in spirit to the present version, but may differ in detail to
240
+address new problems or concerns.
241
+
242
+Each version is given a distinguishing version number.  If the Program
243
+specifies a version number of this License which applies to it and "any
244
+later version", you have the option of following the terms and conditions
245
+either of that version or of any later version published by the Free
246
+Software Foundation.  If the Program does not specify a version number of
247
+this License, you may choose any version ever published by the Free Software
248
+Foundation.
249
+
250
+  10. If you wish to incorporate parts of the Program into other free
251
+programs whose distribution conditions are different, write to the author
252
+to ask for permission.  For software which is copyrighted by the Free
253
+Software Foundation, write to the Free Software Foundation; we sometimes
254
+make exceptions for this.  Our decision will be guided by the two goals
255
+of preserving the free status of all derivatives of our free software and
256
+of promoting the sharing and reuse of software generally.
257
+
258
+                            NO WARRANTY
259
+
260
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
261
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
262
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
263
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
264
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
265
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
266
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
267
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
268
+REPAIR OR CORRECTION.
269
+
270
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
271
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
272
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
273
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
274
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
275
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
276
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
277
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
278
+POSSIBILITY OF SUCH DAMAGES.
279
+
280
+                     END OF TERMS AND CONDITIONS
281
+
282
+            How to Apply These Terms to Your New Programs
283
+
284
+  If you develop a new program, and you want it to be of the greatest
285
+possible use to the public, the best way to achieve this is to make it
286
+free software which everyone can redistribute and change under these terms.
287
+
288
+  To do so, attach the following notices to the program.  It is safest
289
+to attach them to the start of each source file to most effectively
290
+convey the exclusion of warranty; and each file should have at least
291
+the "copyright" line and a pointer to where the full notice is found.
292
+
293
+    <one line to give the program's name and a brief idea of what it does.>
294
+    Copyright (C) <year>  <name of author>
295
+
296
+    This program is free software; you can redistribute it and/or modify
297
+    it under the terms of the GNU General Public License as published by
298
+    the Free Software Foundation; either version 2 of the License, or
299
+    (at your option) any later version.
300
+
301
+    This program is distributed in the hope that it will be useful,
302
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
303
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
304
+    GNU General Public License for more details.
305
+
306
+    You should have received a copy of the GNU General Public License
307
+    along with this program; if not, write to the Free Software
308
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
309
+
310
+
311
+Also add information on how to contact you by electronic and paper mail.
312
+
313
+If the program is interactive, make it output a short notice like this
314
+when it starts in an interactive mode:
315
+
316
+    Gnomovision version 69, Copyright (C) year name of author
317
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
318
+    This is free software, and you are welcome to redistribute it
319
+    under certain conditions; type `show c' for details.
320
+
321
+The hypothetical commands `show w' and `show c' should show the appropriate
322
+parts of the General Public License.  Of course, the commands you use may
323
+be called something other than `show w' and `show c'; they could even be
324
+mouse-clicks or menu items--whatever suits your program.
325
+
326
+You should also get your employer (if you work as a programmer) or your
327
+school, if any, to sign a "copyright disclaimer" for the program, if
328
+necessary.  Here is a sample; alter the names:
329
+
330
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
331
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
332
+
333
+  <signature of Ty Coon>, 1 April 1989
334
+  Ty Coon, President of Vice
335
+
336
+This General Public License does not permit incorporating your program into
337
+proprietary programs.  If your program is a subroutine library, you may
338
+consider it more useful to permit linking proprietary applications with the
339
+library.  If this is what you want to do, use the GNU Library General
340
+Public License instead of this License.

+ 2
- 0
ChangeLog View File

@@ -0,0 +1,2 @@
1
+2013-07-22 : Version 0.9
2
+ * Initial public release.

+ 112
- 0
Makefile View File

@@ -0,0 +1,112 @@
1
+CC = $(CROSS)$(TARGET)cc
2
+STRIP = $(CROSS)$(TARGET)strip
3
+MKDEP = $(CC) -MP -MM -o $*.d $<
4
+RM = rm -f
5
+MV = mv -f
6
+
7
+BUILD_ID = $(shell date +%Y%m%d_%H%M%S)
8
+VERSION = $(shell cat RELEASE)
9
+GIT_VER = $(shell git describe --tags --dirty --always 2>/dev/null)
10
+ifeq "$(GIT_VER)" ""
11
+GIT_VER = "release"
12
+endif
13
+
14
+ifndef V
15
+Q = @
16
+endif
17
+
18
+CFLAGS ?= -O2 -ggdb \
19
+ -W -Wall -Wextra \
20
+ -Wshadow -Wformat-security -Wstrict-prototypes
21
+
22
+DEFS = -DBUILD_ID=\"$(BUILD_ID)\" \
23
+ -DVERSION=\"$(VERSION)\" -DGIT_VER=\"$(GIT_VER)\"
24
+DEFS += -D_FILE_OFFSET_BITS=64
25
+
26
+PREFIX ?= /usr/local
27
+
28
+INSTALL_PRG = tsdumper2
29
+INSTALL_PRG_DIR = $(subst //,/,$(DESTDIR)/$(PREFIX)/bin)
30
+
31
+INSTALL_DOC = tsdumper2.1
32
+INSTALL_DOC_DIR = $(subst //,/,$(DESTDIR)/$(PREFIX)/share/man/man1)
33
+
34
+FUNCS_DIR = libfuncs
35
+FUNCS_LIB = $(FUNCS_DIR)/libfuncs.a
36
+
37
+tsdumper_SRC = \
38
+ udp.c \
39
+ util.c \
40
+ process.c \
41
+ tsdumper2.c
42
+tsdumper_LIBS = -lpthread
43
+
44
+tsdumper_OBJS = $(FUNCS_LIB) $(tsdumper_SRC:.c=.o)
45
+
46
+CLEAN_OBJS = tsdumper2 $(tsdumper_SRC:.c=.o) $(tsdumper_SRC:.c=.d)
47
+
48
+PROGS = tsdumper2
49
+
50
+.PHONY: help distclean clean install uninstall
51
+
52
+all: $(PROGS)
53
+
54
+$(FUNCS_LIB): $(FUNCS_DIR)/libfuncs.h
55
+	$(Q)echo "  MAKE	$(FUNCS_LIB)"
56
+	$(Q)$(MAKE) -s -C $(FUNCS_DIR)
57
+
58
+tsdumper2: $(tsdumper_OBJS)
59
+	$(Q)echo "  LINK	tsdumper2"
60
+	$(Q)$(CC) $(CFLAGS) $(DEFS) $(tsdumper_OBJS) $(tsdumper_LIBS) -o tsdumper2
61
+
62
+%.o: %.c Makefile RELEASE
63
+	@$(MKDEP)
64
+	$(Q)echo "  CC	tsdumper2	$<"
65
+	$(Q)$(CC) $(CFLAGS) $(DEFS) -c $<
66
+
67
+-include $(tsdumper_SRC:.c=.d)
68
+
69
+strip:
70
+	$(Q)echo "  STRIP	$(PROGS)"
71
+	$(Q)$(STRIP) $(PROGS)
72
+
73
+clean:
74
+	$(Q)echo "  RM	$(CLEAN_OBJS)"
75
+	$(Q)$(RM) $(CLEAN_OBJS)
76
+
77
+distclean: clean
78
+	$(Q)$(MAKE) -s -C $(FUNCS_DIR) clean
79
+
80
+install: all
81
+	@install -d "$(INSTALL_PRG_DIR)"
82
+	@echo "INSTALL $(INSTALL_PRG) -> $(INSTALL_PRG_DIR)"
83
+	$(Q)-install $(INSTALL_PRG) "$(INSTALL_PRG_DIR)"
84
+	@echo "INSTALL $(INSTALL_DOC) -> $(INSTALL_DOC_DIR)"
85
+	$(Q)-install --mode 0644 $(INSTALL_DOC) "$(INSTALL_DOC_DIR)"
86
+
87
+uninstall:
88
+	@-for FILE in $(INSTALL_PRG); do \
89
+		echo "RM       $(INSTALL_PRG_DIR)/$$FILE"; \
90
+		rm "$(INSTALL_PRG_DIR)/$$FILE"; \
91
+	done
92
+	@-for FILE in $(INSTALL_DOC); do \
93
+		echo "RM       $(INSTALL_DOC_DIR)/$$FILE"; \
94
+		rm "$(INSTALL_DOC_DIR)/$$FILE"; \
95
+	done
96
+
97
+help:
98
+	$(Q)echo -e "\
99
+tsdumper2 $(VERSION) ($(GIT_VER)) build\n\n\
100
+Build targets:\n\
101
+  tsdumper2|all   - Build tsdumper2.\n\
102
+\n\
103
+  install         - Install tsdumper2 in PREFIX ($(PREFIX))\n\
104
+  uninstall       - Uninstall tsdumper2 from PREFIX\n\
105
+\n\
106
+Cleaning targets:\n\
107
+  clean           - Remove tsdumper2 build files\n\
108
+  distclean       - Remove all build files\n\
109
+\n\
110
+  make V=1          Enable verbose build\n\
111
+  make PREFIX=dir   Set install prefix\n\
112
+  make CROSS=prefix Cross compile\n"

+ 1
- 0
RELEASE View File

@@ -0,0 +1 @@
1
+0.9

+ 2
- 0
TODO View File

@@ -0,0 +1,2 @@
1
+- Add README and man page.
2
+- Add http input.

+ 1
- 0
libfuncs

@@ -0,0 +1 @@
1
+Subproject commit 2d8b0cb1051ce0196ee387ab6ae731c2f841c67b

+ 208
- 0
process.c View File

@@ -0,0 +1,208 @@
1
+/*
2
+ * Process incoming data and save it into files.
3
+ * Copyright (C) 2013 Unix Solutions Ltd.
4
+ *
5
+ * This program is free software; you can redistribute it and/or modify
6
+ * it under the terms of the GNU General Public License version 2
7
+ * as published by the Free Software Foundation.
8
+ *
9
+ * This program is distributed in the hope that it will be useful,
10
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
+ * GNU General Public License (COPYING file) for more details.
13
+ *
14
+ */
15
+#include <stdlib.h>
16
+#include <string.h>
17
+#include <unistd.h>
18
+#include <sys/types.h>
19
+#include <sys/stat.h>
20
+#include <fcntl.h>
21
+#include <errno.h>
22
+
23
+#include "tsdumper2.h"
24
+
25
+#define NO_UNLINK  0
26
+#define UNLINK_OLD 1
27
+
28
+#define ALIGN_DOWN(__src, __value) (__src - (__src % __value))
29
+
30
+static mode_t dir_perm;
31
+
32
+static int file_exists(char *filename) {
33
+	return access(filename, W_OK) == 0;
34
+}
35
+
36
+static void format_output_filename(struct ts *ts, time_t file_time) {
37
+	struct tm file_tm;
38
+	localtime_r(&file_time, &file_tm);
39
+
40
+	ts->output_startts = file_time;
41
+
42
+	ts->output_filename[0] = '\0';
43
+	strcat(ts->output_filename, ts->prefix);
44
+	strcat(ts->output_filename, "-");
45
+	strftime(ts->output_filename + strlen(ts->output_filename), OUTFILE_NAME_MAX, "%Y%m%d_%H%M%S-%s.ts", &file_tm);
46
+
47
+	ts->output_dirname[0] = '\0';
48
+	strftime(ts->output_dirname, OUTFILE_NAME_MAX, "%Y/%m/%d/%H", &file_tm);
49
+
50
+	ts->output_full_filename[0] = '\0';
51
+	snprintf(ts->output_full_filename, sizeof(ts->output_full_filename), "%s/%s",
52
+		ts->output_dirname, ts->output_filename);
53
+}
54
+
55
+static void report_file_creation(struct ts *ts, char *text_prefix, char *filename) {
56
+	char qdepth[32];
57
+	qdepth[0] = '\0';
58
+	if (ts->packet_queue->items)
59
+		snprintf(qdepth, sizeof(qdepth), " (depth:%d)", ts->packet_queue->items);
60
+	p_info("%s%s%s\n", text_prefix, filename, qdepth);
61
+}
62
+
63
+static void create_output_directory(struct ts *ts) {
64
+	if (!ts->create_dirs)
65
+		return;
66
+	if (!file_exists(ts->output_dirname)) {
67
+		p_info(" = Create directory %s", ts->output_dirname);
68
+		create_dir(ts->output_dirname, dir_perm);
69
+	}
70
+}
71
+
72
+static int create_output_file(struct ts *ts) {
73
+	char *filename = ts->output_filename;
74
+	if (ts->create_dirs)
75
+		filename = ts->output_full_filename;
76
+	create_output_directory(ts);
77
+	report_file_creation(ts, " = Create new file ", filename);
78
+	int fd = open(ts->output_filename, O_CREAT | O_WRONLY | O_TRUNC, 0644);
79
+	if (fd < 0) {
80
+		p_err("Can't create output file %s", ts->output_filename);
81
+		return -1;
82
+	}
83
+	if (ts->create_dirs) {
84
+		link(ts->output_filename, ts->output_full_filename);
85
+	}
86
+	return fd;
87
+}
88
+
89
+static int append_output_file(struct ts *ts) {
90
+	char *filename = ts->output_filename;
91
+	if (ts->create_dirs)
92
+		filename = ts->output_full_filename;
93
+	create_output_directory(ts);
94
+	report_file_creation(ts, " + Append to file ", filename);
95
+	int fd = open(ts->output_filename, O_APPEND | O_WRONLY);
96
+	if (fd < 0) {
97
+		p_err("Can't append to output file %s", ts->output_filename);
98
+		return -1;
99
+	}
100
+	if (ts->create_dirs) {
101
+		link(ts->output_filename, ts->output_full_filename);
102
+	}
103
+	return fd;
104
+}
105
+
106
+static void close_output_file(struct ts *ts, int unlink_file) {
107
+	if (ts->output_fd > -1) {
108
+		close(ts->output_fd);
109
+		if (unlink_file && ts->create_dirs) {
110
+			// The file is hard linked into the subdirectory. There is no need
111
+			// to keep it in the main directory.
112
+			unlink(ts->output_filename);
113
+		}
114
+	}
115
+}
116
+
117
+static void handle_files(struct ts *ts, struct packet *packet) {
118
+	int file_time = ALIGN_DOWN(packet->ts.tv_sec, ts->rotate_secs);
119
+
120
+	// Is this file already created?
121
+	if (file_time <= ts->output_startts)
122
+		return;
123
+
124
+	close_output_file(ts, UNLINK_OLD);
125
+	format_output_filename(ts, file_time);
126
+
127
+	/*
128
+	 * When tsdumper2 is started, try to continue writing into "current" file.
129
+	 * This allows the program to be killed/restarted.
130
+	 *
131
+	 * If current file does not exist, create new file with the time of the start
132
+	 * (not aligned to rotate_secs).
133
+	 */
134
+	int append = 0;
135
+	if (ts->output_fd < 0) { // First file (or error).
136
+		append = file_exists(ts->output_filename);
137
+		if (!append) { // Create first file *NOT ALIGNED*
138
+			format_output_filename(ts, packet->ts.tv_sec);
139
+		}
140
+	}
141
+
142
+	ts->output_fd = append ? append_output_file(ts) : create_output_file(ts);
143
+}
144
+
145
+void *write_thread(void *_ts) {
146
+	struct ts *ts = _ts;
147
+	struct packet *packet;
148
+
149
+	mode_t umask_val = umask(0);
150
+	dir_perm = (0777 & ~umask_val) | (S_IWUSR | S_IXUSR);
151
+
152
+	set_thread_name("tsdump-write");
153
+	while ((packet = queue_get(ts->packet_queue))) {
154
+		if (!packet->data_len)
155
+			continue;
156
+
157
+		time_t packet_time = packet->ts.tv_sec;
158
+		time_t file_time   = ALIGN_DOWN(packet_time, ts->rotate_secs);
159
+		p_dbg1(" - Got packet %d, size: %u, file_time:%lu packet_time:%lu depth:%d\n",
160
+			packet->num, packet->data_len, file_time, packet_time, ts->packet_queue->items);
161
+
162
+		handle_files(ts, packet);
163
+
164
+		if (ts->output_fd > -1) {
165
+			p_dbg2(" - Writing into fd:%d size:%d file:%s\n", ts->output_fd, packet->data_len, ts->output_filename);
166
+			ssize_t written = write(ts->output_fd, packet->data, packet->data_len);
167
+			if (written != packet->data_len) {
168
+				p_err("Can not write data (fd:%d written %zd of %d file:%s)",
169
+					ts->output_fd, written, packet->data_len, ts->output_filename);
170
+			}
171
+		}
172
+		free_packet(packet);
173
+	}
174
+	close_output_file(ts, NO_UNLINK);
175
+	return NULL;
176
+}
177
+
178
+static struct packet *add_to_queue(struct ts *ts) {
179
+	queue_add(ts->packet_queue, ts->current_packet);
180
+	ts->current_packet = alloc_packet(ts);
181
+	return ts->current_packet;
182
+}
183
+
184
+void process_packets(struct ts *ts, uint8_t *ts_packet, ssize_t readen) {
185
+	struct timeval now;
186
+	struct packet *packet = ts->current_packet;
187
+
188
+	if (packet->data_len + readen < PACKET_MAX_LENGTH) {
189
+		// Add data to buffer
190
+		memcpy(packet->data + packet->data_len, ts_packet, readen);
191
+		packet->data_len += readen;
192
+	} else {
193
+		// Too much data, add to queue
194
+		p_dbg1("*** Reached buffer end (%zd + %zd > %d)\n", packet->data_len + readen, readen, PACKET_MAX_LENGTH);
195
+		packet = add_to_queue(ts);
196
+	}
197
+
198
+	if (!packet->ts.tv_sec)
199
+		gettimeofday(&packet->ts, NULL);
200
+
201
+	gettimeofday(&now, NULL);
202
+	unsigned long long diff = timeval_diff_msec(&packet->ts, &now);
203
+	if (diff > PACKET_MAX_TIME) {
204
+		// Too much time have passed, add to queue
205
+		p_dbg1("+++ Reached time limit (%llu > %d)\n", diff, PACKET_MAX_TIME);
206
+		add_to_queue(ts);
207
+	}
208
+}

+ 313
- 0
tsdumper2.c View File

@@ -0,0 +1,313 @@
1
+/*
2
+ * tsdumper2
3
+ * Copyright (C) 2013 Unix Solutions Ltd.
4
+ *
5
+ * This program is free software; you can redistribute it and/or modify
6
+ * it under the terms of the GNU General Public License version 2
7
+ * as published by the Free Software Foundation.
8
+ *
9
+ * This program is distributed in the hope that it will be useful,
10
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
+ * GNU General Public License (COPYING file) for more details.
13
+ *
14
+ */
15
+#include <stdlib.h>
16
+#include <stdarg.h>
17
+#include <unistd.h>
18
+#include <getopt.h>
19
+#include <string.h>
20
+#include <sys/types.h>
21
+#include <sys/stat.h>
22
+#include <signal.h>
23
+#include <fcntl.h>
24
+#include <errno.h>
25
+#include <sys/resource.h>
26
+
27
+#include "tsdumper2.h"
28
+
29
+extern int ai_family;
30
+
31
+#define PROGRAM_NAME "tsdumper2"
32
+static const char *program_id = PROGRAM_NAME " v" VERSION " (git-" GIT_VER ", build date " BUILD_ID ")";
33
+
34
+static int keep_running = 1;
35
+static unsigned long long total_read;
36
+
37
+static const char short_options[] = "n:s:d:i:z46DhV";
38
+
39
+static const struct option long_options[] = {
40
+	{ "prefix",				required_argument, NULL, 'n' },
41
+	{ "seconds",			required_argument, NULL, 's' },
42
+	{ "output-dir",			required_argument, NULL, 'd' },
43
+	{ "create-dirs",		no_argument,       NULL, 'D' },
44
+
45
+	{ "input",				required_argument, NULL, 'i' },
46
+	{ "input-ignore-disc",	no_argument,       NULL, 'z' },
47
+	{ "ipv4",				no_argument,       NULL, '4' },
48
+	{ "ipv6",				no_argument,       NULL, '6' },
49
+
50
+	{ "help",				no_argument,       NULL, 'h' },
51
+	{ "version",			no_argument,       NULL, 'V' },
52
+
53
+	{ 0, 0, 0, 0 }
54
+};
55
+
56
+static void show_help(struct ts *ts) {
57
+	printf("%s\n", program_id);
58
+	printf("Copyright (C) 2013 Unix Solutions Ltd.\n");
59
+	printf("\n");
60
+	printf("	Usage: " PROGRAM_NAME " -n <name> -i <input>\n");
61
+	printf("\n");
62
+	printf("Settings:\n");
63
+	printf(" -n --prefix <name>         | Filename prefix.\n");
64
+	printf(" -s --seconds <seconds>     | How much to save (default: %u sec).\n", ts->rotate_secs);
65
+	printf(" -d --output-dir <dir>      | Startup directory (default: %s).\n", ts->output_dir);
66
+	printf(" -D --create-dirs           | Save files in subdirs YYYY/MM/DD/HH/file.\n");
67
+	printf("\n");
68
+	printf("Input options:\n");
69
+	printf(" -i --input <source>        | Where to read from. Multicast address.\n");
70
+	printf("                            .  -i udp://224.0.0.1:5000    (v4 multicast)\n");
71
+	printf("                            .  -i udp://[ff01::1111]:5000 (v6 multicast)\n");
72
+	printf(" -z --input-ignore-disc     | Do not report discontinuty errors in input.\n");
73
+	printf(" -4 --ipv4                  | Use only IPv4 addresses.\n");
74
+	printf(" -6 --ipv6                  | Use only IPv6 addresses.\n");
75
+	printf("\n");
76
+	printf("Misc options:\n");
77
+	printf(" -h --help                  | Show help screen.\n");
78
+	printf(" -V --version               | Show program version.\n");
79
+	printf("\n");
80
+}
81
+
82
+static int parse_io_param(struct io *io, char *opt) {
83
+	int port_set = 0;
84
+	io->type = NET_IO;
85
+	int host_set = parse_host_and_port(opt, &io->hostname, &io->service, &port_set);
86
+	return !(!port_set || !host_set);
87
+}
88
+
89
+extern char *optarg;
90
+extern int optind, opterr, optopt;
91
+
92
+static void parse_options(struct ts *ts, int argc, char **argv) {
93
+	int j, input_addr_err = 1;
94
+	opterr = 0; // Prevent printing of error messages for unknown options in getopt()
95
+	while ((j = getopt_long(argc, argv, short_options, long_options, NULL)) != -1) {
96
+		if (j == '?')
97
+			die("Unknown parameter '%s'.\n", argv[optind - 1]);
98
+		switch (j) {
99
+			case 'n': // --prefix
100
+				ts->prefix = optarg;
101
+				if (strlen(optarg) >= PREFIX_MAX_LENGTH)
102
+					die("Prefix is longer than %d characters!", PREFIX_MAX_LENGTH);
103
+				break;
104
+			case 's': // --seconds
105
+				ts->rotate_secs = atoi(optarg);
106
+				break;
107
+			case 'd': // --output-dir
108
+				ts->output_dir = optarg;
109
+				break;
110
+			case 'D': // --create-dirs
111
+				ts->create_dirs = !ts->create_dirs;
112
+				break;
113
+			case 'i': // --input
114
+				input_addr_err = !parse_io_param(&ts->input, optarg);
115
+				break;
116
+			case 'z': // --input-ignore-disc
117
+				ts->ts_discont = !ts->ts_discont;
118
+				break;
119
+			case '4': // --ipv4
120
+				ai_family = AF_INET;
121
+				break;
122
+			case '6': // --ipv6
123
+				ai_family = AF_INET6;
124
+				break;
125
+			case 'h': // --help
126
+				show_help(ts);
127
+				exit(EXIT_SUCCESS);
128
+			case 'V': // --version
129
+				printf("%s\n", program_id);
130
+				exit(EXIT_SUCCESS);
131
+		}
132
+	}
133
+	if (input_addr_err || !ts->prefix) {
134
+		show_help(ts);
135
+		if (!ts->prefix)
136
+			fprintf(stderr, "ERROR: File name prefix is not set (--prefix XXX | -n XXX).\n");
137
+		if (input_addr_err)
138
+			fprintf(stderr, "ERROR: Input address is invalid (--input XXX | -i XXX).\n");
139
+		exit(EXIT_FAILURE);
140
+	}
141
+
142
+	p_info("Prefix     : %s\n", ts->prefix);
143
+	p_info("Input addr : udp://%s:%s/\n", ts->input.hostname, ts->input.service);
144
+	p_info("Seconds    : %u\n", ts->rotate_secs);
145
+	p_info("Output dir : %s (create directories: %s)\n", ts->output_dir,
146
+		ts->create_dirs ? "YES" : "no");
147
+	if (chdir(ts->output_dir) < 0)
148
+		die("Can not change directory to %s: %s\n", ts->output_dir, strerror(errno));
149
+}
150
+
151
+void signal_quit(int sig) {
152
+	if (!keep_running)
153
+		raise(sig);
154
+	keep_running = 0;
155
+	p_info("Killed %s with signal %d\n", program_id, sig);
156
+	signal(sig, SIG_DFL);
157
+}
158
+
159
+static void clear_packet(struct packet *p) {
160
+	p->ts.tv_sec  = 0;
161
+	p->ts.tv_usec = 0;
162
+	p->data_len   = 0;
163
+	p->allocated  = 0;
164
+	p->in_use     = 0;
165
+}
166
+
167
+struct packet *alloc_packet(struct ts *ts) {
168
+	// check for free static allocations
169
+	struct packet *p;
170
+	int i;
171
+	for (i = 0; i < NUM_PACKETS; i++) {
172
+		p = &ts->packets[i];
173
+		if (!p->in_use) {
174
+			p->in_use = 1;
175
+			p_dbg2("STATIC packet, num %d\n", p->num);
176
+			goto OUT;
177
+		}
178
+	}
179
+	// Dynamically allocate packet
180
+	p = malloc(sizeof(struct packet));
181
+	if (!p)
182
+		die("Can't alloc %lu bytes.\n", (unsigned long)sizeof(struct packet));
183
+	clear_packet(p);
184
+	p->num       = time(NULL);
185
+	p->allocated = 1;
186
+	p_dbg2("ALLOC  packet, num %d\n", p->num);
187
+OUT:
188
+	return p;
189
+}
190
+
191
+void free_packet(struct packet *packet) {
192
+	if (!packet->allocated) {
193
+		clear_packet(packet);
194
+		return;
195
+	}
196
+	p_dbg2("FREE   packet, num %d\n", packet->num);
197
+	free(packet);
198
+}
199
+
200
+#define RTP_HDR_SZ  12
201
+
202
+static uint8_t ts_packet[FRAME_SIZE + RTP_HDR_SZ];
203
+static uint8_t rtp_hdr[2][RTP_HDR_SZ];
204
+static struct ts ts;
205
+
206
+int main(int argc, char **argv) {
207
+	ssize_t readen;
208
+	int i;
209
+	int have_data = 1;
210
+	int ntimeouts = 0;
211
+	int rtp_hdr_pos = 0, num_packets = 0;
212
+	struct rlimit rl;
213
+
214
+	if (getrlimit(RLIMIT_STACK, &rl) == 0) {
215
+		if (rl.rlim_cur > THREAD_STACK_SIZE) {
216
+			rl.rlim_cur = THREAD_STACK_SIZE;
217
+			setrlimit(RLIMIT_STACK, &rl);
218
+		}
219
+	}
220
+
221
+	memset(rtp_hdr[0], 0, RTP_HDR_SZ);
222
+	memset(rtp_hdr[1], 0, RTP_HDR_SZ);
223
+
224
+	for (i = 0; i < NUM_PACKETS; i++) {
225
+		struct packet *p = &ts.packets[i];
226
+		p->num = i + 1;
227
+	}
228
+
229
+	ts.ts_discont     = 1;
230
+	ts.output_dir     = ".";
231
+	ts.rotate_secs    = 60;
232
+	ts.current_packet = alloc_packet(&ts);
233
+	ts.output_fd      = -1;
234
+
235
+	pthread_attr_init(&ts.thread_attr);
236
+	size_t stack_size;
237
+	pthread_attr_getstacksize(&ts.thread_attr, &stack_size);
238
+	if (stack_size > THREAD_STACK_SIZE)
239
+		pthread_attr_setstacksize(&ts.thread_attr, THREAD_STACK_SIZE);
240
+
241
+	parse_options(&ts, argc, argv);
242
+
243
+	ts.packet_queue   = queue_new();
244
+
245
+	p_info("Start %s\n", program_id);
246
+
247
+	if (ts.input.type == NET_IO && udp_connect_input(&ts.input) < 1)
248
+		goto EXIT;
249
+
250
+	signal(SIGCHLD, SIG_IGN);
251
+	signal(SIGPIPE, SIG_IGN);
252
+
253
+	signal(SIGINT , signal_quit);
254
+	signal(SIGTERM, signal_quit);
255
+
256
+	pthread_create(&ts.write_thread , &ts.thread_attr, &write_thread , &ts);
257
+
258
+	int data_received = 0;
259
+	do {
260
+		set_log_io_errors(0);
261
+		if (!ts.rtp_input) {
262
+			readen = fdread_ex(ts.input.fd, (char *)ts_packet, FRAME_SIZE, 250, 4, 1);
263
+		} else {
264
+			readen = fdread_ex(ts.input.fd, (char *)ts_packet, FRAME_SIZE + RTP_HDR_SZ, 250, 4, 1);
265
+			if (readen > RTP_HDR_SZ) {
266
+				memcpy(rtp_hdr[rtp_hdr_pos], ts_packet, RTP_HDR_SZ);
267
+				memmove(ts_packet, ts_packet + RTP_HDR_SZ, FRAME_SIZE);
268
+				readen -= RTP_HDR_SZ;
269
+				uint16_t ssrc  = (rtp_hdr[rtp_hdr_pos][2] << 8) | rtp_hdr[rtp_hdr_pos][3];
270
+				uint16_t pssrc = (rtp_hdr[!rtp_hdr_pos][2] << 8) | rtp_hdr[!rtp_hdr_pos][3];
271
+				rtp_hdr_pos = !rtp_hdr_pos;
272
+				if (pssrc + 1 != ssrc && (ssrc != 0 && pssrc != 0xffff) && num_packets > 2)
273
+					if (ts.ts_discont)
274
+						p_info(" *** RTP discontinuity last_ssrc %5d, curr_ssrc %5d, lost %d packet ***\n",
275
+							pssrc, ssrc, ((ssrc - pssrc)-1) & 0xffff);
276
+				num_packets++;
277
+			}
278
+		}
279
+		set_log_io_errors(1);
280
+		if (readen < 0) {
281
+			p_info(" *** Input read timeout ***\n");
282
+			data_received = 0;
283
+			ntimeouts++;
284
+		} else {
285
+			if (ntimeouts && readen > 0) {
286
+				ntimeouts = 0;
287
+			}
288
+		}
289
+		if (readen > 0) {
290
+			if (!data_received) {
291
+				p_info("Data received.\n");
292
+				data_received = 1;
293
+			}
294
+			total_read += readen;
295
+			process_packets(&ts, ts_packet, readen);
296
+		}
297
+		if (!keep_running)
298
+			break;
299
+	} while (have_data);
300
+EXIT:
301
+
302
+	queue_add(ts.packet_queue, ts.current_packet);
303
+	queue_add(ts.packet_queue, NULL); // Exit write_thread
304
+	pthread_join(ts.write_thread, NULL);
305
+
306
+	p_info("Stop %s (bytes_processed:%llu).\n", program_id, total_read);
307
+
308
+	queue_free(&ts.packet_queue);
309
+
310
+	pthread_attr_destroy(&ts.thread_attr);
311
+
312
+	exit(EXIT_SUCCESS);
313
+}

+ 105
- 0
tsdumper2.h View File

@@ -0,0 +1,105 @@
1
+/*
2
+ * Data definitions
3
+ * Copyright (C) 2013 Unix Solutions Ltd.
4
+ *
5
+ * This program is free software; you can redistribute it and/or modify
6
+ * it under the terms of the GNU General Public License version 2
7
+ * as published by the Free Software Foundation.
8
+ *
9
+ * This program is distributed in the hope that it will be useful,
10
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
+ * GNU General Public License (COPYING file) for more details.
13
+ *
14
+ */
15
+#ifndef DATA_H
16
+#define DATA_H
17
+
18
+#include <pthread.h>
19
+#include <inttypes.h>
20
+#include <stdbool.h>
21
+
22
+#include "libfuncs/libfuncs.h"
23
+#include "util.h"
24
+
25
+// Supported values 0, 1 and 2. Higher value equals more spam in the log.
26
+#define DEBUG 0
27
+
28
+// 7 * 188
29
+#define FRAME_SIZE 1316
30
+
31
+// 64k should be enough for everybody
32
+#define THREAD_STACK_SIZE (64 * 1024)
33
+
34
+enum io_type {
35
+	FILE_IO,
36
+	NET_IO,
37
+	WTF_IO
38
+};
39
+
40
+// 1.2MB = ~13Mbit/s
41
+#define PACKET_MAX_LENGTH (1316 * 1024)
42
+
43
+// Maximum packet fill time in ms
44
+#define PACKET_MAX_TIME 1000
45
+
46
+#define PREFIX_MAX_LENGTH 64
47
+
48
+// PREFIX-20130717_000900-1374008940.ts (PREFIX-YYYYMMDD_HHMMSS-0123456789.ts)
49
+#define OUTFILE_NAME_MAX  (PREFIX_MAX_LENGTH + 128)
50
+
51
+#define NUM_PACKETS 16
52
+
53
+struct packet {
54
+	int					num;
55
+	struct timeval		ts;							// packet start time
56
+	int					allocated;					// set to true if the struct is dynamically allocated
57
+	int					in_use;						// this packet is currently being used
58
+	int					data_len;					// data length
59
+	uint8_t				data[PACKET_MAX_LENGTH];	// the data
60
+};
61
+
62
+struct io {
63
+	int					fd;
64
+	enum io_type		type;
65
+	char				*hostname;
66
+	char				*service;
67
+};
68
+
69
+struct ts {
70
+	char				*prefix;
71
+	char				*output_dir;
72
+	int					create_dirs;
73
+	int					rotate_secs;
74
+	int					ts_discont;
75
+	int					rtp_input;
76
+	struct io			input;
77
+
78
+	pthread_attr_t		thread_attr;
79
+	pthread_t			write_thread;
80
+
81
+	struct packet		packets[NUM_PACKETS];
82
+	int					packet_ptr;
83
+
84
+	struct packet		*current_packet;
85
+	QUEUE				*packet_queue;
86
+
87
+	int					output_fd;
88
+	time_t				output_startts;
89
+	char				output_dirname[OUTFILE_NAME_MAX];
90
+	char				output_filename[OUTFILE_NAME_MAX];
91
+	char				output_full_filename[OUTFILE_NAME_MAX];
92
+};
93
+
94
+// From tsdumper2.c
95
+struct packet *alloc_packet(struct ts *ts);
96
+void free_packet(struct packet *packet);
97
+
98
+// From process.c
99
+void *write_thread(void *_ts);
100
+void process_packets(struct ts *ts, uint8_t *ts_packet, ssize_t readen);
101
+
102
+// From udp.c
103
+int udp_connect_input(struct io *io);
104
+
105
+#endif

+ 150
- 0
udp.c View File

@@ -0,0 +1,150 @@
1
+/*
2
+ * UDP functions
3
+ * Copyright (C) 2013 Unix Solutions Ltd.
4
+ *
5
+ * This program is free software; you can redistribute it and/or modify
6
+ * it under the terms of the GNU General Public License version 2
7
+ * as published by the Free Software Foundation.
8
+ *
9
+ * This program is distributed in the hope that it will be useful,
10
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
+ * GNU General Public License (COPYING file) for more details.
13
+ *
14
+ */
15
+#include <stdio.h>
16
+#include <stdlib.h>
17
+#include <string.h>
18
+#include <sys/types.h>
19
+#include <sys/stat.h>
20
+#include <unistd.h>
21
+#include <fcntl.h>
22
+#include <sys/socket.h>
23
+#include <netinet/in.h>
24
+#include <arpa/inet.h>
25
+#include <errno.h>
26
+
27
+#include "tsdumper2.h"
28
+
29
+#ifndef IPV6_ADD_MEMBERSHIP
30
+#define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP
31
+#define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP
32
+#endif
33
+
34
+int ai_family = AF_UNSPEC;
35
+
36
+static int is_multicast(struct sockaddr_storage *addr) {
37
+	int ret = 0;
38
+	switch (addr->ss_family) {
39
+	case AF_INET: {
40
+		struct sockaddr_in *addr4 = (struct sockaddr_in *)addr;
41
+		ret = IN_MULTICAST(ntohl(addr4->sin_addr.s_addr));
42
+		break;
43
+	}
44
+	case AF_INET6: {
45
+		struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)addr;
46
+		ret = IN6_IS_ADDR_MULTICAST(&addr6->sin6_addr);
47
+		break;
48
+	} }
49
+	return ret;
50
+}
51
+
52
+static int bind_addr(const char *hostname, const char *service, int socktype, struct sockaddr_storage *addr, int *addrlen, int *sock) {
53
+	struct addrinfo hints, *res, *ressave;
54
+	int n, ret = -1;
55
+
56
+	memset(&hints, 0, sizeof(struct addrinfo));
57
+	hints.ai_family = ai_family;
58
+	hints.ai_socktype = socktype;
59
+
60
+	n = getaddrinfo(hostname, service, &hints, &res);
61
+	if (n < 0) {
62
+		p_info("ERROR: getaddrinfo(%s): %s\n", hostname, gai_strerror(n));
63
+		return ret;
64
+	}
65
+
66
+	ressave = res;
67
+	while (res) {
68
+		*sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
69
+		if (*sock > -1) {
70
+			int on = 1;
71
+			setsockopt(*sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
72
+			set_sock_nonblock(*sock);
73
+			if (bind(*sock, res->ai_addr, res->ai_addrlen) == 0) {
74
+				memcpy(addr, res->ai_addr, res->ai_addrlen);
75
+				*addrlen = res->ai_addrlen;
76
+				ret = 0;
77
+				goto OUT;
78
+			} else {
79
+				char str_addr[INET6_ADDRSTRLEN];
80
+				my_inet_ntop(res->ai_family, res->ai_addr, str_addr, sizeof(str_addr));
81
+				p_err("bind: %s:%s (%s)", hostname, service, str_addr);
82
+			}
83
+			close(*sock);
84
+			*sock = -1;
85
+		}
86
+		res = res->ai_next;
87
+	}
88
+OUT:
89
+	freeaddrinfo(ressave);
90
+
91
+	return ret;
92
+}
93
+
94
+static int join_multicast_group(int sock, struct sockaddr_storage *addr) {
95
+	switch (addr->ss_family) {
96
+	case AF_INET: {
97
+		struct ip_mreq mreq;
98
+		mreq.imr_multiaddr.s_addr = ((struct sockaddr_in *)addr)->sin_addr.s_addr;
99
+		mreq.imr_interface.s_addr = INADDR_ANY;
100
+
101
+		if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (const void *)&mreq, sizeof(mreq)) < 0) {
102
+			p_err("setsockopt(IP_ADD_MEMBERSHIP)");
103
+			return -1;
104
+		}
105
+		break;
106
+	}
107
+
108
+	case AF_INET6: {
109
+		struct ipv6_mreq mreq6;
110
+		memcpy(&mreq6.ipv6mr_multiaddr, &(((struct sockaddr_in6 *)addr)->sin6_addr), sizeof(struct in6_addr));
111
+		mreq6.ipv6mr_interface = 0; // interface index, will be set later
112
+
113
+		if (setsockopt(sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mreq6, sizeof(mreq6)) < 0) {
114
+			p_err("setsockopt(IPV6_ADD_MEMBERSHIP)");
115
+			return -1;
116
+		}
117
+		break;
118
+	}
119
+	}
120
+
121
+	return 0;
122
+}
123
+
124
+int udp_connect_input(struct io *io) {
125
+	struct sockaddr_storage addr;
126
+	int addrlen = sizeof(addr);
127
+	int sock = -1;
128
+
129
+	memset(&addr, 0, sizeof(addr));
130
+
131
+	p_info("Connecting input to %s port %s\n", io->hostname, io->service);
132
+	if (bind_addr(io->hostname, io->service, SOCK_DGRAM, &addr, &addrlen, &sock) < 0)
133
+		return -1;
134
+
135
+	/* Set receive buffer size to ~4.0MB */
136
+	int bufsize = (4000000 / 1316) * 1316;
137
+	setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (void *)&bufsize, sizeof(bufsize));
138
+
139
+	if (is_multicast(&addr)) {
140
+		if (join_multicast_group(sock, &addr) < 0) {
141
+			close(sock);
142
+			return -1;
143
+		}
144
+	}
145
+
146
+	io->fd = sock;
147
+	p_info("Input connected to fd:%d\n", io->fd);
148
+
149
+	return 1;
150
+}

+ 167
- 0
util.c View File

@@ -0,0 +1,167 @@
1
+/*
2
+ * Utility functions
3
+ * Copyright (C) 2013 Unix Solutions Ltd.
4
+ *
5
+ * This program is free software; you can redistribute it and/or modify
6
+ * it under the terms of the GNU General Public License version 2
7
+ * as published by the Free Software Foundation.
8
+ *
9
+ * This program is distributed in the hope that it will be useful,
10
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
+ * GNU General Public License (COPYING file) for more details.
13
+ *
14
+ */
15
+
16
+#include <stdio.h>
17
+#include <stdarg.h>
18
+#include <stdlib.h>
19
+#include <unistd.h>
20
+#include <ctype.h>
21
+#include <time.h>
22
+#include <string.h>
23
+#include <errno.h>
24
+#include <arpa/inet.h>
25
+#include <sys/stat.h>
26
+#include <sys/types.h>
27
+
28
+#include "tsdumper2.h"
29
+
30
+#ifdef __linux__
31
+#include <sys/prctl.h>
32
+
33
+void set_thread_name(char *thread_name) {
34
+	prctl(PR_SET_NAME, thread_name, NULL, NULL, NULL);
35
+}
36
+
37
+#else
38
+void set_thread_name(char *thread_name) {
39
+    (void)thread_name;
40
+}
41
+
42
+#endif
43
+
44
+int parse_host_and_port(char *input, char **hostname, char **service, int *port_set) {
45
+	char *p, *proto;
46
+	if (strlen(input) == 0)
47
+		return 0;
48
+	proto = strstr(input, "http://");
49
+	if (proto == input)
50
+		die("HTTP input is unsupported (patch welcome): %s", input);
51
+	proto = strstr(input, "://");
52
+	if (proto)
53
+		input = proto + 3;
54
+	*hostname = input;
55
+	if (input[0] == '[') { // Detect IPv6 static address
56
+		p = strrchr(input, ']');
57
+		if (!p)
58
+			die("Invalid IPv6 address format: %s\n", input);
59
+		*hostname = input + 1; // Remove first [
60
+		*p = 0x00; // Remove last ]
61
+		char *p2 = strchr(p + 1, ':');
62
+		if (p2) {
63
+			*p2 = 0x00;
64
+			*service = p2 + 1;
65
+			*port_set = 1;
66
+		}
67
+	} else {
68
+		p = strrchr(input, ':');
69
+		if (p) {
70
+			*p = 0x00;
71
+			*service = p + 1;
72
+			*port_set = 1;
73
+		}
74
+	}
75
+	if (*service) {
76
+		char *path = strstr(*service, "/");
77
+		if (path)
78
+			path[0] = 0;
79
+	}
80
+	return 1;
81
+}
82
+
83
+char *my_inet_ntop(int family, struct sockaddr *addr, char *dest, int dest_len) {
84
+	struct sockaddr_in  *addr_v4 = (struct sockaddr_in  *)addr;
85
+	struct sockaddr_in6 *addr_v6 = (struct sockaddr_in6 *)addr;
86
+	switch (family) {
87
+		case AF_INET:
88
+			return (char *)inet_ntop(AF_INET, &addr_v4->sin_addr, dest, dest_len);
89
+			break;
90
+		case AF_INET6:
91
+			return (char *)inet_ntop(AF_INET6, &addr_v6->sin6_addr, dest, dest_len);
92
+			break;
93
+		default:
94
+			memset(dest, 0, dest_len);
95
+			strcpy(dest, "unknown");
96
+			return dest;
97
+	}
98
+}
99
+
100
+int create_dir(const char *dir, mode_t mode) {
101
+	int ret = 0;
102
+	unsigned int i;
103
+
104
+	// Shortcut
105
+	if (strchr(dir, '/') == NULL)
106
+		return mkdir(dir, mode);
107
+
108
+	char *d = strdup(dir);
109
+	unsigned int dlen = strlen(dir);
110
+
111
+	// Skip first char (it can be /)
112
+	for (i = 1; i < dlen; i++) {
113
+		if (d[i] != '/')
114
+			continue;
115
+		d[i] = '\0';
116
+		ret = mkdir(d, mode);
117
+		d[i] = '/';
118
+		if (ret < 0 && errno != EEXIST)
119
+			goto OUT;
120
+	}
121
+	ret = mkdir(d, mode);
122
+OUT:
123
+	free(d);
124
+	return ret;
125
+}
126
+
127
+void die(const char *fmt, ...) {
128
+	va_list args;
129
+	va_start(args, fmt);
130
+	fprintf(stderr, "ERROR: ");
131
+	vfprintf(stderr, fmt, args);
132
+	if (fmt[strlen(fmt) - 1] != '\n')
133
+		fprintf(stderr, "\n");
134
+	va_end(args);
135
+	exit(EXIT_FAILURE);
136
+}
137
+
138
+void p_err(const char *fmt, ...) {
139
+	va_list args;
140
+	va_start(args, fmt);
141
+	fprintf(stderr, "ERROR: ");
142
+	vfprintf(stderr, fmt, args);
143
+	if (fmt[strlen(fmt) - 1] != '\n')
144
+		fprintf(stderr, "\n");
145
+	va_end(args);
146
+}
147
+
148
+void p_info(const char *fmt, ...) {
149
+	if (DEBUG > 0) {
150
+		struct timeval tv;
151
+		gettimeofday(&tv, NULL);
152
+		fprintf(stdout, "%08ld.%08ld ", tv.tv_sec, tv.tv_usec);
153
+
154
+		char date[64];
155
+		struct tm tm;
156
+		localtime_r(&tv.tv_sec, &tm);
157
+		strftime(date, sizeof(date), "%F %H:%M:%S", localtime_r(&tv.tv_sec, &tm));
158
+		fprintf(stdout, "%s | ", date);
159
+	}
160
+	va_list args;
161
+	va_start(args, fmt);
162
+	vfprintf(stdout, fmt, args);
163
+	if (fmt[strlen(fmt) - 1] != '\n')
164
+		fprintf(stdout, "\n");
165
+	va_end(args);
166
+	fflush(stdout);
167
+}

+ 39
- 0
util.h View File

@@ -0,0 +1,39 @@
1
+/*
2
+ * Utility functions header
3
+ * Copyright (C) 2013 Unix Solutions Ltd.
4
+ *
5
+ * This program is free software; you can redistribute it and/or modify
6
+ * it under the terms of the GNU General Public License version 2
7
+ * as published by the Free Software Foundation.
8
+ *
9
+ * This program is distributed in the hope that it will be useful,
10
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
+ * GNU General Public License (COPYING file) for more details.
13
+ *
14
+ */
15
+#ifndef UTIL_H
16
+#define UTIL_H
17
+
18
+#include <inttypes.h>
19
+#include <arpa/inet.h>
20
+
21
+void set_thread_name(char *thread_name);
22
+
23
+int parse_host_and_port(char *input, char **hostname, char **service, int *port_set);
24
+char *my_inet_ntop(int family, struct sockaddr *addr, char *dest, int dest_len);
25
+
26
+int create_dir(const char *dir, mode_t mode);
27
+
28
+#define p_dbg1(fmt, ...) \
29
+	do { if (DEBUG > 0) p_info(fmt, __VA_ARGS__); } while(0)
30
+
31
+#define p_dbg2(fmt, ...) \
32
+	do { if (DEBUG > 1) p_info(fmt, __VA_ARGS__); } while(0)
33
+
34
+__attribute__ ((format(printf, 1, 2))) void die(const char *fmt, ...);
35
+
36
+__attribute__ ((format(printf, 1, 2))) void p_err(const char *fmt, ...);
37
+__attribute__ ((format(printf, 1, 2))) void p_info(const char *fmt, ...);
38
+
39
+#endif

Loading…
Cancel
Save