1 /*
2  *  This file is part of vban_emitter.
3  *  Copyright (c) 2018 by Benoît Quiniou <quiniouben@yahoo.fr>
4  *
5  *  vban_emitter is free software: you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation, either version 3 of the License, or
8  *  (at your option) any later version.
9  *
10  *  vban_emitter is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with vban_emitter.  If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <signal.h>
23 #include <getopt.h>
24 #include "vban/vban.h"
25 #include "common/version.h"
26 #include "common/socket.h"
27 #include "common/logger.h"
28 
29 struct config_t
30 {
31     struct socket_config_t      socket;
32     char                        stream_name[VBAN_STREAM_NAME_SIZE];
33     int                         bps;
34     int                         ident;
35     int                         format;
36 };
37 
38 struct main_t
39 {
40     socket_handle_t             socket;
41     char                        buffer[VBAN_PROTOCOL_MAX_SIZE];
42 };
43 
usage()44 void usage()
45 {
46     printf("\nUsage: vban_sendtext [OPTIONS] MESSAGE\n\n");
47     printf("-i, --ipaddress=IP      : MANDATORY. ipaddress to send stream to\n");
48     printf("-p, --port=PORT         : MANDATORY. port to use\n");
49     printf("-s, --streamname=NAME   : MANDATORY. streamname to use\n");
50     printf("-b, --bps=VALUE         : Data bitrate indicator. default 0 (no special bitrate)\n");
51     //XXX give allowed value
52 
53     printf("-n, --ident=VALUE       : Subchannel identification. default 0\n");
54     printf("-f, --format=VALUE      : Text format used. can be: 0 (ASCII), 1 (UTF8), 2 (WCHAR), 240 (USER). default 1\n");
55     printf("-l, --loglevel=LEVEL    : Log level, from 0 (FATAL) to 4 (DEBUG). default is 1 (ERROR)\n");
56     printf("-h, --help              : display this message\n\n");
57 }
58 
get_options(struct config_t * config,int argc,char * const * argv)59 int get_options(struct config_t* config, int argc, char* const* argv)
60 {
61     int c = 0;
62     int ret = 0;
63 
64     static const struct option options[] =
65     {
66         {"ipaddress",   required_argument,  0, 'i'},
67         {"port",        required_argument,  0, 'p'},
68         {"streamname",  required_argument,  0, 's'},
69         {"bps",         required_argument,  0, 'b'},
70         {"ident",       required_argument,  0, 'n'},
71         {"format",      required_argument,  0, 'f'},
72         {"loglevel",    required_argument,  0, 'l'},
73         {"help",        no_argument,        0, 'h'},
74         {0,             0,                  0,  0 }
75     };
76 
77     // default values
78     config->bps     = 0;
79     config->ident   = 0;
80     config->format  = 1;
81     config->socket.direction    = SOCKET_OUT;
82 
83     /* yes, I assume config is not 0 */
84     while (1)
85     {
86         c = getopt_long(argc, argv, "i:p:s:b:n:f:l:h", options, 0);
87         if (c == -1)
88             break;
89 
90         switch (c)
91         {
92             case 'i':
93                 strncpy(config->socket.ip_address, optarg, SOCKET_IP_ADDRESS_SIZE-1);
94                 break;
95 
96             case 'p':
97                 config->socket.port = atoi(optarg);
98                 break;
99 
100             case 's':
101                 strncpy(config->stream_name, optarg, VBAN_STREAM_NAME_SIZE-1);
102                 break;
103 
104             case 'b':
105                 config->bps = atoi(optarg);
106                 break;
107 
108             case 'n':
109                 config->ident = atoi(optarg);
110                 break;
111 
112             case 'f':
113                 config->format = atoi(optarg);
114                 break;
115 
116             case 'l':
117                 logger_set_output_level(atoi(optarg));
118                 break;
119 
120             case 'h':
121             default:
122                 usage();
123                 return 1;
124         }
125 
126         if (ret)
127         {
128             return ret;
129         }
130     }
131 
132     /** check if we got all arguments */
133     if ((config->socket.ip_address[0] == 0)
134         || (config->socket.port == 0)
135         || (config->stream_name[0] == 0))
136     {
137         logger_log(LOG_FATAL, "Missing ip address, port or stream name");
138         usage();
139         return 1;
140     }
141 
142     if (optind == argc)
143     {
144         logger_log(LOG_FATAL, "Missing message argument");
145         usage();
146         return 1;
147     }
148     else if (optind < argc - 1)
149     {
150         logger_log(LOG_FATAL, "Too many arguments");
151         usage();
152         return 1;
153     }
154 
155     return 0;
156 }
157 
158 
main(int argc,char * const * argv)159 int main(int argc, char* const* argv)
160 {
161     int ret = 0;
162     struct config_t config;
163     struct main_t   main_s;
164     char const* msg = 0;
165     size_t len = 0;
166     struct VBanHeader* const hdr = (struct VBanHeader*)&main_s.buffer;
167 
168     printf("%s version %s\n\n", argv[0], VBAN_VERSION);
169 
170     memset(&config, 0, sizeof(struct config_t));
171     memset(&main_s, 0, sizeof(struct main_t));
172 
173     ret = get_options(&config, argc, argv);
174     if (ret != 0)
175     {
176         return ret;
177     }
178 
179     msg = argv[argc-1];
180     len = strlen(msg);
181     if (len > VBAN_DATA_MAX_SIZE-1)
182     {
183         logger_log(LOG_FATAL, "Message too long. max lenght is %d", VBAN_DATA_MAX_SIZE-1);
184         usage();
185         return 1;
186     }
187 
188     strncpy((char*)&main_s.buffer + sizeof(struct VBanHeader), msg, VBAN_DATA_MAX_SIZE-1);
189 
190     ret = socket_init(&main_s.socket, &config.socket);
191     if (ret != 0)
192     {
193         return ret;
194     }
195 
196     hdr->vban       = VBAN_HEADER_FOURC;
197     hdr->format_SR  = config.bps | VBAN_PROTOCOL_TXT;
198     hdr->format_nbs = 0;
199     hdr->format_nbc = config.ident;
200     hdr->format_bit = config.format;
201     strncpy(hdr->streamname, config.stream_name, VBAN_STREAM_NAME_SIZE);
202     hdr->nuFrame    = 0;
203 
204     logger_log(LOG_DEBUG, "%s: packet is vban: %u, sr: %d, nbs: %d, nbc: %d, bit: %d, name: %s, nu: %u, msg: %s",
205         __func__, hdr->vban, hdr->format_SR, hdr->format_nbs, hdr->format_nbc, hdr->format_bit, hdr->streamname, hdr->nuFrame, (char*)&main_s.buffer + sizeof(struct VBanHeader));
206 
207     ret = socket_write(main_s.socket, main_s.buffer, len + sizeof(struct VBanHeader));
208 
209     socket_release(&main_s.socket);
210 
211     return ret;
212 }
213 
214