source: mediastreamer2/linphone/console/shell.c @ 256:70ad9c490986

Last change on this file since 256:70ad9c490986 was 256:70ad9c490986, checked in by smorlat <smorlat@…>, 4 years ago

linphonecsh and linphonec use a unix socket by default, for security reasons

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

File size: 8.3 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#else
30#include <sys/socket.h>
31#include <netdb.h>
32#include <sys/un.h>
33
34#endif
35
36#include "ortp/ortp.h"
37
38#define DEFAULT_TCP_PORT "32333"
39#define DEFAULT_REPLY_SIZE 4096
40
41#define STATUS_REGISTERED (1<<0)
42#define STATUS_REGISTERING (1<<1)
43#define STATUS_DIALING (1<<2)
44#define STATUS_AUTOANSWER (1<<3)
45#define STATUS_IN_CONNECTED (1<<4) /* incoming call accepted */
46#define STATUS_OUT_CONNECTED (1<<5) /*outgoing call accepted */
47
48static int tcp=0;
49
50static int make_status_value(const char *status_string){
51        int ret=0;
52        if (strstr(status_string,"registered, identity=")){
53                ret|=STATUS_REGISTERED;
54        }
55        if (strstr(status_string,"registered=-1")){
56                ret|=STATUS_REGISTERING;
57        }
58        if (strstr(status_string,"autoanswer=1")){
59                ret|=STATUS_AUTOANSWER;
60        }
61        if (strstr(status_string,"dialing")){
62                ret|=STATUS_DIALING;
63        }
64        if (strstr(status_string,"Call out")){
65                ret|=STATUS_OUT_CONNECTED;
66        }
67        if (strstr(status_string,"hook=answered")){
68                ret|=STATUS_IN_CONNECTED;
69        }
70        return ret;
71}
72
73static int send_command(const char *command, const char * port, char *reply, int reply_len, int print_errors){
74        ortp_socket_t sock;
75        int i;
76        int err;
77        if (tcp){
78                struct addrinfo *ai=NULL;
79                struct addrinfo hints;
80                memset(&hints,0,sizeof(hints));
81                hints.ai_family=AF_INET;
82                hints.ai_socktype=SOCK_STREAM;
83                err=getaddrinfo("127.0.0.1",port,&hints,&ai);
84                if (err!=0){
85                        if (print_errors) fprintf(stderr,"ERROR: getaddrinfo failed: error %i\n", err);
86                        return -1;
87                }
88                sock=socket(PF_INET,SOCK_STREAM,IPPROTO_TCP);
89                if (connect(sock,ai->ai_addr,ai->ai_addrlen)!=0){
90                        if (print_errors) fprintf(stderr,"ERROR: Failed to connect socket.\n");
91                        freeaddrinfo(ai);
92                        return -1;
93                }
94                freeaddrinfo(ai);
95        }else{
96#ifndef WIN32
97                struct sockaddr_un sa;
98                char path[128];
99                sock=socket(AF_UNIX,SOCK_STREAM,0);
100                sa.sun_family=AF_UNIX;
101                snprintf(path,sizeof(path)-1,"/tmp/linphonec-%i",getuid());
102                strncpy(sa.sun_path,path,sizeof(sa.sun_path)-1);
103                if (connect(sock,(struct sockaddr*)&sa,sizeof(sa))!=0){
104                        if (print_errors) fprintf(stderr,"ERROR: Failed to connect socket: %s\n",getSocketError());
105                        return -1;
106                }
107#else
108                fprintf(stderr,"ERROR: windows pipes communication not yet implemented.\n");
109                return -1;
110#endif
111        }
112        if (send(sock,command,strlen(command),0)<0){
113                if (print_errors) fprintf(stderr,"ERROR: Fail to send command to remote linphonec\n");
114                close_socket(sock);
115                return -1;
116        }
117        /*wait for replies */
118        i=0;
119        while ((err=recv(sock,&reply[i],reply_len-i-1,0))>0){
120                i+=err;
121        }
122        reply[i]='\0';
123        close_socket(sock);
124        return 0;
125}
126
127static void print_usage(void){
128        fprintf(stderr,"Usage:\nlinphonecsh <action> [arguments]\n"
129                        "where action is one of\n"
130                        "\tinit\t\t: spawn a linphonec daemon (first step to make other actions)\n"
131                        "\t\t\tfollowed by the arguments sent to linphonec\n"
132                        "\tgeneric\t\t: sends a generic command to the running linphonec daemon\n"
133                        "\t\t\tfollowed by the generic command surrounded by quotes,\n\t\t\t for example \"call sip:joe@example.net\"\n"
134                        "\tregister\t: register; arguments are \n\t\t\t--host <host>\n\t\t\t--username <username>\n\t\t\t--password <password>\n"
135                        "\tunregister\t: unregister\n"
136                        "\tdial\t\t: dial <sip uri or number>\n"
137                        "\tstatus\t\t: can be 'status register', 'status autoanswer' or 'status hook'\n"
138                        "\texit\t\t: make the linphonec daemon to exit.\n"
139        );
140        exit(-1);
141}
142
143#define MAX_ARGS 10
144
145static void spawn_linphonec(int argc, char *argv[]){
146        char * args[10];
147        int i,j;
148        pid_t pid;
149        j=0;
150        args[j++]="linphonec";
151        if (tcp){
152                args[j++]="--tcp";
153                args[j++]=DEFAULT_TCP_PORT;
154        }else args[j++]="--pipe";
155        args[j++]="-c";
156        args[j++]="/dev/null";
157        for(i=0;i<argc;++i){
158                args[j++]=argv[i];
159        }
160        args[j++]=NULL;
161
162        pid = fork();
163        if (pid < 0){
164                fprintf(stderr,"Could not fork\n");
165                exit(-1);
166        }
167        if (pid == 0) {
168                int fd;
169                /*we are the new process*/
170                setsid();
171               
172                fd = open("/dev/null", O_RDWR);
173                if (fd==-1){
174                        fprintf(stderr,"Could not open /dev/null\n");
175                        exit(-1);
176                }
177                dup2(fd, 0);
178                dup2(fd, 1);
179                dup2(fd, 2);
180                close(fd);
181               
182                if (execvp("linphonec",args)==-1){
183                        fprintf(stderr,"Fail to spawn linphonec: %s\n",strerror(errno));
184                        exit(-1);
185                }
186        }
187}
188
189static int send_generic_command(const char *command, int print_result){
190        char reply[DEFAULT_REPLY_SIZE];
191        int err;
192        err=send_command(command,DEFAULT_TCP_PORT,reply,sizeof(reply),print_result);
193        if (err==0 && print_result) printf("%s",reply);
194        return err;
195}
196
197static int register_execute(int argc, char *argv[]){
198        char cmd[512];
199        char *username=NULL;
200        char *host=NULL;
201        char *passwd=NULL;
202        int i;
203        for(i=0;i<argc;++i){
204                if (strcmp(argv[i],"--host")==0){
205                        i++;
206                        if (i<argc){
207                                host=argv[i];
208                        }else print_usage();
209                }else if (strcmp(argv[i],"--username")==0){
210                        i++;
211                        if (i<argc){
212                                username=argv[i];
213                        }else print_usage();
214                }else if (strcmp(argv[i],"--password")==0){
215                        i++;
216                        if (i<argc){
217                                passwd=argv[i];
218                        }else print_usage();
219                }else print_usage();
220        }
221        if (username==NULL) {
222                fprintf(stderr,"Missing --username\n");
223                print_usage();
224        }
225        if (host==NULL) {
226                fprintf(stderr,"Missing --host\n");
227                print_usage();
228        }
229        if (passwd) snprintf(cmd,sizeof(cmd),"register sip:%s@%s sip:%s %s",username,host,host,passwd);
230        else snprintf(cmd,sizeof(cmd),"register sip:%s@%s sip:%s",username,host,host);
231        return send_generic_command(cmd,TRUE);
232}
233
234static int unregister_execute(int argc, char *argv[]){
235        return send_generic_command("unregister",FALSE);
236}
237
238
239static int dial_execute(int argc, char *argv[]){
240        char cmd[512];
241        if (argc==1){
242                snprintf(cmd,sizeof(cmd),"call %s",argv[0]);
243                return send_generic_command(cmd,TRUE);
244        }else{
245                print_usage();
246        }
247        return -1;
248}
249
250static int status_execute(int argc, char *argv[]){
251        char cmd[512];
252        char reply[DEFAULT_REPLY_SIZE];
253        int err;
254       
255        if (argc==1){
256                snprintf(cmd,sizeof(cmd),"status %s",argv[0]);
257                err=send_command(cmd,DEFAULT_TCP_PORT,reply,sizeof(reply),TRUE);
258                if (err==0) {
259                        printf("%s",reply);
260                        err=make_status_value(reply);
261                }
262                return err;
263        }else{
264                print_usage();
265        }
266        return -1;
267}
268
269int main(int argc, char *argv[]){
270        int argi;
271        if (argc<2){
272                print_usage();
273                return -1;
274        }
275        ortp_init();
276        for(argi=1;argi<argc;++argi){
277                if (strcmp(argv[argi],"--tcp")==0){
278                        tcp=1;
279                }else if (strcmp(argv[argi],"init")==0){
280                        /*check if there is running instance*/
281                        if (send_generic_command("help",0)==0){
282                                fprintf(stderr,"A running linphonec has been found, not spawning a second one.\n");
283                        }
284                        spawn_linphonec(argc-argi-1,&argv[argi+1]);
285                        if (tcp) fprintf(stderr,"WARNING: using --tcp is unsafe: unprivilegied users can make calls.\n");
286                        return 0;
287                }else if (strcmp(argv[argi],"generic")==0){
288                        if (argi+1<argc){
289                                return send_generic_command(argv[argi+1],1);
290                        }else print_usage();
291                }else if (strcmp(argv[argi],"register")==0){
292                        return register_execute(argc-argi-1,&argv[argi+1]);
293                }else if (strcmp(argv[argi],"unregister")==0){
294                        return unregister_execute(argc-argi-1,&argv[argi+1]);
295                }else if (strcmp(argv[argi],"dial")==0){
296                        return dial_execute(argc-argi-1,&argv[argi+1]);
297                }else if (strcmp(argv[argi],"hangup")==0){
298                        send_generic_command("terminate",FALSE);
299                        send_generic_command("duration",TRUE);
300                }else if (strcmp(argv[argi],"status")==0){
301                        return status_execute(argc-argi-1,&argv[argi+1]);
302                }else if (strcmp(argv[argi],"exit")==0){
303                        return send_generic_command("quit",TRUE);
304                }else print_usage();
305        }
306        return 0;
307}
Note: See TracBrowser for help on using the repository browser.