Kannel: Open Source WAP and SMS gateway  $Revision: 5037 $
mtbatch.c
Go to the documentation of this file.
1 /* ====================================================================
2  * The Kannel Software License, Version 1.0
3  *
4  * Copyright (c) 2001-2016 Kannel Group
5  * Copyright (c) 1998-2001 WapIT Ltd.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  * notice, this list of conditions and the following disclaimer.
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright
16  * notice, this list of conditions and the following disclaimer in
17  * the documentation and/or other materials provided with the
18  * distribution.
19  *
20  * 3. The end-user documentation included with the redistribution,
21  * if any, must include the following acknowledgment:
22  * "This product includes software developed by the
23  * Kannel Group (http://www.kannel.org/)."
24  * Alternately, this acknowledgment may appear in the software itself,
25  * if and wherever such third-party acknowledgments normally appear.
26  *
27  * 4. The names "Kannel" and "Kannel Group" must not be used to
28  * endorse or promote products derived from this software without
29  * prior written permission. For written permission, please
30  * contact org@kannel.org.
31  *
32  * 5. Products derived from this software may not be called "Kannel",
33  * nor may "Kannel" appear in their name, without prior written
34  * permission of the Kannel Group.
35  *
36  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
37  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
38  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
39  * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS
40  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
41  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
42  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
43  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
44  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
45  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
46  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
47  * ====================================================================
48  *
49  * This software consists of voluntary contributions made by many
50  * individuals on behalf of the Kannel Group. For more information on
51  * the Kannel Group, please see <http://www.kannel.org/>.
52  *
53  * Portions of this software are based upon software originally written at
54  * WapIT Ltd., Helsinki, Finland for the Kannel project.
55  */
56 
57 /*
58  * mtbatch.c - an MT batch run utility for bearerbox
59  *
60  * This utility reads in a content file which has the SMS text message and
61  * a receivers file, which has receiver numbers in each line. It connects
62  * to bearerbox as if it would be a smsbox and issues the SMS sequentially
63  * to bearerbox.
64  *
65  * Stipe Tolj <stolj@kannel.org>
66  * Vincent Chavanis <v.chavanis@telemaque.fr>
67  *
68  * XXX Add UDH capabilities.
69  * XXX Support more charsets than 7-bit.
70  */
71 
72 #include <string.h>
73 #include <unistd.h>
74 #include <signal.h>
75 
76 #include "gwlib/gwlib.h"
77 
78 #include "msg.h"
79 #include "sms.h"
80 #include "dlr.h"
81 #include "bb.h"
82 #include "shared.h"
83 #include "heartbeat.h"
84 
85 static char *pid_file;
86 static Octstr *smsbox_id = NULL;
87 static Octstr *content = NULL;
88 static List *lines = NULL;
89 static Octstr *bb_host;
90 static long bb_port;
91 static int bb_ssl;
92 static Counter *counter;
93 static Octstr *service = NULL;
94 static Octstr *account = NULL;
95 static Octstr *from = NULL;
96 static int dlr_mask = 0;
97 static Octstr *dlr_url = NULL;
98 static Octstr *smsc_id = NULL;
99 static double delay = 0;
100 static int no_smsbox_id = 0;
101 
102 static void write_pid_file(void) {
103  FILE *f;
104 
105  if (pid_file != NULL) {
106  f = fopen(pid_file, "w");
107  fprintf(f, "%d\n", (int)getpid());
108  fclose(f);
109  }
110 }
111 
112 /***********************************************************************
113  * Communication with the bearerbox.
114  */
115 
116 
117 /*
118  * Identify ourself to bearerbox for smsbox-specific routing inside bearerbox.
119  * Do this even while no smsbox-id is given to unlock the sender thread in
120  * bearerbox.
121  */
122 static void identify_to_bearerbox(void)
123 {
124  Msg *msg;
125 
126  msg = msg_create(admin);
127  msg->admin.command = cmd_identify;
128  msg->admin.boxc_id = octstr_duplicate(smsbox_id);
129  write_to_bearerbox(msg);
130 }
131 
132 
133 /*
134  * Read an Msg from the bearerbox and send it to the proper receiver
135  * via a List. At the moment all messages are sent to the smsbox_requests
136  * List.
137  */
138 static void read_messages_from_bearerbox(void *arg)
139 {
140  time_t start, t;
141  unsigned long secs;
142  unsigned long total_s, total_f, total_ft, total_b, total_o;
143  Msg *msg;
144 
145  total_s = total_f = total_ft = total_b = total_o = 0;
146  start = t = time(NULL);
147  while (program_status != shutting_down) {
148  int ret;
149 
150  /* block infinite for reading messages */
151  ret = read_from_bearerbox(&msg, 0.5);
152  if (ret == -1)
153  break;
154  else if (ret == 1) /* timeout */
155  continue;
156  else if (msg == NULL) /* just to be sure, may not happens */
157  break;
158 
159  if (msg_type(msg) == admin) {
160  if (msg->admin.command == cmd_shutdown ||
161  msg->admin.command == cmd_restart) {
162  info(0, "Bearerbox told us to die");
164  }
165  /*
166  * XXXX here should be suspend/resume, add RSN
167  */
168  msg_destroy(msg);
169  } else if (msg_type(msg) == ack) {
170  counter_increase(counter);
171  switch (msg->ack.nack) {
172  case ack_success:
173  total_s++;
174  break;
175  case ack_failed:
176  total_f++;
177  break;
178  case ack_failed_tmp:
179  total_ft++;
180  break;
181  case ack_buffered:
182  total_b++;
183  break;
184  }
185  msg_destroy(msg);
186  } else {
187  warning(0, "Received other message than ack/admin, ignoring!");
188  msg_destroy(msg);
189  total_o++;
190  }
191  }
192  secs = difftime(time(NULL), start);
193  info(0, "Received acks: %ld success, %ld failed, %ld failed temporarly, %ld queued, %ld other in %ld seconds "
194  "(%.2f per second)", total_s, total_f, total_ft, total_b, total_o, secs,
195  (float)(total_s+total_f+total_ft+total_b) / secs);
196 }
197 
198 /*
199  * Send a message to the bearerbox for delivery to a phone.
200  * Return >= 0 for success & count of splitted sms messages,
201  * -1 for failure. Does not destroy the msg.
202  */
203 static int send_message(Msg *msg)
204 {
205  unsigned long msg_count;
206  List *list;
207 
208  gw_assert(msg != NULL);
209  gw_assert(msg_type(msg) == sms);
210 
211  /*
212  * Encode our smsbox-id to the msg structure.
213  * This will allow bearerbox to return specific answers to the
214  * same smsbox, mainly for DLRs and SMS proxy modes.
215  *
216  * In addition the -x flag can be used to identify the mtbatch
217  * instance with an own smsbox-id, but let the normal smsbox
218  * daemons handle the DLRs coming back, as the mtbatch shuts down
219  * after all MTs have been injected. It's not meant to process
220  * the DLR messages.
221  */
222  if (no_smsbox_id == 0 && smsbox_id != NULL) {
223  msg->sms.boxc_id = octstr_duplicate(smsbox_id);
224  }
225 
226  list = sms_split(msg, NULL, NULL, NULL, NULL, 1, 0, 100, MAX_SMS_OCTETS);
227  msg_count = gwlist_len(list);
229 
230  debug("sms", 0, "message length %ld, sending %ld messages",
231  octstr_len(msg->sms.msgdata), msg_count);
232 
233  if (delay > 0)
235 
236  /* pass message to bearerbox */
237  if (deliver_to_bearerbox(msg) != 0)
238  return -1;
239 
240  return msg_count;
241 }
242 
243 
244 static void help(void)
245 {
246  info(0, "Usage: mtbatch [options] content-file receivers-file ...");
247  info(0, "where options are:");
248  info(0, "-v number");
249  info(0, " set log level for stderr logging");
250  info(0, "-b host");
251  info(0, " defines the host of bearerbox (default: localhost)");
252  info(0, "-p port");
253  info(0, " the smsbox port to connect to (default: 13001)");
254  info(0, "-s");
255  info(0, " inidicatr to use SSL for bearerbox connection (default: no)");
256  info(0, "-i smsbox-id");
257  info(0, " defines the smsbox-id to be used for bearerbox connection (default: none)");
258  info(0, "-x");
259  info(0, " indicator to not use smsbox-id in messages send to bearerbox (default: yes)");
260  info(0, "-f sender");
261  info(0, " which sender address should be used");
262  info(0, "-D dlr-mask");
263  info(0, " defines the dlr-mask");
264  info(0, "-u dlr-url");
265  info(0, " defines the dlr-url");
266  info(0, "-n service");
267  info(0, " defines which service name should be logged (default: none)");
268  info(0, "-a account");
269  info(0, " defines which account name should be logged (default: none)");
270  info(0, "-d seconds");
271  info(0, " delay between message sending to bearerbox (default: 0)");
272  info(0, "-r smsc-id");
273  info(0, " use a specific route for the MT traffic");
274 }
275 
276 static void init_batch(Octstr *cfilename, Octstr *rfilename)
277 {
278  Octstr *receivers;
279  long lineno = 0;
280 
281  content = octstr_read_file(octstr_get_cstr(cfilename));
282  octstr_strip_crlfs(content);
283  if (content == NULL)
284  panic(0,"Can not read content file `%s'.",
285  octstr_get_cstr(cfilename));
286  info(0,"SMS-Text: <%s>", octstr_get_cstr(content));
287 
288  info(0,"Loading receiver list. This may take a while...");
289  receivers = octstr_read_file(octstr_get_cstr(rfilename));
290  if (receivers == NULL)
291  panic(0,"Can not read receivers file `%s'.",
292  octstr_get_cstr(rfilename));
293 
294  lines = octstr_split(receivers, octstr_imm("\n"));
295  lineno = gwlist_len(lines);
296  if (lineno <= 0)
297  panic(0,"Receiver file seems empty!");
298 
299  info(0,"Receivers file `%s' contains %ld destination numbers.",
300  octstr_get_cstr(rfilename), lineno);
301 
302  counter = counter_create();
303 }
304 
305 static unsigned long run_batch(void)
306 {
307  Octstr *no;
308  unsigned long linerr = 0;
309  unsigned long lineno = 0;
310 
311  while ((no = gwlist_consume(lines)) != NULL) {
312  if (octstr_check_range(no, 0, 256, gw_isdigit)) {
313  Msg *msg;
314 
315  lineno++;
316 
317  msg = msg_create(sms);
318 
319  msg->sms.smsc_id = smsc_id ? octstr_duplicate(smsc_id) : NULL;
320  msg->sms.service = service ? octstr_duplicate(service) : NULL;
321  msg->sms.sms_type = mt_push;
322  msg->sms.sender = octstr_duplicate(from);
323  msg->sms.receiver = octstr_duplicate(no);
324  msg->sms.account = account ? octstr_duplicate(account) : NULL;
325  msg->sms.msgdata = content ? octstr_duplicate(content) : octstr_create("");
326  msg->sms.dlr_mask = dlr_mask;
327  msg->sms.dlr_url = octstr_duplicate(dlr_url);
328  msg->sms.udhdata = octstr_create("");
329  msg->sms.coding = DC_7BIT;
330 
331  if (send_message(msg) < 0) {
332  linerr++;
333  info(0,"Failed to send message at line <%ld> for receiver `%s' to bearerbox.",
334  lineno, octstr_get_cstr(no));
335  msg_destroy(msg);
336  }
337  }
338  else {
339  linerr++;
340  error(0, "Receiver `%s' at line <%ld> contains non-digit characters, discarded!",
341  octstr_get_cstr(no), lineno);
342  }
343  octstr_destroy(no);
344  }
345  info(0,"mtbatch has processed %ld messages with %ld errors.", lineno, linerr);
346  return lineno;
347 }
348 
349 int main(int argc, char **argv)
350 {
351  int opt;
352  unsigned long sended = 0;
353  Octstr *cf, *rf;
354 
355  gwlib_init();
356 
357  bb_host = octstr_create("localhost");
358  bb_port = 13001;
359  bb_ssl = 0;
360 
361  while ((opt = getopt(argc, argv, "hv:b:p:si:xn:a:f:D:u:d:r:")) != EOF) {
362  switch (opt) {
363  case 'v':
365  break;
366  case 'b':
367  octstr_destroy(bb_host);
368  bb_host = octstr_create(optarg);
369  break;
370  case 'p':
371  bb_port = atoi(optarg);
372  break;
373  case 's':
374  bb_ssl = 1;
375  break;
376  case 'i':
377  smsbox_id = octstr_create(optarg);
378  break;
379  case 'x':
380  no_smsbox_id = 1;
381  break;
382  case 'n':
383  service = octstr_create(optarg);
384  break;
385  case 'a':
386  account = octstr_create(optarg);
387  break;
388  case 'f':
389  from = octstr_create(optarg);
390  break;
391  case 'D':
392  dlr_mask = atoi(optarg);
393  break;
394  case 'u':
395  dlr_url = octstr_create(optarg);
396  break;
397  case 'd':
398  delay = atof(optarg);
399  break;
400  case 'r':
401  smsc_id = octstr_create(optarg);
402  break;
403  case '?':
404  default:
405  error(0, "Invalid option %c", opt);
406  help();
407  panic(0, "Stopping.");
408  }
409  }
410 
411  if (optind == argc || argc-optind < 2) {
412  help();
413  exit(1);
414  }
415 
416  /* check some mandatory elements */
417  if (from == NULL)
418  panic(0,"Sender address not specified. Use option -f to specify sender address.");
419 
420  if ((DLR_IS_ENABLED(dlr_mask) && dlr_url == NULL) || (!DLR_IS_ENABLED(dlr_mask) && dlr_url != NULL))
421  panic(0,"dlr-url address OR dlr-mask not specified. Use option -D or -u to specify dlr values");
422 
423  rf = octstr_create(argv[argc-1]);
424  cf = octstr_create(argv[argc-2]);
425 
426  report_versions("mtbatch");
427  write_pid_file();
428 
429  init_batch(cf, rf);
430 
431  connect_to_bearerbox(bb_host, bb_port, bb_ssl, NULL /* bb_our_host */);
434 
435  sended = run_batch();
436 
437  /* avoid exiting before sending all msgs */
438  while (sended > counter_value(counter)) {
439  gwthread_sleep(0.1);
440  }
441 
444 
445  octstr_destroy(bb_host);
446  octstr_destroy(smsbox_id);
447  octstr_destroy(content);
448  octstr_destroy(service);
449  octstr_destroy(account);
450  octstr_destroy(dlr_url);
451  octstr_destroy(smsc_id);
452  counter_destroy(counter);
454 
455  gwlib_shutdown();
456 
457  return 0;
458 }
void error(int err, const char *fmt,...)
Definition: log.c:612
void info(int err, const char *fmt,...)
Definition: log.c:636
#define MAX_SMS_OCTETS
Definition: sms.h:129
void gwthread_join_all(void)
static unsigned long run_batch(void)
Definition: mtbatch.c:305
static Octstr * dlr_url
Definition: mtbatch.c:97
void counter_destroy(Counter *counter)
Definition: counter.c:110
static void write_pid_file(void)
Definition: mtbatch.c:102
int octstr_check_range(Octstr *ostr, long pos, long len, octstr_func_t filter)
Definition: octstr.c:812
static int bb_ssl
Definition: mtbatch.c:91
long gwlist_len(List *list)
Definition: list.c:166
program_status
Definition: shared.h:79
int read_from_bearerbox(Msg **msg, double seconds)
Definition: shared.c:220
static void help(void)
Definition: mtbatch.c:244
msg_type
Definition: msg.h:73
int optind
Definition: attgetopt.c:80
static void identify_to_bearerbox(void)
Definition: mtbatch.c:122
static Octstr * service
Definition: mtbatch.c:93
#define msg_create(type)
Definition: msg.h:136
#define DLR_IS_ENABLED(dlr)
Definition: dlr.h:81
#define octstr_get_cstr(ostr)
Definition: octstr.h:233
List * sms_split(Msg *orig, Octstr *header, Octstr *footer, Octstr *nonlast_suffix, Octstr *split_chars, int catenate, unsigned long msg_sequence, int max_messages, int max_octets)
Definition: sms.c:309
unsigned long counter_increase(Counter *counter)
Definition: counter.c:123
static List * lines
Definition: mtbatch.c:88
static void read_messages_from_bearerbox(void *arg)
Definition: mtbatch.c:138
int getopt(int argc, char **argv, char *opts)
Definition: attgetopt.c:84
static Octstr * from
Definition: mtbatch.c:95
Definition: msg.h:108
static int send_message(Msg *msg)
Definition: mtbatch.c:203
void msg_destroy_item(void *msg)
Definition: msg.c:147
Octstr * octstr_imm(const char *cstr)
Definition: octstr.c:281
static Octstr * smsbox_id
Definition: mtbatch.c:86
Definition: msg.h:79
Counter * counter_create(void)
Definition: counter.c:94
void log_set_output_level(enum output_level level)
Definition: log.c:217
int main(int argc, char **argv)
Definition: mtbatch.c:349
void connect_to_bearerbox(Octstr *host, int port, int ssl, Octstr *our_host)
Definition: shared.c:108
#define octstr_duplicate(ostr)
Definition: octstr.h:187
static Octstr * smsc_id
Definition: mtbatch.c:98
static Octstr * bb_host
Definition: mtbatch.c:89
void msg_destroy(Msg *msg)
Definition: msg.c:132
int gw_isdigit(int c)
Definition: utils.c:988
static double delay
Definition: mtbatch.c:99
void warning(int err, const char *fmt,...)
Definition: log.c:624
void octstr_destroy(Octstr *ostr)
Definition: octstr.c:322
#define gwthread_create(func, arg)
Definition: gwthread.h:90
#define octstr_create(cstr)
Definition: octstr.h:125
void octstr_destroy_item(void *os)
Definition: octstr.c:334
unsigned long counter_value(Counter *counter)
Definition: counter.c:145
gw_assert(wtls_machine->packet_to_send!=NULL)
void gwthread_sleep(double seconds)
static void init_batch(Octstr *cfilename, Octstr *rfilename)
Definition: mtbatch.c:276
int deliver_to_bearerbox(Msg *msg)
Definition: shared.c:166
static long bb_port
Definition: mtbatch.c:90
static char * pid_file
Definition: mtbatch.c:85
Octstr * octstr_read_file(const char *filename)
Definition: octstr.c:1546
void octstr_strip_crlfs(Octstr *text)
Definition: octstr.c:1376
void report_versions(const char *boxname)
Definition: utils.c:539
long octstr_len(const Octstr *ostr)
Definition: octstr.c:340
static int dlr_mask
Definition: mtbatch.c:96
void write_to_bearerbox(Msg *pmsg)
Definition: shared.c:142
Definition: octstr.c:118
void * gwlist_consume(List *list)
Definition: list.c:427
void debug(const char *place, int err, const char *fmt,...)
Definition: log.c:690
char * optarg
Definition: attgetopt.c:82
#define panic
Definition: log.h:87
void gwlib_shutdown(void)
Definition: gwlib.c:94
void gwlib_init(void)
Definition: gwlib.c:78
static int no_smsbox_id
Definition: mtbatch.c:100
static Counter * counter
Definition: mtbatch.c:92
List * octstr_split(const Octstr *os, const Octstr *sep)
Definition: octstr.c:1638
Definition: list.c:102
static Octstr * account
Definition: mtbatch.c:94
static XMLRPCDocument * msg
Definition: test_xmlrpc.c:86
static int start
#define DC_7BIT
Definition: sms.h:110
void gwlist_destroy(List *list, gwlist_item_destructor_t *destructor)
Definition: list.c:145
See file LICENSE for details about the license agreement for using, modifying, copying or deriving work from this software.