mirror of
				https://github.com/RangeNetworks/openbts.git
				synced 2025-10-30 19:33:33 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			404 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			404 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /*
 | |
| * Copyright 2011, 2012, 2014 Range Networks, Inc.
 | |
| *
 | |
| * This software is distributed under the terms of the GNU Affero Public License.
 | |
| * See the COPYING file in the main directory for details.
 | |
| *
 | |
| * This use of this software may be subject to additional restrictions.
 | |
| * See the LEGAL file in the main directory for details.
 | |
| 
 | |
| 	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 Affero General Public License for more details.
 | |
| 
 | |
| 	You should have received a copy of the GNU Affero General Public License
 | |
| 	along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | |
| 
 | |
| */
 | |
| 
 | |
| 
 | |
| // KEEP THIS FILE CLEAN FOR GPL PUBLIC RELEASE.
 | |
| 
 | |
| #include <config.h>
 | |
| #include <sys/types.h>
 | |
| #include <sys/stat.h>
 | |
| #include <unistd.h>
 | |
| #include <sys/socket.h>
 | |
| #include <sys/un.h>
 | |
| #include <stdio.h>
 | |
| #include <stdlib.h>
 | |
| #include <limits.h>
 | |
| #include <time.h>
 | |
| #include <errno.h>
 | |
| #include <arpa/inet.h>
 | |
| #include <stdarg.h>
 | |
| #include <string>
 | |
| #include <cstring>
 | |
| 
 | |
| #define HAVE_LIBREADLINE
 | |
| 
 | |
| 
 | |
| #ifdef HAVE_LIBREADLINE
 | |
| #  include <readline/readline.h>
 | |
| #  include <readline/history.h>
 | |
| #endif
 | |
| 
 | |
| // Note that we ONLY use this for the name of the file to use.
 | |
| 
 | |
| // The assumption is that OpenBTS and OpenBTSCLI were built together.
 | |
| #include "Globals.h"
 | |
| 
 | |
| struct sockaddr_in sa;
 | |
| static char *progname = (char*) "";
 | |
| 
 | |
| 
 | |
| char target[64] = "127.0.0.1";
 | |
| int port = 49300;
 | |
| 
 | |
| static void banner()
 | |
| {
 | |
| 	static int bannerPrinted = false;
 | |
| 	if (bannerPrinted) return;
 | |
| 	bannerPrinted = true;
 | |
| 	printf("OpenBTS Command Line Interface (CLI) utility\n");
 | |
| 	printf("Copyright 2012, 2013, 2014 Range Networks, Inc.\n");
 | |
| 	printf("Licensed under GPLv2.\n");
 | |
| #ifdef HAVE_LIBREADLINE
 | |
| 	printf("Includes libreadline, GPLv2.\n");
 | |
| #endif
 | |
| }
 | |
| 
 | |
| static void oops(const char *fmt, ...)
 | |
| {
 | |
| 	banner();
 | |
| 	va_list ap;
 | |
| 	va_start(ap,fmt);
 | |
| 	vprintf(fmt,ap);
 | |
| 	va_end(ap);
 | |
| 	printf(" OpenBTSCLI options:\n"
 | |
| 		"  -t ip_address : specify IP address of target machine on which OpenBTS is running\n"
 | |
| 		"  -p port_number : specify OpenBTS port number\n"
 | |
| 		"  -c command .. : execute this OpenBTS command and exit; also suppresses extraneous banners\n"
 | |
| 		"  -d : read one OpenBTS command, execute it and exit\n"
 | |
| 		"If -d or -c not specified, read OpenBTS commands and execute them.\n"
 | |
| 		"To see OpenBTS help, type the 'help' command to OpenBTS, or for example: OpenBTSCLI -c help\n"
 | |
| 		);
 | |
| 	exit(1);
 | |
| }
 | |
| 
 | |
| bool doCmd(int fd, char *cmd) // return false to abort/exit
 | |
| {
 | |
| 	const int bufsz = 100000;
 | |
| 	char resbuf[bufsz];
 | |
| 	int nread = 0;
 | |
| 
 | |
| 	int len = strlen(cmd);
 | |
| 	int svlen = len;
 | |
| 	len = htonl(len);
 | |
| 	if (send(fd, &len, sizeof(len), 0) < 0) {
 | |
| 		perror("sending stream");
 | |
| 		return false;
 | |
| 	}
 | |
| 	len = svlen;
 | |
| 	if (send(fd, cmd, strlen(cmd), 0) < 0) {
 | |
| 		perror("sending stream");
 | |
| 		return false;
 | |
| 	}
 | |
| 	nread = recv(fd, &len, sizeof(len), 0);
 | |
| 	if (nread < 0) {
 | |
| 		perror("receiving stream");
 | |
| 		return false;
 | |
| 	}
 | |
| 	if (nread == 0) {
 | |
| 		printf("Remote connection closed\n");
 | |
| 		exit(1);
 | |
| 	}
 | |
| 	if (nread != (int) sizeof(len)) {
 | |
| 		printf("Partial read of length from server, expected %d, got %d\n", sizeof(len), len);
 | |
| 		exit(1);
 | |
| 	}
 | |
| 	len = ntohl(len);
 | |
| 	if (len >= bufsz-1) {
 | |
| 		printf("Response of %d bytes is too long\n", len);
 | |
| 		exit(1);
 | |
| 	}
 | |
| 	int off = 0;
 | |
| 	svlen = len;
 | |
| 	while(len != 0) {
 | |
| 		nread = recv(fd,&resbuf[off],len,0);
 | |
| 		if (nread < 0) {
 | |
| 			perror("receiving stream");
 | |
| 			return false;
 | |
| 		}
 | |
| 		if (nread == 0) {
 | |
| 			printf("Remote connection closed\n");
 | |
| 			exit(1);
 | |
| 		}
 | |
| 		off += nread;
 | |
| 		len -= nread;
 | |
| 	}
 | |
| 	nread = svlen;
 | |
| 
 | |
| 	if (nread<0) {
 | |
| 		perror("receiving response");
 | |
| 		return false;
 | |
| 	}
 | |
| 	resbuf[nread] = '\0';
 | |
|     if (strcmp("restart", cmd) == 0)
 | |
|     {
 | |
|         printf("OpenBTS has been shut down or restarted.\n");
 | |
|         printf("You will need to restart OpenBTSCLI after it restarts.\n");
 | |
|         return false;
 | |
|     }
 | |
|     if (strcmp("shutdown", cmd) == 0)
 | |
|     {
 | |
|         printf("OpenBTS has been shut down or restarted.\n");
 | |
|         printf("You will need to restart OpenBTSCLI after it restarts.\n");
 | |
|         return false;
 | |
|     }
 | |
|     printf("%s\n",resbuf);
 | |
|     if (nread==(bufsz-1)) {
 | |
|         printf("(response truncated at %d characters)\n",nread);
 | |
|     }
 | |
| 	return true;
 | |
| }
 | |
| 
 | |
| int main(int argc, char *argv[])
 | |
| {
 | |
| 	bool isBTSDo = false;	// If set, execute one command without prompting, then exit.
 | |
| 	std::string sCommand("");
 | |
| 	progname = argv[0];
 | |
| 	argc--; argv++;			// Skip program name.
 | |
| 	while(argc > 0) {
 | |
| 		if (argv[0][0] == '-') {
 | |
| 			if (strlen(argv[0]) > 2) {
 | |
| 				oops("Invalid option '%s'\n", argv[0]);
 | |
| 				exit(1);
 | |
| 			}
 | |
| 			switch(argv[0][1]) {
 | |
| 				case 'd': // OpenBTSDo interface
 | |
| 					isBTSDo = true;
 | |
| 					break;
 | |
| 				case 'c': // Run command on command line then exit.
 | |
| 					isBTSDo = true;
 | |
| 					if (argc == 1) {
 | |
| 						oops("Missing argument to -c\n");
 | |
| 					}
 | |
| 					{
 | |
| 						// Gather up the command line.
 | |
| 						for (int j = 1; j < argc; j++) {
 | |
| 							sCommand += argv[j];
 | |
| 							sCommand += " ";
 | |
| 						}
 | |
| 					}
 | |
| 					argc = 1;	// terminates while loop.
 | |
| 					break;
 | |
| 				case 'p': // TCP Port number
 | |
| 					argc--, argv++;
 | |
| 					port = atoi(argv[0]);
 | |
| 					printf("TCP %d\n", port);
 | |
| 					break;
 | |
| 				case 't': // target
 | |
| 					argc--, argv++;
 | |
| 					snprintf(target, sizeof(target)-1, "%s", argv[0]);
 | |
| 					break;
 | |
| 				default:
 | |
| 					oops("Invalid option '%s'\n", argv[0]);
 | |
| 					exit(1);	// NOTREACHED but makes the compiler happy.
 | |
| 			}
 | |
| 			argc--;
 | |
| 			argv++;
 | |
| 		} else {
 | |
| 			oops("Invalid argument '%s'\n", argv[0]);
 | |
| 			exit(1);	// NOTREACHED but makes the compiler happy.
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	if (sCommand.c_str()[0] == '\0') {
 | |
| 		banner();
 | |
| 		printf("Connecting to %s:%d...\n", target, port);
 | |
| 	}
 | |
| 
 | |
| 	int sock = -1;
 | |
| 	char prompt[16] = "OpenBTS> ";
 | |
| 
 | |
| 	// Define this stuff "globally" as it's needed in various places
 | |
| 	memset(&sa, 0, sizeof(sa));
 | |
| 
 | |
| 	// the socket
 | |
| 	sock = socket(AF_INET,SOCK_STREAM,0);
 | |
| 	if (sock<0) {
 | |
| 		perror("opening stream socket");
 | |
| 		exit(1);
 | |
| 	}
 | |
| 
 | |
| 	// destination address
 | |
| 	sa.sin_family = AF_INET;
 | |
| 	sa.sin_port = htons(port);
 | |
| 	if (inet_pton(AF_INET, target, &sa.sin_addr) <= 0) {
 | |
| 		oops("unable to convert target to an IP address\n");
 | |
| 	}
 | |
| 
 | |
| 	if (0) {
 | |
| 		// (pat) I used this code for testing.
 | |
| 		// If you wanted to specify the port you were binding from, this is how you would do it...
 | |
| 		// We dont use this code - we let the connect system call pick the port.
 | |
| 		struct sockaddr_in sockAddrBuf;
 | |
| 		memset(&sockAddrBuf,0,sizeof(sockAddrBuf));		// overkill.
 | |
| 		sockAddrBuf.sin_family = AF_INET;
 | |
| 		sockAddrBuf.sin_addr.s_addr = INADDR_ANY;
 | |
| 		sockAddrBuf.sin_port = htons(13011);
 | |
| 		if (bind(sock, (struct sockaddr *) &sockAddrBuf, sizeof(struct sockaddr_in))) {	// Bind the socket to our assigned port.
 | |
| 			printf("bind call failed: %s",strerror(errno));
 | |
| 			exit(2);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	if (connect(sock, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
 | |
| 		perror("connect stream socket");
 | |
| 		fprintf(stderr, "Is OpenBTS running?\n");
 | |
| 		exit(1);
 | |
| 	}
 | |
| 
 | |
| #ifdef HAVE_LIBREADLINE
 | |
| 	char *history_name = 0;
 | |
| 	if (!isBTSDo)
 | |
| 	{
 | |
| 	    // start console
 | |
| 	    using_history();
 | |
| 
 | |
| 	    static const char * const history_file_name = "/.openbts_history";
 | |
| 	    char *home_dir = getenv("HOME");
 | |
| 
 | |
| 	    if(home_dir) {
 | |
| 		    size_t home_dir_len = strlen(home_dir);
 | |
| 		    size_t history_file_len = strlen(history_file_name);
 | |
| 		    size_t history_len = home_dir_len + history_file_len + 1;
 | |
| 		    if(history_len > home_dir_len) {
 | |
| 			    if(!(history_name = (char *)malloc(history_len))) {
 | |
| 				    perror("malloc failed");
 | |
| 				    exit(2);
 | |
| 			    }
 | |
| 			    memcpy(history_name, home_dir, home_dir_len);
 | |
| 			    memcpy(history_name + home_dir_len, history_file_name,
 | |
| 			       history_file_len + 1);
 | |
| 			    read_history(history_name);
 | |
| 		    }
 | |
| 	    }
 | |
| 	}
 | |
| #endif
 | |
| 
 | |
| 
 | |
| 	if (!isBTSDo)
 | |
| 	    printf("Remote Interface Ready.\nType:\n \"help\" to see commands,\n \"version\" for version information,\n \"notices\" for licensing information,\n \"quit\" to exit console interface.\n");
 | |
| 
 | |
| 
 | |
|         if (sCommand.c_str()[0] != '\0') {
 | |
|                 doCmd(sock, (char *)sCommand.c_str());
 | |
|         } else
 | |
|             while (1)
 | |
|             {
 | |
| #ifdef HAVE_LIBREADLINE
 | |
|                 char *cmd = readline(isBTSDo ? NULL : prompt);
 | |
|                 if (!cmd) continue;
 | |
|                         if (cmd[0] == '\0') continue;
 | |
|                 if (!isBTSDo)
 | |
|                     if (*cmd) add_history(cmd);
 | |
| #else // HAVE_LIBREADLINE
 | |
|                 if (!isBTSDo)
 | |
|                 {
 | |
|                     printf("%s",prompt);
 | |
|                     fflush(stdout);
 | |
|                 }
 | |
|                 char *inbuf = (char*)malloc(BUFSIZ);
 | |
|                 char *cmd = fgets(inbuf,BUFSIZ-1,stdin);
 | |
|                 if (!cmd)
 | |
|                 {
 | |
|                     if (isBTSDo)
 | |
|                         break;
 | |
|                     continue;
 | |
|                 }
 | |
|                         if (cmd[0] == '\0') continue;
 | |
|                 // strip trailing CR
 | |
|                 cmd[strlen(cmd)-1] = '\0';
 | |
| #endif
 | |
|                 if (!isBTSDo)
 | |
|                 {
 | |
|                     // local quit?
 | |
|                     if (strcmp(cmd,"quit")==0) {
 | |
|                         printf("closing remote console\n");
 | |
|                         break;
 | |
|                     }
 | |
|                             // shutdown via upstart
 | |
|                     if (strcmp(cmd,"shutdown")==0) {
 | |
|                         printf("terminating openbts\n");
 | |
|                         if (getuid() == 0)
 | |
|                             system("stop openbts");
 | |
|                         else
 | |
|                         {
 | |
|                             printf("If prompted, enter the password you use for sudo\n");
 | |
|                             system("sudo stop openbts");
 | |
|                         }
 | |
|                         break;
 | |
|                     }
 | |
|                     // shell escape?
 | |
|                     if (cmd[0]=='!') {
 | |
|                         int i = system(cmd+1);
 | |
|                         if (i < 0)
 | |
|                         {
 | |
|                             perror("system");
 | |
|                         }
 | |
|                         continue;
 | |
|                     }
 | |
|                 }
 | |
|                 char *pCmd = cmd;
 | |
|                 while(isspace(*pCmd)) pCmd++; // skip leading whitespace
 | |
|                 if (*pCmd)
 | |
|                 {
 | |
|                     if (doCmd(sock, cmd) == false)
 | |
|                     {
 | |
|                         bool sd = false;
 | |
|                         if (strcmp(cmd,"shutdown")==0)
 | |
|                             sd = true;
 | |
|                         else if (strcmp(cmd,"restart")==0)
 | |
|                             sd = true;
 | |
|                         free(cmd);
 | |
|                         //{
 | |
|                             if (isBTSDo)
 | |
|                                 break;
 | |
|                             if (sd)
 | |
|                                 break;
 | |
|                             continue;
 | |
|                         //}
 | |
|                     }
 | |
|                 }
 | |
|                 free(cmd);
 | |
|                 if (isBTSDo)
 | |
|                     break;
 | |
|             }
 | |
| 
 | |
| #ifdef HAVE_LIBREADLINE
 | |
| 	if (!isBTSDo)
 | |
| 	{
 | |
| 	    if(history_name)
 | |
| 	    {
 | |
| 		    int e = write_history(history_name);
 | |
| 		    if(e) {
 | |
| 			    fprintf(stderr, "error: history: %s\n", strerror(e));
 | |
| 		    }
 | |
| 		    free(history_name);
 | |
| 		    history_name = 0;
 | |
| 	    }
 | |
| 	}
 | |
| #endif
 | |
| 
 | |
| 
 | |
| 	close(sock);
 | |
| }
 |