genericunixprotocols/telnetsrv/src/telnetd.cpp
changeset 0 c6b0df440bee
equal deleted inserted replaced
-1:000000000000 0:c6b0df440bee
       
     1 /*
       
     2 * Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies). 
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description: 
       
    15 *
       
    16 */
       
    17 
       
    18 //  Include Files
       
    19 
       
    20 #include <stdlib.h>
       
    21 #include <stdio.h>
       
    22 #include <string.h>
       
    23 #include <math.h>
       
    24 #include <sys/select.h>
       
    25 #include <unistd.h>
       
    26 #include <sys/wait.h>
       
    27 #include <arpa/telnet.h>
       
    28 
       
    29 //For connect
       
    30 #include <sys/socket.h>
       
    31 #include <netinet/in.h>
       
    32 
       
    33 //For posix_spawn
       
    34 #include <spawn.h>
       
    35 
       
    36 //for pipe
       
    37 #include <fcntl.h>
       
    38 #include <sys/stat.h>
       
    39 #include <sys/param.h>
       
    40 
       
    41 //Symbian headers
       
    42 #include <e32std.h>
       
    43 #include <es_sock.h>
       
    44 #include <f32file.h>
       
    45 
       
    46 void add_return(char* source, char* dest);
       
    47 int startConnection();
       
    48 TDriveNumber getSystemDrive();
       
    49 
       
    50 int main(int argc, char *argv[], char **envp)
       
    51 	{
       
    52 
       
    53 	int net;
       
    54 	int fds[3];
       
    55 	int pid;
       
    56 	int ctl_sock;
       
    57 	int on = 1;
       
    58 	int replicate = 0;
       
    59 	int ch = 1;
       
    60 
       
    61 	char ayt_response[]={IAC,NOP};
       
    62 
       
    63 	socklen_t addrlen;
       
    64 
       
    65 	int port = 23;
       
    66 
       
    67 	sockaddr_in server_addr;
       
    68 	sockaddr_in his_addr;
       
    69 
       
    70 	const char *argstr = "RDP:";
       
    71 
       
    72 	while ((ch = getopt(argc, argv, argstr)) != -1) {
       
    73 		switch (ch) {
       
    74 
       
    75 		case 'D':
       
    76 
       
    77 			for(int i=1 /*no name*/; i<argc; i++)
       
    78 				{
       
    79 				for(unsigned int j=0;j<strlen(argv[i]); j++)
       
    80 					if(argv[i][j]=='D')
       
    81 						{
       
    82 						//Daemon token found, change it to allow replication to new background processes
       
    83 						argv[i][j]='R';
       
    84 						}
       
    85 				}
       
    86 			posix_spawn(NULL,argv[0],NULL,NULL,argv,envp);
       
    87 			exit(0);
       
    88 			break;
       
    89 
       
    90 		case 'R':
       
    91 			replicate = 1;
       
    92 			break;
       
    93 
       
    94 		case 'P':
       
    95 			port = atoi(optarg);
       
    96 			break;
       
    97 
       
    98 		default:
       
    99 			printf("unknown flag -%c ignored", optopt);
       
   100 			scanf("");
       
   101 			break;
       
   102 		}
       
   103 	}
       
   104 
       
   105 	if(startConnection() != KErrNone)
       
   106 		{
       
   107 		exit(1);
       
   108 		}
       
   109 
       
   110 	ctl_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
       
   111 
       
   112 	if (ctl_sock < 0)
       
   113 		{
       
   114 		exit(1);
       
   115 		}
       
   116 
       
   117 	if (setsockopt(ctl_sock, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) < 0)
       
   118 		{
       
   119 		exit(1);
       
   120 		}
       
   121 
       
   122 
       
   123 	server_addr.sin_family = AF_INET;
       
   124 	server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
       
   125 	server_addr.sin_port = htons(port);
       
   126 
       
   127 	if (bind(ctl_sock, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0)
       
   128 		{
       
   129 		exit(1);
       
   130 		}
       
   131 
       
   132 	if (listen(ctl_sock, 32) < 0)
       
   133 		{
       
   134 		exit(1);
       
   135 		}
       
   136 
       
   137 	addrlen = sizeof(his_addr);
       
   138 
       
   139 	net = accept(ctl_sock, (struct sockaddr *)&his_addr, &addrlen);
       
   140 
       
   141 	if(net<0)
       
   142 		{
       
   143 		exit(1);
       
   144 		}
       
   145 
       
   146 	close(ctl_sock);
       
   147 
       
   148 	//replicate server
       
   149 	if(replicate)
       
   150 		posix_spawn(NULL,argv[0],NULL,NULL,argv,envp);
       
   151 
       
   152 	//launch shell and redirect the commands...
       
   153 	pid=popen3("zsh.exe", NULL, NULL, fds);
       
   154 
       
   155 
       
   156 	if(pid>0)
       
   157 		{
       
   158 
       
   159 		char read_zsh[256];
       
   160 		char read_zsh_crlf[512];
       
   161 		int sock_cnt=0, zsh_cnt=0, ret;
       
   162 		int max=0;
       
   163 	    fd_set read_fds;
       
   164 
       
   165 	    //create fifo pipe
       
   166 		char pipeName[MAXPATHLEN];
       
   167 		sprintf(pipeName,"%c:\\telnetd_%d_pipe",getSystemDrive()+'A',getpid());
       
   168 
       
   169 		if (mkfifo(pipeName, S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH) < 0)
       
   170 			{
       
   171 			exit(1);
       
   172 			}
       
   173 
       
   174 		int pipe = open(pipeName, O_RDONLY | O_NONBLOCK);
       
   175 
       
   176 
       
   177 	    max =  fds[1] > fds[2] ? fds[1] : fds[2];
       
   178 		max =  max > net ? max : net;
       
   179 		max =  max > pipe ? max : pipe;
       
   180 
       
   181 		char exportVariable[MAXPATHLEN];
       
   182 		sprintf(exportVariable,"PIPE='%s'\n",pipeName);
       
   183 
       
   184 		//read first prompt and write PIPE variable
       
   185 		read(fds[1], read_zsh, 11); //"localhost# "
       
   186 		write(fds[0], exportVariable, strlen(exportVariable));
       
   187 
       
   188 		for(;;)
       
   189 			{
       
   190 			int status=-1;
       
   191 
       
   192 			FD_ZERO(&read_fds);
       
   193 			FD_SET(net, &read_fds);
       
   194 			FD_SET(fds[1], &read_fds);
       
   195 			FD_SET(fds[2], &read_fds);
       
   196 			FD_SET(pipe, &read_fds);
       
   197 
       
   198 			//is child terminated...
       
   199 
       
   200 			//Fix for defect to prevent the process from taking too much of the processor
       
   201 			sleep(1);
       
   202 
       
   203 			int wait_pid=waitpid(pid, &status, WNOHANG);
       
   204 			if(pid == wait_pid || wait_pid == -1) //dont wait for the child to terminate
       
   205 				{
       
   206 				break;
       
   207 				}
       
   208 
       
   209 			//is any of the fds ready for read...
       
   210 			ret=select(max+1, &read_fds, NULL, NULL, NULL);
       
   211 
       
   212 			if(ret==-1)
       
   213 				{
       
   214 				break;
       
   215 				}
       
   216 
       
   217    		    //is there any data to be written onto socket..
       
   218 			if(FD_ISSET(fds[1], &read_fds))
       
   219 				{
       
   220 				memset(&read_zsh[0], 0, 256);
       
   221 
       
   222 				zsh_cnt=read(fds[1], read_zsh, 255);
       
   223 				if(zsh_cnt>0)
       
   224 					{
       
   225 					//reading from the socket can have more than one \n
       
   226 					//so replace all \n with \r\n.
       
   227 					add_return(read_zsh,read_zsh_crlf);
       
   228 					write(net, read_zsh_crlf, strlen(read_zsh_crlf));
       
   229 					}
       
   230 				}
       
   231 
       
   232    		    //is there any data to be written onto socket..
       
   233 			if (FD_ISSET(fds[2], &read_fds))
       
   234 				{
       
   235 				memset(&read_zsh[0], 0, 256);
       
   236 
       
   237 				zsh_cnt=read(fds[2], read_zsh, 255);
       
   238 				if(zsh_cnt>0)
       
   239 					{
       
   240 					//reading from the socket can have more than one \n
       
   241 					//so replace all \n with \r\n.
       
   242 					add_return(read_zsh,read_zsh_crlf);
       
   243 					write(net, read_zsh_crlf, strlen(read_zsh_crlf));
       
   244 					}
       
   245 				}
       
   246 
       
   247 
       
   248 			//is there any data to be written on to pipe
       
   249 			if(FD_ISSET(net, &read_fds))
       
   250 				{
       
   251 				//char* ptr=0;
       
   252 				char temp,temp2;
       
   253 
       
   254 				sock_cnt=0;
       
   255 
       
   256 				sock_cnt=read(net, &temp, 1);
       
   257 				if(sock_cnt > 0)
       
   258 					{
       
   259 					//echo the command..
       
   260 					//write(net, &temp, 1);
       
   261 
       
   262 					switch(temp & 0xFF)
       
   263 						{
       
   264 						case '\r':
       
   265 								sock_cnt=read(net, &temp, 1); //expect \n here...
       
   266 								//write(net, &temp, 1);
       
   267 								if(sock_cnt && !(write(fds[0], &temp, 1) > 0))
       
   268 									printf("1 telnetd: zsh is not waiting for data.\n");
       
   269 								break;
       
   270 
       
   271 						case IAC: //telnet command
       
   272 							{
       
   273 								read(net, &temp2, 1);
       
   274 								switch(temp2 & 0xFF)
       
   275 									{
       
   276 									case AYT:
       
   277 										write(net,&ayt_response,2);
       
   278 										break;
       
   279 									}
       
   280 								break;
       
   281 							}
       
   282 
       
   283 						default:
       
   284 							if(!(write(fds[0], &temp, 1) > 0))
       
   285 								printf("2 telnetd: zsh is not waiting for data.\n");
       
   286 						}
       
   287 
       
   288 					}
       
   289    		    	}
       
   290 
       
   291 
       
   292 			if(FD_ISSET(pipe, &read_fds))
       
   293 				{
       
   294 				memset(&read_zsh[0], 0, 256);
       
   295 				zsh_cnt=read(pipe, read_zsh, 255);
       
   296 
       
   297 				if(zsh_cnt>0)
       
   298 					{
       
   299 					write(net, read_zsh, strlen(read_zsh));
       
   300 					}
       
   301 				}
       
   302 
       
   303 
       
   304 			}
       
   305 
       
   306 		close(net);
       
   307 		close(fds[0]);
       
   308 		close(fds[1]);
       
   309 		close(fds[2]);
       
   310 		close(pipe);
       
   311 
       
   312 		//delete pipe file
       
   313 		unlink(pipeName);
       
   314 
       
   315 		exit(0);//exit server here...
       
   316 
       
   317 
       
   318 
       
   319 		}
       
   320 	else
       
   321 		{
       
   322 
       
   323 		char errorMessage[]="\n\rShell (zsh.exe) not launched\n\r";
       
   324 
       
   325 		write(net, errorMessage, strlen(errorMessage));
       
   326 		sleep(5);
       
   327 		exit(-1); //exit here
       
   328 		}
       
   329 
       
   330 	}
       
   331 
       
   332 
       
   333 void add_return(char* source, char* dest)
       
   334 	{
       
   335 
       
   336 	int sourceLen = strlen(source);
       
   337 	int destIndex = 0;
       
   338 	int sourceIndex = 0;
       
   339 
       
   340 	for(; sourceIndex<sourceLen; sourceIndex++, destIndex++)
       
   341 		{
       
   342 		if(source[sourceIndex]=='\n')
       
   343 			{
       
   344 			dest[destIndex]='\r';
       
   345 			destIndex++;
       
   346 			}
       
   347 		dest[destIndex] = source[sourceIndex];
       
   348 		}
       
   349 
       
   350 	dest[destIndex] = '\0';
       
   351 
       
   352 	}
       
   353 
       
   354 
       
   355 int startConnection()
       
   356 	{
       
   357 
       
   358 	int error;
       
   359 
       
   360 	RSocketServ rSockServer;
       
   361 
       
   362 	error = rSockServer.Connect();
       
   363 
       
   364 	if(error == KErrNone)
       
   365     {
       
   366     RConnection rConnect;
       
   367     error = rConnect.Open(rSockServer);
       
   368     if(error == KErrNone)
       
   369         {
       
   370         TRequestStatus status;
       
   371         rConnect.Start(status);
       
   372         User::WaitForRequest(status);
       
   373         }
       
   374     rConnect.Close();
       
   375     }
       
   376 
       
   377 	rSockServer.Close();
       
   378 
       
   379 	return error;
       
   380 
       
   381 	}
       
   382 
       
   383 
       
   384 TDriveNumber getSystemDrive()
       
   385 	{
       
   386 	_LIT(KFileSrvDll, "efsrv.dll");
       
   387 
       
   388 	TDriveNumber defaultSysDrive(EDriveC);
       
   389 	RLibrary pluginLibrary;
       
   390 	TInt pluginErr = pluginLibrary.Load(KFileSrvDll);
       
   391 
       
   392 	if (pluginErr == KErrNone)
       
   393 		{
       
   394 		typedef TDriveNumber(*fun1)();
       
   395 		fun1 sysdrive;
       
   396 
       
   397 	#ifdef __EABI__
       
   398 		sysdrive = (fun1)pluginLibrary.Lookup(336);
       
   399 	#else
       
   400 		sysdrive = (fun1)pluginLibrary.Lookup(304);
       
   401 	#endif
       
   402 
       
   403 		if(sysdrive!=NULL)
       
   404 			{
       
   405 			defaultSysDrive = sysdrive();
       
   406 			}
       
   407 		}
       
   408 	pluginLibrary.Close();
       
   409 	return defaultSysDrive;
       
   410 	}
       
   411 
       
   412 
       
   413