📄 smsc_cgw.c
字号:
}/****************************************************************************** * cgw_read_op - read an operation, and return it as a *cgwop structure * * This function will not lock and wait for data if none is available. It will * however lock until a whole op has been read. Timeout not implemented yet. */struct cgwop *cgw_read_op(PrivData *privdata, SMSCConn *conn, Connection *server, time_t timeout){ Octstr *line, *name, *value; int finished = 0; int c = 0; struct cgwop *cgwop = NULL; int op = CGW_OP_NOP; if ((line = conn_read_line(server)) == NULL) return NULL; /* don't block */ do { while (line == NULL) line = conn_read_line(server); /* wait for more data */ c = octstr_search_char(line, ':', 0); if (c != -1) { name = octstr_copy(line, 0, c); value = octstr_copy(line, c + 1, octstr_len(line) - (c + 1)); if (octstr_compare(name, octstr_imm("hello")) == 0) { /* A connection is started by CGW by sending a * "hello: Provider Server..." line. */ cgwop = cgwop_create(CGW_OP_HELLO, 0); cgwop_add(cgwop, octstr_imm("hello"), value); octstr_destroy(name); octstr_destroy(value); octstr_destroy(line); return cgwop; } if (octstr_compare(name, octstr_imm("op")) == 0) { /* check different ops */ if (octstr_compare(value, octstr_imm("msg")) == 0) op = CGW_OP_MSG; else if (octstr_compare(value, octstr_imm("ok")) == 0) op = CGW_OP_OK; else if (octstr_compare(value, octstr_imm("delivery")) == 0) op = CGW_OP_DELIVERY; else if (octstr_compare(value, octstr_imm("err")) == 0) op = CGW_OP_ERR; else if (octstr_compare(value, octstr_imm("status")) == 0) op = CGW_OP_STATUS; else info(0, "CGW: Received unknown op: %s", octstr_get_cstr(value)); if (cgwop == NULL) cgwop = cgwop_create(op, 0); else info(0, "cgw: cgwop != null"); } if (op != CGW_OP_NOP) { /* All commands have to be inside an op:xx ... end:xx statement */ if (octstr_compare(name, octstr_imm("end")) == 0) { // found end of op finished = 1; } else { // store in name/value fields in cgwop if (cgwop != NULL) { cgwop_add(cgwop, name, value); } } } octstr_destroy(name); octstr_destroy(value); octstr_destroy(line); if (!finished) line = conn_read_line(server); } else { info(0, "cgw: Received invalid input: %s", octstr_get_cstr(line)); octstr_destroy(line); finished = 1; } } while (!finished); return cgwop;}static int cgw_open_listening_socket(PrivData *privdata){ int s; if ((s = make_server_socket(privdata->rport, NULL)) == -1) { /* XXX add interface_name if required */ error(0, "smsc_cgw: could not create listening socket in port %d", privdata->rport); return -1; } if (socket_set_blocking(s, 0) == -1) { error(0, "smsc_cgw: couldn't make listening socket port %d non-blocking", privdata->rport); close(s); return -1; } privdata->listening_socket = s; return 0;}/****************************************************************************** * This is the entry point for our receiver thread. Listens for incoming * connections and handles operations. */static void cgw_listener(void *arg){ SMSCConn *conn = arg; PrivData *privdata = conn->data; struct sockaddr_in server_addr; socklen_t server_addr_len; Octstr *ip; Connection *server; int s, ret; while (!privdata->shutdown) { server_addr_len = sizeof(server_addr); ret = gwthread_pollfd(privdata->listening_socket, POLLIN, -1); if (ret == -1) { if (errno == EINTR) continue; error(0, "Poll for cgw smsc connections failed, shutting down"); break; } if (privdata->shutdown) break; if (ret == 0) /* This thread was woken up from elsewhere, but * if we're not shutting down nothing to do here. */ continue; s = accept(privdata->listening_socket, (struct sockaddr *) & server_addr, &server_addr_len); if (s == -1) { warning(errno, "cgw_listener: accept() failed, retrying..."); continue; } ip = host_ip(server_addr); if (!is_allowed_ip(privdata->allow_ip, privdata->deny_ip, ip)) { info(0, "CGW smsc connection tried from denied host <%s>, disconnected", octstr_get_cstr(ip)); octstr_destroy(ip); close(s); continue; } server = conn_wrap_fd(s, 0); if (server == NULL) { error(0, "cgw_listener: conn_wrap_fd failed on accept()ed fd"); octstr_destroy(ip); close(s); continue; } conn_claim(server); info(0, "cgw: smsc connected from %s", octstr_get_cstr(ip)); octstr_destroy(ip); cgw_receiver(conn, server); conn_destroy(server); } if (close(privdata->listening_socket) == -1) warning(errno, "smsc_cgw: couldn't close listening socket at shutdown"); gwthread_wakeup(privdata->sender_thread);}static void cgw_receiver(SMSCConn *conn, Connection *server){ PrivData *privdata = conn->data; Octstr *str = NULL; struct cgwop *cgwop; while (1) { if (conn_eof(server)) { info(0, "cgw: receive connection closed by SMSC"); return ; } if (conn_read_error(server)) { error(0, "cgw: receive connection broken"); return ; } if (conn->is_stopped) str = NULL; cgwop = cgw_read_op(conn->data, conn, server, 0); if (cgwop != NULL) { cgw_handle_op(conn, server, cgwop); cgwop_destroy(cgwop); } else conn_wait(server, -1); if (privdata->shutdown) break; } return ;}/****************************************************************************** * This function handles incoming operations. Used by both receiver and sender * threads (i.e. sender thread uses this function for delivery and ack * operations). * Returns 1 if successfull, otherwise 0 */static int cgw_handle_op(SMSCConn *conn, Connection *server, struct cgwop *cgwop){ PrivData *privdata = conn->data; Msg *msg = NULL; Octstr *from, *app, *sid, *to, *msgtype, *msgdata; /* for messages */ Octstr *msid, *status, *txt; /* delivery reports */ Octstr *clid; /* for acks */ struct cgwop *reply = NULL; long trn, stat; /* transaction number for ack */ Msg *dlrmsg = NULL, *origmsg = NULL; Octstr *ts; if (cgwop == NULL) return 0; from = cgwop_get(cgwop, octstr_imm("from")); app = cgwop_get(cgwop, octstr_imm("app")); sid = cgwop_get(cgwop, octstr_imm("session-id")); to = cgwop_get(cgwop, octstr_imm("to")); msgtype = cgwop_get(cgwop, octstr_imm("type")); msgdata = cgwop_get(cgwop, octstr_imm("msg")); txt = cgwop_get(cgwop, octstr_imm("txt")); msid = cgwop_get(cgwop, octstr_imm("msid")); status = cgwop_get(cgwop, octstr_imm("status")); clid = cgwop_get(cgwop, octstr_imm("client-id")); if (clid != NULL) { octstr_parse_long(&trn, clid, 0, 10); if ((trn < 0) || (trn >= CGW_TRN_MAX)) { /* invalid transaction number */ info(0, "cgw: Invalid transaction number: %d", (int) trn); trn = -1; return 0; } } switch (cgwop->op) { case CGW_OP_MSG: msg = msg_create(sms); time(&msg->sms.time); msg->sms.msgdata = cgw_decode_msg(octstr_duplicate(msgdata)); msg->sms.sender = octstr_duplicate(from); msg->sms.receiver = octstr_duplicate(to); msg->sms.smsc_id = octstr_duplicate(conn->id); bb_smscconn_receive(conn, msg); reply = cgwop_create(CGW_OP_OK, -1); cgwop_add(reply, octstr_imm("session-id"), sid); cgwop_send(server, reply); // send reply cgwop_destroy(reply); break; case CGW_OP_DELIVERY: if (privdata->dlr[trn]) { octstr_parse_long(&stat, status, 0, 10); origmsg = privdata->sendmsg[trn]; if (origmsg == NULL) break; ts = octstr_create(""); octstr_append(ts, conn->id); octstr_append_char(ts, '-'); octstr_append_decimal(ts, trn); switch (stat) { case 0: /* delivered */ dlrmsg = dlr_find(octstr_get_cstr(conn->id), octstr_get_cstr(ts), /* timestamp */ octstr_get_cstr(msid), /* destination */ DLR_SUCCESS); break; case 1: /* buffered */ dlrmsg = dlr_find(octstr_get_cstr(conn->id), octstr_get_cstr(ts), /* timestamp */ octstr_get_cstr(msid), /* destination */ DLR_BUFFERED); break; case 2: /* not delivered */ dlrmsg = dlr_find(octstr_get_cstr(conn->id), octstr_get_cstr(ts), /* timestamp */ octstr_get_cstr(msid), /* destination */ DLR_FAIL); break; } octstr_destroy(ts); if (dlrmsg != NULL) { dlrmsg->sms.msgdata = octstr_duplicate(txt); bb_smscconn_receive(conn, dlrmsg); } } break; case CGW_OP_OK: if (trn == -1) break; /* invalid transaction number */ /* info(0, "cgw: Got ACK: %s", octstr_get_cstr(clid)); */ privdata->sendtime[trn] = 0; privdata->unacked--; /* add delivery notification request if wanted */ msg = privdata->sendmsg[trn]; if (msg && msg->sms.dlr_url && (msg->sms.dlr_mask & 0x07)) { Octstr *ts; ts = octstr_create(""); octstr_append(ts, conn->id); octstr_append_char(ts, '-'); octstr_append_decimal(ts, trn); dlr_add(octstr_get_cstr(conn->id), octstr_get_cstr(ts), octstr_get_cstr(msg->sms.sender), octstr_get_cstr(msg->sms.receiver), octstr_get_cstr(msg->sms.service), octstr_get_cstr(msg->sms.dlr_url), msg->sms.dlr_mask); octstr_destroy(ts); privdata->dlr[trn] = 1; } else { privdata->dlr[trn] = 0; } bb_smscconn_sent(conn, msg); /* mark as successfully sent */ break; case CGW_OP_STATUS: info(0, "CGW: Warning: Got session status"); /* op:status messages are sent by ProviderServer to tell if there are problems with the session status. These are not wanted, and should never occur, as the delivery is cancelled, and no end-user billing is done. */ break; case CGW_OP_HELLO: info(0, "CGW: Server said: %s", octstr_get_cstr(cgwop_get(cgwop, octstr_imm("hello")))); break; case CGW_OP_ERR: if (trn == -1) break; /* invalid transaction number */ info(0, "CGW: Received error: %s", octstr_get_cstr(txt)); privdata->sendtime[trn] = 0; privdata->unacked--; bb_smscconn_send_failed(conn, privdata->sendmsg[trn], SMSCCONN_FAILED_REJECTED); break; default: info(0, "cgw: Unknown operation: %d", cgwop->op); return 0; } return 1;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -