⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 smsc_cimd2.c

📁 gnu的专业网关smpp协议支持源代码。
💻 C
📖 第 1 页 / 共 5 页
字号:
/* Driver for CIMD 2 SMS centres. * Copyright 2000  WapIT Oy Ltd. * Author: Richard Braakman *//* TODO: Check checksums on incoming packets *//* TODO: Leading or trailing spaces are not allowed on parameters * "user identity" and "password".  Check this. *//* TODO: Try to use the "More messages to send" flag *//* This code is based on the CIMD 2 spec, version 2-0 en. * All USSD-specific parts have been left out, since we only want to * communicate with SMSC's. * * I found one contradiction in the spec: * * - The definition of Integer parameters specifies decimal digits only, *   but at least one Integer parameter (Validity Period Relative) can *   be negative.  I assume that this means a leading - is valid. */#include <ctype.h>#include <time.h>#include <errno.h>#include <limits.h>#include <string.h>#include <unistd.h>#include "gwlib/gwlib.h"#include "smsc_p.h"#include "sms.h"#include "dlr.h"#ifndef CIMD2_TRACE#define CIMD2_TRACE 0#endif/* Microseconds before giving up on a request */#define RESPONSE_TIMEOUT (10 * 1000000)/* Textual names for the operation codes defined by the CIMD 2 spec. *//* If you make changes here, also change the operation table. */enum {    /* Requests from client */    LOGIN = 1,    LOGOUT = 2,    SUBMIT_MESSAGE = 3,    ENQUIRE_MESSAGE_STATUS = 4,    DELIVERY_REQUEST = 5,    CANCEL_MESSAGE = 6,    SET_REQ = 8,    GET_REQ = 9,    /* Requests from server */    DELIVER_MESSAGE = 20,    DELIVER_STATUS_REPORT = 23,    /* Requests from either */    ALIVE = 40,    /* Not a request; add to any request to make it a response */    RESPONSE = 50,    /* Responses not related to requests */    GENERAL_ERROR_RESPONSE = 98,    NACK = 99};/* Textual names for the parameters defined by the CIMD 2 spec. *//* If you make changes here, also change the parameter table. */enum {    P_USER_IDENTITY = 10,    P_PASSWORD = 11,    P_DESTINATION_ADDRESS = 21,    P_ORIGINATING_ADDRESS = 23,    P_ORIGINATING_IMSI = 26,    P_ORIGINATED_VISITED_MSC = 28,    P_DATA_CODING_SCHEME = 30,    P_USER_DATA_HEADER = 32,    P_USER_DATA = 33,    P_USER_DATA_BINARY = 34,    P_MORE_MESSAGES_TO_SEND = 44,    P_VALIDITY_PERIOD_RELATIVE = 50,    P_VALIDITY_PERIOD_ABSOLUTE = 51,    P_PROTOCOL_IDENTIFIER = 52,    P_FIRST_DELIVERY_TIME_RELATIVE = 53,    P_FIRST_DELIVERY_TIME_ABSOLUTE = 54,    P_REPLY_PATH = 55,    P_STATUS_REPORT_REQUEST = 56,    P_CANCEL_ENABLED = 58,    P_CANCEL_MODE = 59,    P_MC_TIMESTAMP = 60,    P_STATUS_CODE = 61,    P_STATUS_ERROR_CODE = 62,    P_DISCHARGE_TIME = 63,    P_TARIFF_CLASS = 64,    P_SERVICE_DESCRIPTION = 65,    P_MESSAGE_COUNT = 66,    P_PRIORITY = 67,    P_DELIVERY_REQUEST_MODE = 68,    P_GET_PARAMETER = 500,    P_MC_TIME = 501,    P_ERROR_CODE = 900,    P_ERROR_TEXT = 901};/***************************************************************************//* Table of properties of the parameters defined by CIMD 2, and some       *//* functions to look up fields.                                            *//***************************************************************************//* Parameter types, internal.  CIMD 2 spec considers P_TIME to be "Integer" * and P_SMS to be "User Data". */enum { P_INT, P_STRING, P_ADDRESS, P_TIME, P_HEX, P_SMS };/* Information about the parameters defined by the CIMD 2 spec. * Used for warning about invalid incoming messages, and for validating * outgoing messages. */static const struct{    unsigned char *name;    int number;    int maxlen;    int type;  /* P_ values */    int minval, maxval;  /* For P_INT */}parameters[] = {    { "user identity", P_USER_IDENTITY, 32, P_STRING },    { "password", P_PASSWORD, 32, P_STRING },    { "destination address", P_DESTINATION_ADDRESS, 20, P_ADDRESS },    { "originating address", P_ORIGINATING_ADDRESS, 20, P_ADDRESS },    /* IMSI is International Mobile Subscriber Identity number */    { "originating IMSI", P_ORIGINATING_IMSI, 20, P_ADDRESS },    { "originated visited MSC", P_ORIGINATED_VISITED_MSC, 20, P_ADDRESS },    { "data coding scheme", P_DATA_CODING_SCHEME, 3, P_INT, 0, 255 },    { "user data header", P_USER_DATA_HEADER, 280, P_HEX },    { "user data", P_USER_DATA, 480, P_SMS },    { "user data binary", P_USER_DATA_BINARY, 280, P_HEX },    { "more messages to send", P_MORE_MESSAGES_TO_SEND, 1, P_INT, 0, 1 },    { "validity period relative", P_VALIDITY_PERIOD_RELATIVE, 3, P_INT, -1, 255 },    { "validity period absolute", P_VALIDITY_PERIOD_ABSOLUTE, 12, P_TIME },    { "protocol identifier", P_PROTOCOL_IDENTIFIER, 3, P_INT, 0, 255 },    { "first delivery time relative", P_FIRST_DELIVERY_TIME_RELATIVE, 3, P_INT, -1, 255 },    { "first delivery time absolute", P_FIRST_DELIVERY_TIME_ABSOLUTE, 12, P_TIME },    { "reply path", P_REPLY_PATH, 1, P_INT, 0, 1 },    { "status report request", P_STATUS_REPORT_REQUEST, 2, P_INT, 0, 63 },    { "cancel enabled", P_CANCEL_ENABLED, 1, P_INT, 0, 1 },    { "cancel mode", P_CANCEL_MODE, 1, P_INT, 0, 2 },    { "service centre timestamp", P_MC_TIMESTAMP, 12, P_TIME },    { "status code", P_STATUS_CODE, 2, P_INT, 0, 9 },    { "status error code", P_STATUS_ERROR_CODE, 3, P_INT, 0, 999 },    { "discharge time", P_DISCHARGE_TIME, 12, P_TIME },    { "tariff class", P_TARIFF_CLASS, 2, P_INT, 0, 99 },    { "service description", P_SERVICE_DESCRIPTION, 1, P_INT, 0, 9 },    { "message count", P_MESSAGE_COUNT, 3, P_INT, 0, 999 },    { "priority", P_PRIORITY, 1, P_INT, 1, 9 },    { "delivery request mode", P_DELIVERY_REQUEST_MODE, 1, P_INT, 0, 2 },    { "get parameter", P_GET_PARAMETER, 3, P_INT, 501, 999 },    { "MC time", P_MC_TIME, 12, P_TIME },    { "error code", P_ERROR_CODE, 3, P_INT, 0, 999 },    { "error text", P_ERROR_TEXT, 64, P_STRING },    { NULL }};/* Return the index in the parameters array for this parameter id. * Return -1 if it is not found. */static const int parm_index(int parmno){    int i;    for (i = 0; parameters[i].name != NULL; i++) {        if (parameters[i].number == parmno)            return i;    }    return -1;}#ifndef NO_GWASSERT/* Return the type of this parameter id.  Return -1 if the id is unknown. */static const int parm_type(int parmno){    int i = parm_index(parmno);    if (i < 0)        return -1;    return parameters[i].type;}#endif/* Return the max length for this parameter id. * Return -1 if the id is unknown. */static const int parm_maxlen(int parmno){    int i = parm_index(parmno);    if (i < 0)        return -1;    return parameters[i].maxlen;}static const char *parm_name(int parmno){    int i = parm_index(parmno);    if (i < 0)        return NULL;    return parameters[i].name;}#ifndef NO_GWASSERT/* Return 1 if the value for this (Integer) parameter is in range. * Return 0 otherwise.  Return -1 if the parameter was not found.  */static const int parm_in_range(int parmno, long value){    int i;    i = parm_index(parmno);    if (i < 0)        return -1;    return (value >= parameters[i].minval && value <= parameters[i].maxval);}#endif/* Helper function to check P_ADDRESS type */static int isphonedigit(int c){    return isdigit(c) || c == '+' || c == '-';}static const int parm_valid_address(Octstr *value){    return octstr_check_range(value, 0, octstr_len(value), isphonedigit);}/***************************************************************************//* Some functions to look up information about operation codes             *//***************************************************************************/static int operation_find(int operation);static Octstr *operation_name(int operation);static const int operation_can_send(int operation);static const int operation_can_receive(int operation);static const struct{    unsigned char *name;    int code;    int can_send;    int can_receive;}operations[] = {    { "Login", LOGIN, 1, 0 },    { "Logout", LOGOUT, 1, 0 },    { "Submit message", SUBMIT_MESSAGE, 1, 0 },    { "Enquire message status", ENQUIRE_MESSAGE_STATUS, 1, 0 },    { "Delivery request", DELIVERY_REQUEST, 1, 0 },    { "Cancel message", CANCEL_MESSAGE, 1, 0 },    { "Set parameter", SET_REQ, 1, 0 },    { "Get parameter", GET_REQ, 1, 0 },    { "Deliver message", DELIVER_MESSAGE, 0, 1 },    { "Deliver status report", DELIVER_STATUS_REPORT, 0, 1 },    { "Alive", ALIVE, 1, 1 },    { "NACK", NACK, 1, 1 },    { "General error response", GENERAL_ERROR_RESPONSE, 0, 1 },    { NULL, 0, 0, 0 }};static int operation_find(int operation){    int i;    for (i = 0; operations[i].name != NULL; i++) {        if (operations[i].code == operation)            return i;    }    return -1;}/* Return a human-readable representation of this operation code */static Octstr *operation_name(int operation){    int i;    i = operation_find(operation);    if (i >= 0)        return octstr_create(operations[i].name);    if (operation >= RESPONSE) {        i = operation_find(operation - RESPONSE);        if (i >= 0) {            Octstr *name = octstr_create(operations[i].name);            octstr_append_cstr(name, " response");            return name;        }    }    /* Put the operation number here when we have octstr_format */    return octstr_create("(unknown)");}/* Return true if a CIMD2 client may send this operation */static const int operation_can_send(int operation){    int i = operation_find(operation);    if (i >= 0)        return operations[i].can_send;    /* If we can receive the request, then we can send the response. */    if (operation >= RESPONSE)        return operation_can_receive(operation - RESPONSE);    return 0;}/* Return true if a CIMD2 server may send this operation */static const int operation_can_receive(int operation){    int i = operation_find(operation);    if (i >= 0)        return operations[i].can_receive;    /* If we can send the request, then we can receive the response. */    if (operation >= RESPONSE)        return operation_can_send(operation - RESPONSE);    return 0;}/***************************************************************************//* Packet encoding/decoding functions.  They handle packets at the octet   *//* level, and know nothing of the network.                                 *//***************************************************************************/struct packet{    /* operation and seq are -1 if their value could not be parsed */    int operation;    int seq;   /* Sequence number */    Octstr *data;   /* Encoded packet */    /* CIMD 2 packet structure is so simple that packet information is     * stored as a valid encoded packet, and decoded as necessary.      * Exceptions: operation code and sequence number are also stored     * as ints for speed, and the checksum is not added until the packet     * is about to be sent.  Since checksums are optional, the packet     * is still valid without a checksum.     *     * The sequence number is kept at 0 until it's time to actually     * send the packet, so that the send functions have control over     * the sequence numbers.     */};/* These are the separators defined by the CIMD 2 spec */#define STX 2   /* Start of packet */#define ETX 3   /* End of packet */#define TAB 9   /* End of parameter *//* The same separators, in string form */#define STX_str "\02"#define ETX_str "\03"#define TAB_str "\011"/* A reminder that packets are created without a valid sequence number */#define BOGUS_SEQUENCE 0static Msg *cimd2_accept_delivery_report_message(struct packet *request, SMSCenter *smsc);/* Look for the STX OO:SSS TAB header defined by CIMD 2, where OO is the * operation code in two decimals and SSS is the sequence number in three * decimals.  Leave the results in the proper fields of the packet. * Try to make sense of headers that don't fit this pattern; validating * the packet format is not our job. */static void packet_parse_header(struct packet *packet){    int pos;    long number;    /* Set default values, in case we can't parse the fields */    packet->operation = -1;    packet->seq = -1;    pos = octstr_parse_long(&number, packet->data, 1, 10);    if (pos < 0)        return;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -