📄 smsc_at.c
字号:
continue; } if ((pos = octstr_parse_long(&location, line, ++pos, 10)) == -1) { /* there was an error parsing the message id. next! */ error(2, "AT2[%s]: error parsing memory location in CMTI notification", octstr_get_cstr(privdata->name)); O_DESTROY(line); octstr_destroy(cmti_storage); continue; } /* check if we need to change storage location before issuing the read command */ if (!current_storage || (octstr_compare(current_storage, cmti_storage) != 0)) { octstr_destroy(current_storage); current_storage = octstr_duplicate(cmti_storage); at2_set_message_storage(privdata, cmti_storage); } if (!at2_read_delete_message(privdata, location)) { error(1,"AT2[%s]: CMTI notification received, but no message found in memory!", octstr_get_cstr(privdata->name)); } octstr_destroy(line); octstr_destroy(cmti_storage); } /* set prefered message storage back to what configured */ if (current_storage && privdata->modem->message_storage && (octstr_compare(privdata->modem->message_storage, current_storage) != 0)) at2_set_message_storage(privdata, privdata->modem->message_storage); octstr_destroy(current_storage);}static int at2_read_sms_memory(PrivAT2data* privdata){ /* get memory status */ if (at2_check_sms_memory(privdata) == -1) { debug("bb.smsc.at2", 0, "AT2[%s]: memory check error", octstr_get_cstr(privdata->name)); return -1; } if (privdata->sms_memory_usage) { /* * that is - greater then 0, meaning there are some messages to fetch * now - I used to just loop over the first input_mem_sms_used locations, * but it doesn't hold, since under load, messages may be received while * we're in the loop, and get stored in locations towards the end of the list, * thus creating 'holes' in the memory. * * There are two ways we can fix this : * (a) Just read the last message location, delete it and return. * It's not a complete solution since holes can still be created if messages * are recieved between the memory check and the delete command, * and anyway - it will slow us down and won't hold well under pressure * (b) Just scan the entire memory each call, bottom to top. * This will be slow too, but it'll be reliable. * * We can massivly improve performance by stopping after input_mem_sms_used messages * have been read, but send_modem_command returns 0 for no message as well as for a * message read, and the only other way to implement it is by doing memory_check * after each read and stoping when input_mem_sms_used get to 0. This is slow * (modem commands take time) so we improve speed only if there are less then 10 * messages in memory. * * I implemented the alternative - changed at2_wait_modem_command to return the * number of messages it collected. */ int i; int message_count = 0; /* cound number of messages collected */ debug("bb.smsc.at2", 0, "AT2[%s]: %d messages waiting in memory", octstr_get_cstr(privdata->name), privdata->sms_memory_usage); /* * loop till end of memory or collected enouch messages */ for (i = 1; i <= privdata->sms_memory_capacity && message_count < privdata->sms_memory_usage; ++i) { /* if (meanwhile) there are pending CMTI notifications, process these first * to not let CMTI and sim buffering sit in each others way */ while (list_len(privdata->pending_incoming_messages) > 0) { at2_read_pending_incoming_messages(privdata); } /* read the message and delete it */ message_count += at2_read_delete_message(privdata, i); } } /* at2_send_modem_command(privdata, ModemTypes[privdata->modemid].init1, 0, 0); */ return 0;}int at2_check_sms_memory(PrivAT2data *privdata){ long values[4]; /* array to put response data in */ int pos; /* position of parser in data stream */ int ret; Octstr* search_cpms = NULL; /* select memory type and get report */ if ((ret = at2_send_modem_command(privdata, "AT+CPMS?", 0, 0)) != 0) { debug("bb.smsc.at2.memory_check", 0, "failed to send mem select command to modem %d", ret); return -1; } search_cpms = octstr_create("+CPMS:"); if ((pos = octstr_search(privdata->lines, search_cpms, 0)) != -1) { /* got back a +CPMS response */ int index = 0; /* index in values array */ pos += 6; /* position of parser in the stream - start after header */ /* skip memory indication */ pos = octstr_search(privdata->lines, octstr_imm(","), pos) + 1; /* find all the values */ while (index < 4 && pos < octstr_len(privdata->lines) && (pos = octstr_parse_long(&values[index], privdata->lines, pos, 10)) != -1) { ++pos; /* skip number seperator */ ++index; /* increment array index */ if (index == 2) /* skip second memory indication */ pos = octstr_search(privdata->lines, octstr_imm(","), pos) + 1; } if (index < 4) { /* didn't get all memory data - I don't why, so I'll bail */ debug("bb.smsc.at2", 0, "AT2[%s]: couldn't parse all memory locations : %d:'%s'.", octstr_get_cstr(privdata->name), index, &(octstr_get_cstr(privdata->lines)[pos])); O_DESTROY(search_cpms); return -1; } privdata->sms_memory_usage = values[0]; privdata->sms_memory_capacity = values[1]; /* privdata->output_mem_sms_used = values[2]; privdata->output_mem_sms_capacity = values[3]; */ /* everything's cool */ ret = 0; /* clear the buffer */ O_DESTROY(privdata->lines); } else { debug("bb.smsc.at2", 0, "AT2[%s]: no correct header for CPMS response.", octstr_get_cstr(privdata->name)); /* didn't get a +CPMS response - this is clearly an error */ ret = -1; } O_DESTROY(search_cpms); return ret;}void at2_set_speed(PrivAT2data *privdata, int bps){ struct termios tios; int ret; int speed; tcgetattr(privdata->fd, &tios); switch (bps) { case 300: speed = B300; break; case 1200: speed = B1200; break; case 2400: speed = B2400; break; case 4800: speed = B4800; break; case 9600: speed = B9600; break; case 19200: speed = B19200; break; case 38400: speed = B38400; break;#ifdef B57600 case 57600: speed = B57600; break;#endif#ifdef B115200 case 115200: speed = B115200; break;#endif default: speed = B9600; } cfsetospeed(&tios, speed); cfsetispeed(&tios, speed); ret = tcsetattr(privdata->fd, TCSANOW, &tios); /* apply changes now */ if (ret == -1) { error(errno, "AT2[%s]: at_data_link: fail to set termios attribute", octstr_get_cstr(privdata->name)); } tcflush(privdata->fd, TCIOFLUSH); info(0, "AT2[%s]: speed set to %d", octstr_get_cstr(privdata->name), bps);}void at2_device_thread(void *arg){ SMSCConn *conn = arg; PrivAT2data *privdata = conn->data; int l, reconnecting = 0, error_count = 0; long idle_timeout, memory_poll_timeout = 0; conn->status = SMSCCONN_CONNECTING; /* Make sure we log into our own log-file if defined */ log_thread_to(conn->log_idx);reconnect: do { if (reconnecting) { if (conn->status == SMSCCONN_ACTIVE) { mutex_lock(conn->flow_mutex); conn->status = SMSCCONN_RECONNECTING; mutex_unlock(conn->flow_mutex); } error(0, "AT2[%s]: Couldn't connect (retrying in %ld seconds).", octstr_get_cstr(privdata->name), conn->reconnect_delay); gwthread_sleep(conn->reconnect_delay); } /* If modems->speed is defined, try to use it, else autodetect */ if (privdata->speed == 0 && privdata->modem != NULL && privdata->modem->speed != 0) { info(0, "AT2[%s]: trying to use speed <%ld> from modem definition", octstr_get_cstr(privdata->name), privdata->modem->speed); if(0 == at2_test_speed(privdata, privdata->modem->speed)) { privdata->speed = privdata->modem->speed; info(0, "AT2[%s]: speed is %ld", octstr_get_cstr(privdata->name), privdata->speed); } else { info(0, "AT2[%s]: speed in modem definition don't work, will autodetect", octstr_get_cstr(privdata->name)); } } if (privdata->speed == 0 && at2_detect_speed(privdata) == -1) { continue; } if (privdata->modem == NULL && at2_detect_modem_type(privdata) == -1) { continue; } if (at2_open_device(privdata)) { error(errno, "AT2[%s]: at2_device_thread: open_at2_device failed. Terminating", octstr_get_cstr(privdata->name)); continue; } if (privdata->max_error_count > 0 && error_count > privdata->max_error_count && privdata->modem != NULL && privdata->modem->reset_string != NULL) { error_count = 0; if (at2_send_modem_command(privdata, octstr_get_cstr(privdata->modem->reset_string), 0, 0) != 0) { error(0, "AT2[%s]: Reset of modem failed.", octstr_get_cstr(privdata->name)); at2_close_device(privdata); continue; } else { info(0, "AT2[%s]: Modem reseted.", octstr_get_cstr(privdata->name)); } } if (at2_init_device(privdata) != 0) { error(0, "AT2[%s]: Opening failed. Terminating", octstr_get_cstr(privdata->name)); at2_close_device(privdata); error_count++; continue; } else error_count = 0; /* If we got here, then the device is opened */ break; } while (!privdata->shutdown); mutex_lock(conn->flow_mutex); conn->status = SMSCCONN_ACTIVE; conn->connect_time = time(NULL); mutex_unlock(conn->flow_mutex); bb_smscconn_connected(conn); idle_timeout = 0; while (!privdata->shutdown) { l = list_len(privdata->outgoing_queue); if (l > 0) { at2_send_messages(privdata); idle_timeout = time(NULL); } else at2_wait_modem_command(privdata, 1, 0, NULL); while (list_len(privdata->pending_incoming_messages) > 0) { at2_read_pending_incoming_messages(privdata); } if (privdata->keepalive && idle_timeout + privdata->keepalive < time(NULL)) { if (at2_send_modem_command(privdata, octstr_get_cstr(privdata->modem->keepalive_cmd), 5, 0) < 0) { at2_close_device(privdata); reconnecting = 1; goto reconnect; } idle_timeout = time(NULL); } if (privdata->sms_memory_poll_interval && memory_poll_timeout + privdata->sms_memory_poll_interval < time(NULL)) { if (at2_read_sms_memory(privdata) == -1) { at2_close_device(privdata); reconnecting = 1; goto reconnect; } memory_poll_timeout = time(NULL); } } at2_close_device(privdata); mutex_lock(conn->flow_mutex); conn->status = SMSCCONN_DISCONNECTED; mutex_unlock(conn->flow_mutex); /* maybe some cleanup here? */ at2_destroy_modem(privdata->modem); octstr_destroy(privdata->device); octstr_destroy(privdata->ilb); octstr_destroy(privdata->lines); octstr_destroy(privdata->pin); octstr_destroy(privdata->validityperiod); octstr_destroy(privdata->my_number); octstr_destroy(privdata->sms_center); octstr_destroy(privdata->name); octstr_destroy(privdata->configfile); list_destroy(privdata->outgoing_queue, NULL); list_destroy(privdata->pending_incoming_messages, octstr_destroy_item); gw_free(conn->data); conn->data = NULL; mutex_lock(conn->flow_mutex); conn->why_killed = SMSCCONN_KILLED_SHUTDOWN; conn->status = SMSCCONN_DEAD; mutex_unlock(conn->flow_mutex); bb_smscconn_killed();}int at2_shutdown_cb(SMSCConn *conn, int finish_sending){ PrivAT2data *privdata = conn->data; debug("bb.sms", 0, "AT2[%s]: Shutting down SMSCConn, %s", octstr_get_cstr(privdata->name), finish_sending ? "slow" : "instant"); /* * Documentation claims this would have been done by smscconn.c, * but isn't when this code is being written. */ conn->why_killed = SMSCCONN_KILLED_SHUTDOWN; privdata->shutdown = 1; /* * Separate from why_killed to avoid locking, as * why_killed may be changed from outside? */ if (finish_sending == 0) { Msg *msg; while ((msg = list_extract_first(privdata->outgoing_queue)) != NULL) { bb_smscconn_send_failed(conn, msg, SMSCCONN_FAILED_SHUTDOWN, NULL); } } gwthread_wakeup(privdata->device_thread); return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -