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

📄 virtmodem.c

📁 NOKIA手机开发包
💻 C
字号:
/*  $Id: virtmodem.c,v 1.41 2003/10/23 17:45:41 bozo Exp $  G N O K I I  A Linux/Unix toolset and driver for Nokia mobile phones.  This file is part of gnokii.  Gnokii 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.  Gnokii 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 gnokii; if not, write to the Free Software  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA  Copyright (C) 1999, 2000 Hugh Blemings & Pavel Jan韐 ml.  This file provides a virtual modem interface to the GSM phone by calling  code in gsm-api.c, at-emulator.c and datapump.c. The code here provides  the overall framework and coordinates switching between command mode  (AT-emulator) and "online" mode where the data pump code translates data  from/to the GSM handset and the modem data/fax stream.*/#include "config.h"/* * BEWARE! UGLY HACK! * We will define _XOPEN_SOURCE but it will disable the u_char, u_short, * u_int and u_long types on OpenBSD. It seems only the OpenBSD is affected, * so this is the workaround - bozo */#ifdef	__OpenBSD__#  include <sys/types.h>#  define HAVE_MSGHDR_MSG_CONTROL 1#endif/* same for FreeBSD */#ifdef	__FreeBSD__#  include <sys/types.h>#  undef	__BSD_VISIBLE#  define	__BSD_VISIBLE	1#endif/* This is the correct way to include stdlib with _XOPEN_SOURCE = 500 defined. * Needed for clean unlockpt() declaration. * msghdr structure in Solaris depends on _XOPEN_SOURCE = 500 too. - bozo */#define _XOPEN_SOURCE 500#include <stdio.h>#include <errno.h>#include <fcntl.h>#include <signal.h>#include <termios.h>#include <grp.h>#include <string.h>#include <sys/types.h>#include <sys/stat.h>#ifdef HAVE_SYS_TIME_H#  include <sys/time.h>#endif#include <unistd.h>#include <sys/socket.h>#include <sys/wait.h>#include <sys/uio.h>#include <sys/param.h>#include "compat.h"#include "misc.h"#include "gnokii.h"#include "data/at-emulator.h"#include "data/datapump.h"#include "device.h"/* Defines */#ifndef AF_LOCAL #  ifdef AF_UNIX#    define AF_LOCAL AF_UNIX#  else#    error AF_LOCAL not defined#  endif#endif/* Prototypes */static int  VM_PtySetup(char *bindir);static gn_error VM_GSMInitialise(struct gn_statemachine *sm);/* Global variables */extern bool GTerminateThread;int ConnectCount;bool CommandMode;/* Local variables */static int PtyRDFD;	/* File descriptor for reading and writing to/from */static int PtyWRFD;	/* pty interface - only different in debug mode. */static bool UseSTDIO;	/* Use STDIO for debugging purposes instead of pty */struct vm_queue queue;/* If initialised in debug mode, stdin/out is used instead   of ptys for interface. */bool gn_vm_initialise(const char *iname, char *bindir, bool debug_mode, bool GSMInit){	static struct gn_statemachine State;	sm = &State;	queue.n = 0;	queue.head = 0;	queue.tail = 0;	CommandMode = true;	if (debug_mode == true) {		UseSTDIO = true;	} else {		UseSTDIO = false;	}	if (GSMInit) {		dprintf("Initialising GSM\n");		if (!gn_cfg_phone_load(iname, sm)) return false;		if ((VM_GSMInitialise(sm) != GN_ERR_NONE)) {			fprintf (stderr, _("gn_vm_initialise - VM_GSMInitialise failed!\n"));			return (false);		}	}	GSMInit = false;	if (VM_PtySetup(bindir) < 0) {		fprintf (stderr, _("gn_vm_initialise - VM_PtySetup failed!\n"));		return (false);	}	if (gn_atem_initialise(PtyRDFD, PtyWRFD, sm) != true) {		fprintf (stderr, _("gn_vm_initialise - gn_atem_initialise failed!\n"));		return (false);	}	if (dp_Initialise(PtyRDFD, PtyWRFD) != true) {		fprintf (stderr, _("gn_vm_Initialise - dp_Initialise failed!\n"));		return (false);	}	return (true);}void gn_vm_loop(void){	fd_set rfds;	struct timeval tv;	int res;	int nfd, devfd;	int i, n;	char buf[256], *d;	devfd = device_getfd(sm);	nfd = (PtyRDFD > devfd) ? PtyRDFD + 1 : devfd + 1;	while (!GTerminateThread) {		if (CommandMode && gn_atem_initialised && queue.n > 0) {			d = queue.buf + queue.head;			queue.head = (queue.head + 1) % sizeof(queue.buf);			queue.n--;			gn_atem_incoming_data_handle(d, 1);			continue;		}		FD_ZERO(&rfds);		FD_SET(devfd, &rfds);		if ( queue.n < sizeof(queue.buf) ) {			FD_SET(PtyRDFD, &rfds);		}		tv.tv_sec = 0;		tv.tv_usec = 500000;		res = select(nfd, &rfds, NULL, NULL, &tv);		switch (res) {		case 0: /* Timeout */			continue;		case -1:			perror("gn_vm_loop - select");			exit (-1);		default:			break;		}		if (FD_ISSET(PtyRDFD, &rfds)) {			n = sizeof(queue.buf) - queue.n < sizeof(buf) ?				sizeof(queue.buf) - queue.n :				sizeof(buf);			if ( (n = read(PtyRDFD, buf, n)) <= 0 ) gn_vm_terminate();			for (i = 0; i < n; i++) {				queue.buf[queue.tail++] = buf[i];				queue.tail %= sizeof(queue.buf);				queue.n++;			}		}		if (FD_ISSET(devfd, &rfds)) gn_sm_loop(1, sm);	}}/* Application should call gn_vm_terminate to shut down   the virtual modem thread */void gn_vm_terminate(void){	/* Request termination of thread */	GTerminateThread = true;	if (!UseSTDIO) {		close (PtyRDFD);		close (PtyWRFD);	}	/* Shutdown device */	gn_sm_functions(GN_OP_Terminate, NULL, sm);}/* The following two functions are based on the skeleton from * W. Richard Stevens' "UNIX Network Programming", Volume 1, Second Edition. */static int gread(int fd, void *ptr, size_t nbytes, int *recvfd){	struct msghdr msg;	struct iovec iov[1];	int n;#ifdef HAVE_MSGHDR_MSG_CONTROL	union {		struct cmsghdr cm;		char control[CMSG_SPACE(sizeof(int))];	} control_un;	struct cmsghdr *cmptr;	msg.msg_control = control_un.control;	msg.msg_controllen = sizeof(control_un.control);#else	int newfd;	msg.msg_accrights = (caddr_t) &newfd;	msg.msg_accrightslen = sizeof(int);#endif /* HAVE_MSGHDR_MSG_CONTROL */	msg.msg_name = NULL;	msg.msg_namelen = 0;	iov[0].iov_base = ptr;	iov[0].iov_len = nbytes;	msg.msg_iov = iov;	msg.msg_iovlen = 1;	if ((n = recvmsg(fd, &msg, 0)) <= 0) return n;#ifdef HAVE_MSGHDR_MSG_CONTROL	if ((cmptr = CMSG_FIRSTHDR(&msg)) != NULL &&	    cmptr->cmsg_len == CMSG_LEN(sizeof(int))) {		if (cmptr->cmsg_level != SOL_SOCKET) perror("control level != SOL_SOCKET");		if (cmptr->cmsg_type != SCM_RIGHTS) perror("control type != SCM_RIGHTS");		*recvfd = *((int *)CMSG_DATA(cmptr));	} else {		*recvfd = -1;	}#else	if (msg.msg_accrightslen == sizeof(int)) *recvfd = newfd;	else *recvfd = -1;#endif /* HAVE_MSGHDR_MSG_CONTROL */	return (n);}static int gopen(const char *command){	int fd, sockfd[2], status;	pid_t childpid;	char c, argsockfd[10];	if (socketpair(AF_LOCAL, SOCK_STREAM, 0, sockfd) < 0) return -1;	switch (childpid = fork()) {	case -1:		/* Critical error */		return -1;	case 0:		/* Child */		close(sockfd[0]);		snprintf(argsockfd, sizeof(argsockfd), "%d", sockfd[1]);		execl(command, "mgnokiidev", argsockfd, NULL);		perror("execl: ");	default:		/* Parent */		break;	}	close(sockfd[1]);	waitpid(childpid, &status, 0);	if (WIFEXITED(status) == 0) perror("wait: ");	if ((status = WEXITSTATUS(status)) == 0) {		gread(sockfd[0], &c, 1, &fd);	} else {		errno = status;		fd = -1;	}	close(sockfd[0]);#ifdef USE_UNIX98PTYS	/*	 * I don't know why but it's required to operate correctly.	 * bozo -- tested on: Linux 2.4.17	 */	if (fd >= 0 && unlockpt(fd)) {		close(fd);		fd = -1;	}#endif	return(fd);}/* Open pseudo tty interface and (in due course create a symlink   to be /dev/gnokii etc. ) */static int VM_PtySetup(char *bindir){	char mgnokiidev[200];	if (UseSTDIO) {		PtyRDFD = STDIN_FILENO;		PtyWRFD = STDOUT_FILENO;		return (0);	}	if (bindir) {		strncpy(mgnokiidev, bindir, 200);		strcat(mgnokiidev, "/");	}	strncat(mgnokiidev, "mgnokiidev", 200 - strlen(bindir));	if (access(mgnokiidev, X_OK) != 0) {		fprintf(stderr, _("Cannot access %s, check the bindir in your gnokiirc!\n"), mgnokiidev);		exit(1);	}	PtyRDFD = gopen(mgnokiidev);	if (PtyRDFD < 0) {		fprintf (stderr, _("Couldn't open pty!\n"));		return(-1);	}	PtyWRFD = PtyRDFD;	return (0);}/* Initialise GSM interface, returning gn_error as appropriate  */static gn_error VM_GSMInitialise(struct gn_statemachine *sm){	gn_error error;	/* Initialise the code for the GSM interface. */	error = gn_gsm_initialise(sm);	if (error != GN_ERR_NONE)		fprintf(stderr, _("GSM/FBUS init failed!\n"));	return (error);}

⌨️ 快捷键说明

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