source: mediastreamer2/linphone/console/shell.c @ 263:12947b259fb3

Last change on this file since 263:12947b259fb3 was 263:12947b259fb3, checked in by smorlat <smorlat@…>, 4 years ago

make linphonecsh/linphonec work on windows

git-svn-id: svn+ssh://svn.savannah.nongnu.org/linphone/trunk@266 3f6dc0c8-ddfe-455d-9043-3cd528dc4637

File size: 8.8 KB
Line 
1/****************************************************************************
2 *  Copyright (C) 2009  Simon MORLAT <simon.morlat@linphone.org>
3 *
4 ****************************************************************************
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19 *
20 ****************************************************************************/
21
22
23#include <stdio.h>
24#include <stdlib.h>
25
26
27#ifdef WIN32
28#include <ws2tcpip.h>
29#include <ctype.h>
30#include <conio.h>
31#else
32#include <sys/socket.h>
33#include <netdb.h>
34#include <sys/un.h>
35
36#endif
37
38#include "ortp/ortp.h"
39
40#define DEFAULT_TCP_PORT "32333"
41#define DEFAULT_REPLY_SIZE 4096
42
43#define STATUS_REGISTERED (1<<0)
44#define STATUS_REGISTERING (1<<1)
45#define STATUS_DIALING (1<<2)
46#define STATUS_AUTOANSWER (1<<3)
47#define STATUS_IN_CONNECTED (1<<4) /* incoming call accepted */
48#define STATUS_OUT_CONNECTED (1<<5) /*outgoing call accepted */
49
50#ifndef WIN32
51static int tcp=0;
52#else
53static int tcp=1;
54#endif
55
56static int make_status_value(const char *status_string){
57        int ret=0;
58        if (strstr(status_string,"registered, identity=")){
59                ret|=STATUS_REGISTERED;
60        }
61        if (strstr(status_string,"registered=-1")){
62                ret|=STATUS_REGISTERING;
63        }
64        if (strstr(status_string,"autoanswer=1")){
65                ret|=STATUS_AUTOANSWER;
66        }
67        if (strstr(status_string,"dialing")){
68                ret|=STATUS_DIALING;
69        }
70        if (strstr(status_string,"Call out")){
71                ret|=STATUS_OUT_CONNECTED;
72        }
73        if (strstr(status_string,"hook=answered")){
74                ret|=STATUS_IN_CONNECTED;
75        }
76        return ret;
77}
78
79static int send_command(const char *command, const char * port, char *reply, int reply_len, int print_errors){
80        ortp_socket_t sock;
81        int i;
82        int err;
83        if (tcp){
84                struct addrinfo *ai=NULL;
85                struct addrinfo hints;
86                memset(&hints,0,sizeof(hints));
87                hints.ai_family=AF_INET;
88                hints.ai_socktype=SOCK_STREAM;
89                err=getaddrinfo("127.0.0.1",port,&hints,&ai);
90                if (err!=0){
91                        if (print_errors) fprintf(stderr,"ERROR: getaddrinfo failed: error %i\n", err);
92                        return -1;
93                }
94                sock=socket(PF_INET,SOCK_STREAM,IPPROTO_TCP);
95                if (connect(sock,ai->ai_addr,ai->ai_addrlen)!=0){
96                        if (print_errors) fprintf(stderr,"ERROR: Failed to connect socket.\n");
97                        freeaddrinfo(ai);
98                        return -1;
99                }
100                freeaddrinfo(ai);
101        }else{
102#ifndef WIN32
103                struct sockaddr_un sa;
104                char path[128];
105                sock=socket(AF_UNIX,SOCK_STREAM,0);
106                sa.sun_family=AF_UNIX;
107                snprintf(path,sizeof(path)-1,"/tmp/linphonec-%i",getuid());
108                strncpy(sa.sun_path,path,sizeof(sa.sun_path)-1);
109                if (connect(sock,(struct sockaddr*)&sa,sizeof(sa))!=0){
110                        if (print_errors) fprintf(stderr,"ERROR: Failed to connect socket: %s\n",getSocketError());
111                        return -1;
112                }
113#else
114                fprintf(stderr,"ERROR: windows pipes communication not yet implemented.\n");
115                return -1;
116#endif
117        }
118        if (send(sock,command,strlen(command),0)<0){
119                if (print_errors) fprintf(stderr,"ERROR: Fail to send command to remote linphonec\n");
120                close_socket(sock);
121                return -1;
122        }
123        /*wait for replies */
124        i=0;
125        while ((err=recv(sock,&reply[i],reply_len-i-1,0))>0){
126                i+=err;
127        }
128        reply[i]='\0';
129        close_socket(sock);
130        return 0;
131}
132
133static void print_usage(void){
134        fprintf(stderr,"Usage:\nlinphonecsh <action> [arguments]\n"
135                        "where action is one of\n"
136                        "\tinit\t\t: spawn a linphonec daemon (first step to make other actions)\n"
137                        "\t\t\tfollowed by the arguments sent to linphonec\n"
138                        "\tgeneric\t\t: sends a generic command to the running linphonec daemon\n"
139                        "\t\t\tfollowed by the generic command surrounded by quotes,\n\t\t\t for example \"call sip:joe@example.net\"\n"
140                        "\tregister\t: register; arguments are \n\t\t\t--host <host>\n\t\t\t--username <username>\n\t\t\t--password <password>\n"
141                        "\tunregister\t: unregister\n"
142                        "\tdial\t\t: dial <sip uri or number>\n"
143                        "\tstatus\t\t: can be 'status register', 'status autoanswer' or 'status hook'\n"
144                        "\texit\t\t: make the linphonec daemon to exit.\n"
145        );
146        exit(-1);
147}
148
149#define MAX_ARGS 10
150
151#ifndef WIN32
152static void spawn_linphonec(int argc, char *argv[]){
153        char * args[10];
154        int i,j;
155        pid_t pid;
156        j=0;
157        args[j++]="linphonec";
158        if (tcp){
159                args[j++]="--tcp";
160                args[j++]=DEFAULT_TCP_PORT;
161        }else args[j++]="--pipe";
162        args[j++]="-c";
163        args[j++]="/dev/null";
164        for(i=0;i<argc;++i){
165                args[j++]=argv[i];
166        }
167        args[j++]=NULL;
168
169        pid = fork();
170        if (pid < 0){
171                fprintf(stderr,"Could not fork\n");
172                exit(-1);
173        }
174        if (pid == 0) {
175                int fd;
176                /*we are the new process*/
177                setsid();
178               
179                fd = open("/dev/null", O_RDWR);
180                if (fd==-1){
181                        fprintf(stderr,"Could not open /dev/null\n");
182                        exit(-1);
183                }
184                dup2(fd, 0);
185                dup2(fd, 1);
186                dup2(fd, 2);
187                close(fd);
188               
189                if (execvp("linphonec",args)==-1){
190                        fprintf(stderr,"Fail to spawn linphonec: %s\n",strerror(errno));
191                        exit(-1);
192                }
193        }
194}
195#else
196
197static void spawn_linphonec(int argc, char *argv[]){
198        PPROCESS_INFORMATION pi;
199        STARTUPINFO si;
200        ZeroMemory( &si, sizeof(si) );
201    si.cb = sizeof(si);
202    ZeroMemory( &pi, sizeof(pi) );
203
204
205        BOOL ret=CreateProcess(NULL,"linphonec.exe --tcp " DEFAULT_TCP_PORT " -c NUL",
206                NULL,
207                NULL,
208                FALSE,
209                0,
210                NULL,
211                NULL,
212                &si,
213                &pi);
214        if (!ret){
215                fprintf(stderr,"Spawning of linphonec.exe failed.\n");
216        }
217}
218
219#endif
220
221static int send_generic_command(const char *command, int print_result){
222        char reply[DEFAULT_REPLY_SIZE];
223        int err;
224        err=send_command(command,DEFAULT_TCP_PORT,reply,sizeof(reply),print_result);
225        if (err==0 && print_result) {
226                printf("%s",reply);
227                fflush(stdout);
228        }
229        return err;
230}
231
232static int register_execute(int argc, char *argv[]){
233        char cmd[512];
234        char *username=NULL;
235        char *host=NULL;
236        char *passwd=NULL;
237        int i;
238        for(i=0;i<argc;++i){
239                if (strcmp(argv[i],"--host")==0){
240                        i++;
241                        if (i<argc){
242                                host=argv[i];
243                        }else print_usage();
244                }else if (strcmp(argv[i],"--username")==0){
245                        i++;
246                        if (i<argc){
247                                username=argv[i];
248                        }else print_usage();
249                }else if (strcmp(argv[i],"--password")==0){
250                        i++;
251                        if (i<argc){
252                                passwd=argv[i];
253                        }else print_usage();
254                }else print_usage();
255        }
256        if (username==NULL) {
257                fprintf(stderr,"Missing --username\n");
258                print_usage();
259        }
260        if (host==NULL) {
261                fprintf(stderr,"Missing --host\n");
262                print_usage();
263        }
264        if (passwd) snprintf(cmd,sizeof(cmd),"register sip:%s@%s sip:%s %s",username,host,host,passwd);
265        else snprintf(cmd,sizeof(cmd),"register sip:%s@%s sip:%s",username,host,host);
266        return send_generic_command(cmd,TRUE);
267}
268
269static int unregister_execute(int argc, char *argv[]){
270        return send_generic_command("unregister",FALSE);
271}
272
273
274static int dial_execute(int argc, char *argv[]){
275        char cmd[512];
276        if (argc==1){
277                snprintf(cmd,sizeof(cmd),"call %s",argv[0]);
278                return send_generic_command(cmd,TRUE);
279        }else{
280                print_usage();
281        }
282        return -1;
283}
284
285static int status_execute(int argc, char *argv[]){
286        char cmd[512];
287        char reply[DEFAULT_REPLY_SIZE];
288        int err;
289       
290        if (argc==1){
291                snprintf(cmd,sizeof(cmd),"status %s",argv[0]);
292                err=send_command(cmd,DEFAULT_TCP_PORT,reply,sizeof(reply),TRUE);
293                if (err==0) {
294                        printf("%s",reply);
295                        err=make_status_value(reply);
296                }
297                return err;
298        }else{
299                print_usage();
300        }
301        return -1;
302}
303
304int main(int argc, char *argv[]){
305        int argi;
306        if (argc<2){
307                print_usage();
308                return -1;
309        }
310        ortp_init();
311        for(argi=1;argi<argc;++argi){
312                if (strcmp(argv[argi],"--tcp")==0){
313                        tcp=1;
314                }else if (strcmp(argv[argi],"init")==0){
315                        /*check if there is running instance*/
316                        if (send_generic_command("help",0)==0){
317                                fprintf(stderr,"A running linphonec has been found, not spawning a second one.\n");
318                                return 0;
319                        }
320                        spawn_linphonec(argc-argi-1,&argv[argi+1]);
321                        if (tcp) fprintf(stderr,"WARNING: using --tcp is unsafe: unprivilegied users can make calls.\n");
322                        return 0;
323                }else if (strcmp(argv[argi],"generic")==0){
324                        if (argi+1<argc){
325                                return send_generic_command(argv[argi+1],1);
326                        }else print_usage();
327                }else if (strcmp(argv[argi],"register")==0){
328                        return register_execute(argc-argi-1,&argv[argi+1]);
329                }else if (strcmp(argv[argi],"unregister")==0){
330                        return unregister_execute(argc-argi-1,&argv[argi+1]);
331                }else if (strcmp(argv[argi],"dial")==0){
332                        return dial_execute(argc-argi-1,&argv[argi+1]);
333                }else if (strcmp(argv[argi],"hangup")==0){
334                        send_generic_command("terminate",FALSE);
335                        send_generic_command("duration",TRUE);
336                }else if (strcmp(argv[argi],"status")==0){
337                        return status_execute(argc-argi-1,&argv[argi+1]);
338                }else if (strcmp(argv[argi],"exit")==0){
339                        return send_generic_command("quit",TRUE);
340                }else print_usage();
341        }
342        return 0;
343}
Note: See TracBrowser for help on using the repository browser.