?? smsc_ois.c
字號:
/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2005 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see <http://www.kannel.org/>. * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /***************************************************************************** * smsc_ois.c - Sema Group SMS2000 (G6.0) Center (OIS 5.0). * Jouko Koski (EDS) for WapIT Ltd. * * The SMS2000 has a general X.25 access gateway for accessing the SMSC, * as described in the Open Interface Specification 5.0 document. * A protocol translator - like the Cisco 2501 router - hides all the * X.25 trickery from us. We just connect to a preconfigured router * address/port, and the translator forwards the connection to the SMS2000. * Correspondingly, if the SMSC has something to say, it looks like * the router were contacting our port. The router should be configured so, * that it has a pre-defined address and tcp port in X.25 automode establishing * a X.25 link and a similar configuration in X.25 side connecting to a pre- * defined address and port, it shall not encapsulate everything in Telnet * (set the stream mode), and it should suppress banner messages like "Trying * 9876...Open" (set the quiet mode). * * Whenever possible, I've tried to steal ideas and code from other smsc_* * files, particularly from Hao Shi's (EDS) original implementation for a * serial-line-connected PAD. However, the code is highly evolutionary, * because during the implementation new technical details kept popping * up all the time (initially, PAD commands were supposed to be used, * but the router was configured to "automode", so they weren't necessary; * instead the router gave banner messages and wanted some telnet negotiations; * the router insisted echoing everything and delayed <nul>s after <cr>s; * telnet transmit-binary mode solved that; then the stream mode (no telnet * encapsulation) was discovered; suddenly the banners were turned off also; * but still the smsc didn't deliver mo messages, because it wanted to * connect instead of using our existing connection; then we began to use * short connection sessions for transmitting instead of a single ever- * lasting connection, and also started to specifically listen for smsc * initiated connections, which yielded two separate input buffers; then * suddenly the banners were there again, so some intelligence had to be * added to adapt their (non-)existence; then revealed the spec version 4.5 * had been obsolete all the time and we got 5.0; the router apparently * caused some extra packets on the x.25 side and everybody was blaming the * application; then the connection maintenance and buffering was again * revisited to achieve better performance and reliability... Really an * interesting story but think if it were about you instead of me :-) * * Really funny thing is that according to the spec the SMS2000 does have * a direct TCP/IP access interface. However, here we have the general X.25 * access interface, since we started with the old spec and probably the * simpler TCP/IP access is not available in our particular customer's * installation, not at least when this was written. In the direct access * only single ever-lasting connection is necessary, and the messages are * the same but their format is different. Encoding tricks are the same. * So, if you are implementing that access mode some day, there are probably * differences between this access mode and yours on so many levels, that * simple if () selections won't work; write your own code from (nearly) * scratch and take appropriate encoding conversion functions here. Or do * just whatever you want, what should I care :-). */#include <unistd.h>#include <ctype.h>#include <errno.h>#include <string.h>#include <sys/time.h>#include <sys/types.h>#include <sys/timeb.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include "smsc.h"#include "smsc_p.h"#include "gwlib/gwlib.h"#include "sms.h"/* XXX Delete me and replace dcs with dcs_to_fields */enum dcs_body_type { DCS_GSM_TEXT = 0, DCS_OCTET_DATA = 4 /* flag_8bit */};/* 'private:' */int ois_debug_level = 0; /* some extra verbosity in debug logging *//* 0=just normal debugging, 1=input/output messages, 2=function entries, *//* 3=message assembly/disassembly, 4=disconnection tracing, *//* 5=message conversions, and 8=message polling (=too much) */#define SAY(d,s) { if (d<=ois_debug_level) debug("bb.sms.ois",0,s); }#define SAY2(d,s,t) { if (d<=ois_debug_level) debug("bb.sms.ois",0,s,t); }#define SAY3(d,s,t,u) { if (d<=ois_debug_level) debug("bb.sms.ois",0,s,t,u); }#define IOTRACE(x,s,l) SAY3(1,"%s [%s]",x,ois_debug_str(s,l))#define BUFLEN (511) /* sure enough for ois messages */#define OIS_OPEN_WAITTIME (15) /* seconds, waiting for banners */#define OIS_MESSAGE_WAITTIME (30) /* seconds, until closing idle connection */#define OIS_WAITTIME (999999) /* microseconds, waiting for banners at a time */#define OIS_NOWAIT (0) /* microseconds, not waiting */#define MAXCOUNTER (10000) /* ois message id */#define EOL ('\r') /* ois definition for the eol */typedef struct ois_listentry { struct ois_listentry *next; Msg *msg;} ois_listentry;#define OIS_FLAG_DEBUG (0x000f)#define OIS_FLAG_ERROR (0x0100)#define OIS_FLAG_NOBANNER (0x0200)#define OIS_FLAG_MULTIPLE_CALL (0x0400)#define OIS_FLAG_CLOSED (0x0800)static int ois_counter = 0; /* [0..MAXCOUNTER), ois "unique" message id */static int ois_open_listener(SMSCenter *smsc);static int ois_open_sender(SMSCenter *smsc);static int ois_open_receiver(SMSCenter *smsc);static void ois_disconnect_all(SMSCenter *smsc);static void ois_disconnect(SMSCenter *smsc);static int ois_read_into_buffer(SMSCenter *smsc, long wait_usec);static int ois_check_input(SMSCenter *smsc, long wait_usec);static int ois_check_incoming(SMSCenter *smsc, long wait_usec);static void ois_append_to_list(ois_listentry **head, Msg *msg);static int ois_int_to_i4(char *raw, int nbr);static int ois_increment_counter(void);static int ois_submit_sm_invoke(SMSCenter *smsc, const Msg *msg);static int ois_encode_submit_sm_invoke(char *str, const Msg *msg);static int ois_append_msisdn(char *raw, const Msg *msg);static int ois_append_sme_reference_number(char *raw);static int ois_append_priority(char *raw);static int ois_append_originating_address(char *raw);static int ois_append_validity_period(char *raw);static int ois_append_data_coding_scheme(char *raw, const Msg *msg);static int ois_append_status_report_request(char *raw);static int ois_append_protocol_id(char *raw);static int ois_append_submission_options(char *raw, const Msg *msg);static int ois_append_sm_text(char *raw, const Msg *msg);static int ois_submit_sm_result(SMSCenter *smsc, const char *buffer);static int ois_decode_submit_sm_result(int *code, const char *str);static int ois_deliver_sm_invoke(SMSCenter *smsc, const char *buffer);static int ois_decode_deliver_sm_invoke(Msg *msg, const char *str);static int ois_check_deliver_sm_invoke(const char *str);static int ois_adjust_destination_address(Msg *msg, const char *raw);static int ois_ignore_smsc_reference_number(const char *raw);static int ois_adjust_originating_address(Msg *msg, const char *raw);static int ois_adjust_data_coding_scheme(Msg *msg, const char *raw);static int ois_ignore_protocol_id(const char *raw);static int ois_adjust_additional_information(Msg *msg, const char *raw);static int ois_adjust_sm_text(Msg *msg, const char *raw);static int ois_ignore_time(const char *raw);static int ois_deliver_sm_result(SMSCenter *smsc, int result, const char *str);static int ois_encode_deliver_sm_result(char *str, int result);static int ois_expand_gsm7(char *raw8, const char *raw7, int len);static int ois_expand_gsm7_to_bits(char *bits, const char *raw7, int len);static char ois_expand_gsm7_from_bits(const char *bits, int pos);static int ois_convert_to_ia5(char *str, const char *raw, int len);static int ois_convert_from_ia5(char *raw, const char *str);static int ois_convert_to_iso88591(char *raw, int len);static int ois_extract_msg_from_buffer(char *str, SMSCenter *smsc);static int ois_extract_line_from_buffer(char *str, SMSCenter *smsc);static void ois_swap_buffering(SMSCenter *smsc);static const char *ois_debug_str(const char *raw, int len);/* 'public:' *//* * Establish a connection to the SMSC. */SMSCenter *ois_open(int receiveport, const char *hostname, int port, int debug_level){ SMSCenter *smsc; int ret; ois_debug_level = debug_level & OIS_FLAG_DEBUG; SAY(2, "ois_open"); /* create a SMSCenter structure */ smsc = smscenter_construct(); if (smsc == NULL) { goto error; } smsc->type = SMSC_TYPE_OIS; smsc->receive_port = receiveport; smsc->hostname = gw_strdup(hostname); smsc->port = port; smsc->ois_flags = ois_debug_level; ret = ois_open_listener(smsc); if (ret < 0) { goto error; } sprintf(smsc->name, "OIS:TCP/X.25-Translator:localhost:%d:TCP:%.512s:%d", smsc->receive_port, smsc->hostname, smsc->port); return smsc; error: error(0, "ois_open: could not open"); smscenter_destruct(smsc); return NULL;}/* * Terminate the SMSC connection. */int ois_close(SMSCenter *smsc){ ois_debug_level = smsc->ois_flags & OIS_FLAG_DEBUG; SAY(2, "ois_close"); if (smsc->type != SMSC_TYPE_OIS) { warning(0, "ois_close: closing a not-ois connection..."); } ois_swap_buffering(smsc); smscenter_remove_from_buffer(smsc, smsc->buflen); ois_swap_buffering(smsc); smscenter_remove_from_buffer(smsc, smsc->buflen); SAY(4, "ois_close: ois_disconnect_all"); ois_disconnect_all(smsc); return 0;}/* * Re-establish a SMSC connection. */int ois_reopen(SMSCenter *smsc){ int ret; ois_debug_level = smsc->ois_flags & OIS_FLAG_DEBUG; SAY(2, "ois_reopen"); ois_close(smsc); if (smsc->type == SMSC_TYPE_OIS) { ret = ois_open_listener(smsc); if (ret < 0) { goto error; } } else { error(0, "ois_reopen: wrong smsc type"); goto error; } return 0; error: error(0, "ois_reopen: could not open"); return -1;}/* * Check for MO messages. * Put all incoming MO messages into an internal queue. */int ois_pending_smsmessage(SMSCenter *smsc){ int ret; ois_debug_level = smsc->ois_flags & OIS_FLAG_DEBUG; SAY(8, "ois_pending_smsmessage"); ret = ois_check_incoming(smsc, OIS_NOWAIT); if (ret == 0 && smsc->socket != -1) { ret = ois_check_input(smsc, OIS_NOWAIT); } if (ret == 0 && smsc->ois_socket != -1) { ois_swap_buffering(smsc); ret = ois_check_input(smsc, OIS_NOWAIT); ois_swap_buffering(smsc); if (smsc->ois_socket == -1 && smsc->ois_ack_debt != 0) { warning(0, "ois_pending_smsmessage: missing %d ack(s)...", smsc->ois_ack_debt); } } return ret;}/* * Send a MT message. */int ois_submit_msg(SMSCenter *smsc, const Msg *msg){ int ret; ois_debug_level = smsc->ois_flags & OIS_FLAG_DEBUG; SAY(2, "ois_submit_msg"); ois_swap_buffering(smsc); if (msg_type((Msg *)msg) != sms) { error(0, "ois_submit_msg: can not handle message types other than smart_msg"); goto error; } if (smsc->socket == -1) { ret = ois_open_sender(smsc); if (ret < 0) { goto error; } } ret = ois_submit_sm_invoke(smsc, msg); if (ret < 0) { goto error_close; } ++smsc->ois_ack_debt; time(&smsc->ois_alive); ret = 0; goto out; error_close: if (smsc->ois_ack_debt != 0) { warning(0, "ois_submit_msg: missing %d ack(s)...", smsc->ois_ack_debt); } SAY(4, "ois_submit_msg: ois_disconnect in error_close"); ois_disconnect(smsc); error: SAY(2, "ois_submit_msg error"); ret = -1; out: ois_swap_buffering(smsc); return ret;}/* * Receive a MO message (from the internal queue). */int ois_receive_msg(SMSCenter *smsc, Msg **msg){ ois_listentry *item; ois_debug_level = smsc->ois_flags & OIS_FLAG_DEBUG; SAY(2, "ois_receive_msg"); item = smsc->ois_received_mo; if (item == NULL) { /* no mo messages */ if ((smsc->ois_flags & OIS_FLAG_ERROR) == 0) { return 0; /* should actually not happen */ } else { return -1; /* error pending, reopen? */ } } else { /* we have a message waiting */ smsc->ois_received_mo = item->next; *msg = item->msg; gw_free(item); return 1; /* got the message */ }}/* * Destruct the internal queue. */void ois_delete_queue(SMSCenter *smsc){ Msg *msg; ois_debug_level = smsc->ois_flags & OIS_FLAG_DEBUG; SAY(2, "ois_delete_queue"); while (ois_receive_msg(smsc, &msg) > 0) { gw_free(msg); } return;}/* * Implementation of 'private:' */static int ois_open_listener(SMSCenter *smsc){ SAY(2, "ois_open_listener"); smsc->ois_listening_socket = make_server_socket(smsc->receive_port, NULL); /* XXX add interface_name if required */ if (smsc->ois_listening_socket < 0) { goto error; } if (socket_set_blocking(smsc->ois_listening_socket, 0) < 0) { ois_close(smsc); goto error; } smsc->ois_flags &= ~OIS_FLAG_ERROR; smsc->ois_flags &= ~OIS_FLAG_NOBANNER; smsc->ois_alive2 = time(&smsc->ois_alive); SAY2(2, "ois_open_listener fd=%d", smsc->ois_listening_socket); return 0; error: error(0, "ois_open_listener: failed to open listening socket"); return -1;}static int ois_open_sender(SMSCenter *smsc){ int ret; char buffer[BUFLEN+1]; time_t now; time_t beginning; SAY(2, "ois_open_sender"); debug("bb.sms.ois", 0, "connecting to host %s port %d", smsc->hostname, smsc->port); time(&beginning); smsc->socket = tcpip_connect_to_server(smsc->hostname, smsc->port, NULL); /* XXX add interface_name if required */ if (smsc->socket < 0) { return -1; } else { smsc->buflen = 0; time(&smsc->ois_alive); smsc->ois_ack_debt = 0; } SAY2(2, "ois_open_sender fd=%d", smsc->socket); if (smsc->ois_flags & OIS_FLAG_NOBANNER) { return 0; } buffer[0] = '\0'; for (time(&now); (now - beginning) < OIS_OPEN_WAITTIME; time(&now)) { ret = ois_read_into_buffer(smsc, OIS_WAITTIME); if (ret < 0) { goto error; } if (smsc->buflen == 0) { /* assume that the router is in the quiet mode */ /* there will be no banners */ smsc->ois_flags |= OIS_FLAG_NOBANNER; debug("bb.sms.ois", 0, "assuming that %s:%d is in the quiet mode", smsc->hostname, smsc->port); return 0; } ret = ois_extract_line_from_buffer(buffer, smsc); if (ret > 0) { if (strncmp(buffer, "Trying", 6) == 0 && strstr(buffer, "...Open\r\n") != NULL) { time(&smsc->ois_alive); return 0; } else { break; } } } error: SAY(4, "ois_open_sender: ois_disconnect in error"); ois_disconnect(smsc); error(0, "ois_open_sender: failed to connect [%s%s]", buffer, ois_debug_str(smsc->buffer, smsc->buflen)); return -1;}static int ois_open_receiver(SMSCenter *smsc){ struct sockaddr_in addr; int addrlen; Octstr *os; SAY(2, "ois_open_receiver"); /* the listening socket should be non-blocking... */ addrlen = sizeof(addr); smsc->socket = accept(smsc->ois_listening_socket, (struct sockaddr *)&addr, &addrlen); if (smsc->socket == -1) { if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK) /* || errno == ECONNABORTED || errno == EPROTO) -Kalle 6.7 */ { return 0; } else { error(errno, "ois_open_receiver: accept failed"); smsc->ois_flags |= OIS_FLAG_ERROR; return -1; } } SAY2(2, "ois_open_receiver fd=%d", smsc->socket); os = gw_netaddr_to_octstr(AF_INET, &addr.sin_addr); debug("bb.sms.ois", 0, "connection from host %s port %hu", octstr_get_cstr(os), ntohs(addr.sin_port)); octstr_destroy(os); time(&smsc->ois_alive); return 0;}static void ois_disconnect_all(SMSCenter *smsc){ SAY2(2, "ois_disconnect_all fd=%d", smsc->ois_listening_socket); ois_swap_buffering(smsc); SAY(4, "ois_disconnect_all: ois_disconnect");
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -