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

📄 smsc_cimd2.c

📁 gnu的专业网关smpp协议支持源代码。
💻 C
📖 第 1 页 / 共 5 页
字号:
    octstr_set_char(packet->data, 5, buf[1]);    octstr_set_char(packet->data, 6, buf[2]);    packet->seq = seq;}static struct packet *packet_encode_message(Msg *msg, Octstr *sender_prefix){    struct packet *packet;    Octstr *text;    int spaceleft;    long truncated;    int dcs = 0;    gw_assert(msg != NULL);    gw_assert(msg->type == sms);    gw_assert(msg->sms.receiver != NULL);    dcs = fields_to_dcs(msg, 0);    if (msg->sms.sender == NULL)        msg->sms.sender = octstr_create("");    if (!parm_valid_address(msg->sms.receiver)) {        warning(0, "cimd2_submit_msg: non-digits in "                "destination phone number '%s', discarded",                octstr_get_cstr(msg->sms.receiver));        return NULL;    }    if (!parm_valid_address(msg->sms.sender)) {        warning(0, "cimd2_submit_msg: non-digits in "                "originating phone number '%s', discarded",                octstr_get_cstr(msg->sms.sender));        return NULL;    }    packet = packet_create(SUBMIT_MESSAGE, BOGUS_SEQUENCE);    packet_add_address_parm(packet, P_DESTINATION_ADDRESS, msg->sms.receiver);    /* CIMD2 interprets the originating address as a sub-address to     * our connection number (so if the connection is "400" and we     * fill in "600" as the sender number, the user sees "400600").     * Since we have no way to ask what this number is, it has to     * be configured. */    if (octstr_len(sender_prefix) == 0) { /* Speed up the default case */        packet_add_address_parm(packet, P_ORIGINATING_ADDRESS,                                msg->sms.sender);    } else if (octstr_compare(sender_prefix, octstr_imm("never")) != 0) {        if (octstr_ncompare(sender_prefix, msg->sms.sender,                            octstr_len(sender_prefix)) == 0) {            Octstr *sender;            sender = octstr_copy(msg->sms.sender,                octstr_len(sender_prefix), octstr_len(msg->sms.sender));            packet_add_address_parm(packet, P_ORIGINATING_ADDRESS, sender);            octstr_destroy(sender);        } else {            warning(0, "CIMD2: Sending message with originating address <%s>, "                       "which does not start with the sender-prefix.",                    octstr_get_cstr(msg->sms.sender));        }    }    /* Explicitly ask not to get status reports.     * If we do not do this, the server's default might be to     * send status reports in some cases, and we don't do anything     * with those reports anyway. */    /* ask for the delivery reports if needed*/    if (msg->sms.dlr_mask & 0x03)    {	packet_add_int_parm(packet, P_STATUS_REPORT_REQUEST, 14);    }    else	packet_add_int_parm(packet, P_STATUS_REPORT_REQUEST, 0);    truncated = 0;    spaceleft = 140;    if (octstr_len(msg->sms.udhdata)) {        /* udhdata will be truncated and warned about if         * it does not fit. */        packet_add_hex_parm(packet, P_USER_DATA_HEADER, msg->sms.udhdata);        spaceleft -= octstr_len(msg->sms.udhdata);    }    if (msg->sms.coding == DC_7BIT)        spaceleft = spaceleft * 8 / 7;    if (spaceleft < 0)        spaceleft = 0;    text = octstr_duplicate(msg->sms.msgdata);    if (octstr_len(text) > 0 && spaceleft == 0) {        warning(0, "CIMD2: message filled up with "                "UDH, no room for message text");    } else if (msg->sms.coding == DC_8BIT || msg->sms.coding == DC_UCS2) {        if (octstr_len(text) > spaceleft) {            truncated = octstr_len(text) - spaceleft;            octstr_truncate(text, spaceleft);        }        packet_add_hex_parm(packet, P_USER_DATA_BINARY, text);    } else {#if CIMD2_TRACE        debug("bb.sms.cimd2", 0, "CIMD2 sending message.  Text:");        octstr_dump(text, 0);#endif        /* Going from latin1 to GSM to CIMD2 may seem like a         * detour, but it's the only way to get all the escape         * codes right. */        charset_latin1_to_gsm(text);        truncated = charset_gsm_truncate(text, spaceleft);        convert_gsm_to_cimd2(text);#if CIMD2_TRACE        debug("bb.sms.cimd2", 0, "After CIMD2 encoding:");        octstr_dump(text, 0);#endif        packet_add_sms_parm(packet, P_USER_DATA, text);    }    if (dcs != 0)        packet_add_int_parm(packet, P_DATA_CODING_SCHEME, dcs);    if (truncated > 0) {        warning(0, "CIMD2: truncating message text to fit "                "in %d characters.", spaceleft);    }    octstr_destroy(text);    return packet;}/***************************************************************************//* Protocol functions.  These implement various transactions.              *//***************************************************************************//* Give this packet a proper sequence number for sending. */static void packet_set_send_sequence(struct packet *packet, SMSCenter *smsc){    gw_assert(smsc != NULL);    /* Send sequence numbers are always odd, receiving are always even */    gw_assert(smsc->cimd2_send_seq % 2 == 1);    packet_set_sequence(packet, smsc->cimd2_send_seq);    smsc->cimd2_send_seq += 2;    if (smsc->cimd2_send_seq > 256)        smsc->cimd2_send_seq = 1;}static struct packet *cimd2_get_packet(SMSCenter *smsc, Octstr **ts){    struct packet *packet = NULL;    gw_assert(smsc != NULL);    /* If packet is already available, don't try to read anything */    packet = packet_extract(smsc->cimd2_inbuffer);    while (packet == NULL) {        if (read_available(smsc->socket, RESPONSE_TIMEOUT) != 1) {            warning(0, "CIMD2 SMSCenter is not responding");            return NULL;        }        if (octstr_append_from_socket(smsc->cimd2_inbuffer, smsc->socket) <= 0) {            error(0, "cimd2_get_packet: read failed");            return NULL;        }        packet = packet_extract(smsc->cimd2_inbuffer);    }    packet_check(packet);    packet_check_can_receive(packet);	if(ts)	    *ts = packet_get_parm(packet,P_MC_TIMESTAMP);    if (smsc->keepalive > 0)        smsc->cimd2_next_ping = time(NULL) + 60 * smsc->keepalive;    return packet;}/* Acknowledge a request.  The CIMD 2 spec only defines positive responses * to the server, because the server is perfect. */static void cimd2_send_response(struct packet *request, SMSCenter *smsc){    struct packet *response;    gw_assert(request != NULL);    gw_assert(request->operation < RESPONSE);    response = packet_create(request->operation + RESPONSE, request->seq);    packet_set_checksum(response);    /* Don't check errors here because if there is something     * wrong with the socket, the main loop will detect it. */    octstr_write_to_socket(smsc->socket, response->data);    packet_destroy(response);}static Msg *cimd2_accept_message(struct packet *request){    Msg *message = NULL;    Octstr *destination = NULL;    Octstr *origin = NULL;    Octstr *UDH = NULL;    Octstr *text = NULL;    int DCS;    /* See GSM 03.38.  The bit patterns we can handle are:     *   000xyyxx  Uncompressed text, yy indicates alphabet.            *                   yy = 00, default alphabet     *                   yy = 01, 8-bit data     *                   yy = 10, UCS2 (can't handle yet)     *                   yy = 11, reserved     *   1111xyxx  Data, y indicates alphabet.     *                   y = 0, default alphabet     *                   y = 1, 8-bit data     */    DCS = packet_get_int_parm(request, P_DATA_CODING_SCHEME);    destination = packet_get_address_parm(request, P_DESTINATION_ADDRESS);    origin = packet_get_address_parm(request, P_ORIGINATING_ADDRESS);    UDH = packet_get_hex_parm(request, P_USER_DATA_HEADER);    /* Text is either in User Data or User Data Binary field. */    text = packet_get_sms_parm(request, P_USER_DATA);    if (text != NULL) {#if CIMD2_TRACE        debug("bb.sms.cimd2", 0, "CIMD2 received message.  Text:");        octstr_dump(text, 0);#endif        convert_cimd2_to_gsm(text);        charset_gsm_to_latin1(text);#if CIMD2_TRACE        debug("bb.sms.cimd", 0, "Text in latin1:");        octstr_dump(text, 0);#endif    } else {        text = packet_get_hex_parm(request, P_USER_DATA_BINARY);#if CIMD2_TRACE        debug("bb.sms.cimd2", 0, "CIMD2 received message.  Text:");        octstr_dump(text, 0);#endif    }    /* Code elsewhere in the gateway always expects the sender and     * receiver fields to be filled, so we discard messages that    	 * lack them.  If they should not be discarded, then the code     * handling sms messages should be reviewed.  -- RB */    if (!destination || octstr_len(destination) == 0) {        info(0, "CIMD2: Got SMS without receiver, discarding.");        goto error;    }    if (!origin || octstr_len(origin) == 0) {        info(0, "CIMD2: Got SMS without sender, discarding.");        goto error;    }    if ((!text || octstr_len(text) == 0) && (!UDH || octstr_len(UDH) == 0)) {        info(0, "CIMD2: Got empty SMS, ignoring.");        goto error;    }    message = msg_create(sms);    if (! dcs_to_fields(&message, DCS)) {	/* XXX Should reject this message ? */	debug("CIMD2", 0, "Invalid DCS");	dcs_to_fields(&message, 0);    }    message->sms.sender = origin;    message->sms.receiver = destination;    if (UDH) {        message->sms.udhdata = UDH;    }    message->sms.msgdata = text;    return message;error:    msg_destroy(message);    octstr_destroy(destination);    octstr_destroy(origin);    octstr_destroy(UDH);    octstr_destroy(text);    return NULL;}/* Deal with a request from the CIMD2 server, and acknowledge it. */static void cimd2_handle_request(struct packet *request, SMSCenter *smsc){    Msg *message = NULL;    /* TODO: Check if the sequence number of this request is what we     * expected. */    if (request->operation == DELIVER_STATUS_REPORT) {        message = cimd2_accept_delivery_report_message(request,smsc);        if (message)            list_append(smsc->cimd2_received, message);     }     else if (request->operation == DELIVER_MESSAGE) {         message = cimd2_accept_message(request);         if (message)             list_append(smsc->cimd2_received, message);    }    cimd2_send_response(request, smsc);}/* Send a request and wait for the ack.  If the other side responds with * an error code, attempt to correct and retry.  * If other packets arrive while we wait for the ack, handle them. * * Return -1 if the SMSC refused the request.  Return -2 for other * errors, such as being unable to send the request at all.  If the * function returns -2, the caller would do well to try to reopen the * connection. * * The SMSCenter must be already open. * * TODO: This function has grown large and complex.  Break it up * into smaller pieces. */static int cimd2_request(struct packet *request, SMSCenter *smsc, Octstr **ts){    int ret;    struct packet *reply = NULL;    int errorcode;    int tries = 0;    gw_assert(smsc != NULL);    gw_assert(request != NULL);    gw_assert(operation_can_send(request->operation));    if (smsc->socket < 0) {        warning(0, "cimd2_request: socket not open.");        goto io_error;    }retransmit:    packet_set_send_sequence(request, smsc);    packet_set_checksum(request);    ret = octstr_write_to_socket(smsc->socket, request->data);    if (ret < 0)        goto io_error;next_reply:    /*reply = cimd2_get_packet(smsc,ts);*/    reply = cimd2_get_packet(smsc, NULL);    if (!reply)        goto io_error;    errorcode = packet_display_error(reply);    if (reply->operation == NACK) {        warning(0, "CIMD2 received NACK");        octstr_dump(reply->data, 0);        /* Correct sequence number if server says it was wrong,         * but only if server's number is sane. */        if (reply->seq != request->seq && (reply->seq % 1) == 1) {            warning(0, "correcting sequence number from %ld to %ld.",                    (long) smsc->cimd2_send_seq, (long) reply->seq);            smsc->cimd2_send_seq = reply->seq;        }        goto retry;    }    if (reply->operation == GENERAL_ERROR_RESPONSE) {        error(0, "CIMD2 received general error response");        goto io_error;    }    /* The server sent us a request.  Handle it, then wait for     * a new reply. */    if (reply->operation < RESPONSE) {        cimd2_handle_request(reply, smsc);        packet_destroy(reply);        goto next_reply;    }    if (reply->seq != request->seq) {        /* We got a response to a different request number than         * what we send.  Strange. */        warning(0, "CIMD2: response had unexpected sequence number; ignoring.\n");        goto next_reply;    }    if (reply->operation != request->operation + RESPONSE) {        /* We got a response that didn't match our request */        Octstr *request_name = operation_name(request->operation);        Octstr *reply_name = operation_name(reply->operation);        warning(0, "CIMD2: %s request got a %s",                octstr_get_cstr(request_name),                octstr_get_cstr(reply_name));        octstr_destroy(request_name);        octstr_destroy(reply_name);        octstr_dump(reply->data, 0);        goto retry;    }

⌨️ 快捷键说明

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