usock.c
来自「Linux下gsm/gprs modem的看守程序。支持短信发送与接受。」· C语言 代码 · 共 1,745 行 · 第 1/4 页
C
1,745 行
/* gsmd unix domain socket handling * * (C) 2006-2007 by OpenMoko, Inc. * Written by Harald Welte <laforge@openmoko.org> * All Rights Reserved * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * */ #define _GNU_SOURCE#include <stdlib.h>#include <stdio.h>#include <unistd.h>#include <string.h>#include <errno.h>#include <ctype.h>#include <sys/socket.h>#include <sys/un.h>#include "gsmd.h"#include <gsmd/gsmd.h>#include <gsmd/usock.h>#include <gsmd/select.h>#include <gsmd/atcmd.h>#include <gsmd/usock.h>#include <gsmd/talloc.h>#include <gsmd/extrsp.h>#include <gsmd/ts0707.h>#include <gsmd/sms.h>static void *__ucmd_ctx, *__gu_ctx;struct gsmd_ucmd *ucmd_alloc(int extra_size){ return talloc_size(__ucmd_ctx, sizeof(struct gsmd_ucmd) + extra_size);}void usock_cmd_enqueue(struct gsmd_ucmd *ucmd, struct gsmd_user *gu){ DEBUGP("enqueueing usock cmd %p for user %p\n", ucmd, gu); /* add to per-user list of finished cmds */ llist_add_tail(&ucmd->list, &gu->finished_ucmds); /* mark socket of user as we-want-to-write */ gu->gfd.when |= GSMD_FD_WRITE;}/* callback for completed passthrough gsmd_atcmd's */static int usock_cmd_cb(struct gsmd_atcmd *cmd, void *ctx, char *resp){ struct gsmd_user *gu = ctx; int rlen = strlen(resp)+1; struct gsmd_ucmd *ucmd = ucmd_alloc(rlen); DEBUGP("entering(cmd=%p, gu=%p)\n", cmd, gu); if (!ucmd) return -ENOMEM; /* FIXME: pass error values back somehow */ ucmd->hdr.version = GSMD_PROTO_VERSION; ucmd->hdr.msg_type = GSMD_MSG_PASSTHROUGH; ucmd->hdr.msg_subtype = GSMD_PASSTHROUGH_RESP; ucmd->hdr.len = rlen; ucmd->hdr.id = cmd->id; memcpy(ucmd->buf, resp, ucmd->hdr.len); usock_cmd_enqueue(ucmd, gu); return 0;}typedef int usock_msg_handler(struct gsmd_user *gu, struct gsmd_msg_hdr *gph, int len);static int usock_rcv_passthrough(struct gsmd_user *gu, struct gsmd_msg_hdr *gph, int len){ struct gsmd_atcmd *cmd; cmd = atcmd_fill((char *)gph+sizeof(*gph), gph->len, &usock_cmd_cb, gu, gph->id, NULL); if (!cmd) return -ENOMEM; DEBUGP("submitting cmd=%p, gu=%p\n", cmd, gu); return atcmd_submit(gu->gsmd, cmd);}static int usock_rcv_event(struct gsmd_user *gu, struct gsmd_msg_hdr *gph, int len){ u_int32_t *evtmask = (u_int32_t *) ((char *)gph + sizeof(*gph)); if (len < sizeof(*gph) + sizeof(u_int32_t)) return -EINVAL; if (gph->msg_subtype != GSMD_EVT_SUBSCRIPTIONS) return -EINVAL; gu->subscriptions = *evtmask; return 0;}static int voicecall_get_stat_cb(struct gsmd_atcmd *cmd, void *ctx, char *resp) { struct gsmd_user *gu = ctx; struct gsmd_call_status gcs; struct gsm_extrsp *er; DEBUGP("resp: %s\n", resp); er = extrsp_parse(cmd, resp); if ( !er ) return -ENOMEM; gcs.is_last = (cmd->ret == 0 || cmd->ret == 4)? 1:0; if ( !strncmp(resp, "OK", 2) ) { /* No existing call */ gcs.idx = 0; } else if ( !strncmp(resp, "+CME", 4) ) { /* +CME ERROR: <err> */ DEBUGP("+CME error\n"); gcs.idx = 0 - atoi(strpbrk(resp, "0123456789")); } else if ( er->num_tokens == 7 && er->tokens[0].type == GSMD_ECMD_RTT_NUMERIC && er->tokens[1].type == GSMD_ECMD_RTT_NUMERIC && er->tokens[2].type == GSMD_ECMD_RTT_NUMERIC && er->tokens[3].type == GSMD_ECMD_RTT_NUMERIC && er->tokens[4].type == GSMD_ECMD_RTT_NUMERIC && er->tokens[5].type == GSMD_ECMD_RTT_STRING && er->tokens[6].type == GSMD_ECMD_RTT_NUMERIC ) { /* * [+CLCC: <id1>,<dir>,<stat>,<mode>,<mpty>[, * <number>,<type>[,<alpha>]] * [<CR><LF>+CLCC: <id2>,<dir>,<stat>,<mode>,<mpty>[, * <number>,<type>[,<alpha>]] * [...]]] */ gcs.idx = er->tokens[0].u.numeric; gcs.dir = er->tokens[1].u.numeric; gcs.stat = er->tokens[2].u.numeric; gcs.mode = er->tokens[3].u.numeric; gcs.mpty = er->tokens[4].u.numeric; strlcpy(gcs.number, er->tokens[5].u.string, GSMD_ADDR_MAXLEN+1); gcs.type = er->tokens[6].u.numeric; } else if ( er->num_tokens == 8 && er->tokens[0].type == GSMD_ECMD_RTT_NUMERIC && er->tokens[1].type == GSMD_ECMD_RTT_NUMERIC && er->tokens[2].type == GSMD_ECMD_RTT_NUMERIC && er->tokens[3].type == GSMD_ECMD_RTT_NUMERIC && er->tokens[4].type == GSMD_ECMD_RTT_NUMERIC && er->tokens[5].type == GSMD_ECMD_RTT_STRING && er->tokens[6].type == GSMD_ECMD_RTT_NUMERIC && er->tokens[7].type == GSMD_ECMD_RTT_STRING ) { /* * [+CLCC: <id1>,<dir>,<stat>,<mode>,<mpty>[, * <number>,<type>[,<alpha>]] * [<CR><LF>+CLCC: <id2>,<dir>,<stat>,<mode>,<mpty>[, * <number>,<type>[,<alpha>]] * [...]]] */ gcs.idx = er->tokens[0].u.numeric; gcs.dir = er->tokens[1].u.numeric; gcs.stat = er->tokens[2].u.numeric; gcs.mode = er->tokens[3].u.numeric; gcs.mpty = er->tokens[4].u.numeric; strlcpy(gcs.number, er->tokens[5].u.string, GSMD_ADDR_MAXLEN+1); gcs.type = er->tokens[6].u.numeric; strlcpy(gcs.alpha, er->tokens[7].u.string, GSMD_ALPHA_MAXLEN+1); } else { DEBUGP("Invalid Input : Parse error\n"); return -EINVAL; } talloc_free(er); return gsmd_ucmd_submit(gu, GSMD_MSG_VOICECALL, GSMD_VOICECALL_GET_STAT, cmd->id, sizeof(gcs), &gcs);}static int voicecall_ctrl_cb(struct gsmd_atcmd *cmd, void *ctx, char *resp) { struct gsmd_user *gu = ctx; int ret = 0; DEBUGP("resp: %s\n", resp); if ( !strncmp(resp, "+CME", 4) ) { /* +CME ERROR: <err> */ DEBUGP("+CME error\n"); ret = atoi(strpbrk(resp, "0123456789")); } return gsmd_ucmd_submit(gu, GSMD_MSG_VOICECALL, GSMD_VOICECALL_CTRL, cmd->id, sizeof(ret), &ret);}static int voicecall_fwd_stat_cb(struct gsmd_atcmd *cmd, void *ctx, char *resp) { struct gsmd_user *gu = ctx; struct gsm_extrsp *er; struct gsmd_call_fwd_stat gcfs; DEBUGP("resp: %s\n", resp); er = extrsp_parse(cmd, resp); if ( !er ) return -ENOMEM; gcfs.is_last = (cmd->ret == 0 || cmd->ret == 4)? 1:0; if ( er->num_tokens == 2 && er->tokens[0].type == GSMD_ECMD_RTT_NUMERIC && er->tokens[1].type == GSMD_ECMD_RTT_NUMERIC ) { /* * +CCFC: <status>,<class1>[,<number>,<type> * [,<subaddr>,<satype>[,<time>]]][ * <CR><LF>+CCFC: <status>,<class2>[,<number>,<type> * [,<subaddr>,<satype>[,<time>]]] * [...]] */ gcfs.status = er->tokens[0].u.numeric; gcfs.classx = er->tokens[1].u.numeric; gcfs.addr.number[0] = '\0'; } else if ( er->num_tokens == 4 && er->tokens[0].type == GSMD_ECMD_RTT_NUMERIC && er->tokens[1].type == GSMD_ECMD_RTT_NUMERIC && er->tokens[2].type == GSMD_ECMD_RTT_STRING && er->tokens[3].type == GSMD_ECMD_RTT_NUMERIC ) { gcfs.status = er->tokens[0].u.numeric; gcfs.classx = er->tokens[1].u.numeric; strlcpy(gcfs.addr.number, er->tokens[2].u.string, GSMD_ADDR_MAXLEN+1); gcfs.addr.type = er->tokens[3].u.numeric; } else if ( er->num_tokens == 7 && er->tokens[0].type == GSMD_ECMD_RTT_NUMERIC && er->tokens[1].type == GSMD_ECMD_RTT_NUMERIC && er->tokens[2].type == GSMD_ECMD_RTT_STRING && er->tokens[3].type == GSMD_ECMD_RTT_NUMERIC && er->tokens[4].type == GSMD_ECMD_RTT_EMPTY && er->tokens[5].type == GSMD_ECMD_RTT_EMPTY && er->tokens[6].type == GSMD_ECMD_RTT_NUMERIC ) { gcfs.status = er->tokens[0].u.numeric; gcfs.classx = er->tokens[1].u.numeric; strlcpy(gcfs.addr.number, er->tokens[2].u.string, GSMD_ADDR_MAXLEN+1); gcfs.addr.type = er->tokens[3].u.numeric; gcfs.time = er->tokens[6].u.numeric; } else { DEBUGP("Invalid Input : Parse error\n"); return -EINVAL; } talloc_free(er); return gsmd_ucmd_submit(gu, GSMD_MSG_VOICECALL, GSMD_VOICECALL_FWD_STAT, cmd->id, sizeof(gcfs), &gcfs);}static int usock_ringing_cb(struct gsmd_atcmd *cmd, void *ctx, char *resp){ struct gsmd_user *gu = ctx; /* If the incoming call answer/rejection succeeded then we * know the modem isn't ringing and we update the state info. */ if (cmd->ret == 0) gu->gsmd->dev_state.ringing = 0; return usock_cmd_cb(cmd, ctx, resp);}static int usock_rcv_voicecall(struct gsmd_user *gu, struct gsmd_msg_hdr *gph, int len){ struct gsmd_atcmd *cmd = NULL; struct gsmd_addr *ga; struct gsmd_dtmf *gd; struct gsmd_call_ctrl *gcc; struct gsmd_call_fwd_reg *gcfr; char buf[64]; int atcmd_len; int *reason; switch (gph->msg_subtype) { case GSMD_VOICECALL_DIAL: if (len < sizeof(*gph) + sizeof(*ga)) return -EINVAL; ga = (struct gsmd_addr *) ((void *)gph + sizeof(*gph)); ga->number[GSMD_ADDR_MAXLEN] = '\0'; cmd = atcmd_fill("ATD", 5 + strlen(ga->number), &usock_cmd_cb, gu, gph->id, NULL); if (!cmd) return -ENOMEM; sprintf(cmd->buf, "ATD%s;", ga->number); /* FIXME: number type! */ break; case GSMD_VOICECALL_HANGUP: /* ATH0 is not supported by QC, we hope ATH is supported by everone */ cmd = atcmd_fill("ATH", 4, gu->gsmd->dev_state.ringing ? usock_ringing_cb : usock_cmd_cb, gu, gph->id,NULL); /* This command is special because it needs to be sent to * the MS even if a command is currently executing. */ if (cmd) { return cancel_atcmd(gu->gsmd, cmd); } break; case GSMD_VOICECALL_ANSWER: cmd = atcmd_fill("ATA", 4, &usock_ringing_cb, gu, gph->id,NULL); break; case GSMD_VOICECALL_DTMF: if (len < sizeof(*gph) + sizeof(*gd)) return -EINVAL; gd = (struct gsmd_dtmf *) ((void *)gph + sizeof(*gph)); if (len < sizeof(*gph) + sizeof(*gd) + gd->len) return -EINVAL; /* FIXME: we don't yet support DTMF of multiple digits */ if (gd->len != 1) return -EINVAL; atcmd_len = 1 + strlen("AT+VTS=") + (gd->len * 2); cmd = atcmd_fill("AT+VTS=", atcmd_len, &usock_cmd_cb, gu, gph->id, NULL); if (!cmd) return -ENOMEM; sprintf(cmd->buf, "AT+VTS=%c;", gd->dtmf[0]); break; case GSMD_VOICECALL_GET_STAT: cmd = atcmd_fill("AT+CLCC", 7+1, &voicecall_get_stat_cb, gu, gph->id, NULL); if (!cmd) return -ENOMEM; break; case GSMD_VOICECALL_CTRL: if (len < sizeof(*gph) + sizeof(*gcc)) return -EINVAL; gcc = (struct gsmd_call_ctrl *) ((void *)gph + sizeof(*gph)); atcmd_len = 1 + strlen("AT+CHLD=") + 2; cmd = atcmd_fill("AT+CHLD=", atcmd_len, &voicecall_ctrl_cb, gu, gph->id, NULL); if (!cmd) return -ENOMEM; switch (gcc->proc) { case GSMD_CALL_CTRL_R_HLDS: case GSMD_CALL_CTRL_UDUB: sprintf(cmd->buf, "AT+CHLD=%d", 0); break; case GSMD_CALL_CTRL_R_ACTS_A_HLD_WAIT: sprintf(cmd->buf, "AT+CHLD=%d", 1); break; case GSMD_CALL_CTRL_R_ACT_X: sprintf(cmd->buf, "AT+CHLD=%d%d", 1, gcc->idx); break; case GSMD_CALL_CTRL_H_ACTS_A_HLD_WAIT: sprintf(cmd->buf, "AT+CHLD=%d", 2); break; case GSMD_CALL_CTRL_H_ACTS_EXCEPT_X: sprintf(cmd->buf, "AT+CHLD=%d%d", 2, gcc->idx); break; case GSMD_CALL_CTRL_M_HELD: sprintf(cmd->buf, "AT+CHLD=%d", 3); break; default: return -EINVAL; } break; case GSMD_VOICECALL_FWD_DIS: if(len < sizeof(*gph) + sizeof(int)) return -EINVAL; reason = (int *) ((void *)gph + sizeof(*gph)); sprintf(buf, "%d,0", *reason); atcmd_len = 1 + strlen("AT+CCFC=") + strlen(buf); cmd = atcmd_fill("AT+CCFC=", atcmd_len, &usock_cmd_cb, gu, gph->id, NULL); if (!cmd) return -ENOMEM; sprintf(cmd->buf, "AT+CCFC=%s", buf); break; case GSMD_VOICECALL_FWD_EN: if(len < sizeof(*gph) + sizeof(int)) return -EINVAL; reason = (int *) ((void *)gph + sizeof(*gph)); sprintf(buf, "%d,1", *reason); atcmd_len = 1 + strlen("AT+CCFC=") + strlen(buf); cmd = atcmd_fill("AT+CCFC=", atcmd_len, &usock_cmd_cb, gu, gph->id, NULL); if (!cmd) return -ENOMEM; sprintf(cmd->buf, "AT+CCFC=%s", buf); break; case GSMD_VOICECALL_FWD_STAT: if(len < sizeof(*gph) + sizeof(int)) return -EINVAL;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?