📄 telnetdlib.c
字号:
* The <pParserCtrlRtn> argument provides a routine using the following* interface:* .CS* STATUS parserControlRtn* (* int telnetdEvent,/@ start or stop a telnet session @/* UINT32 sessionId,/@ a unique session identifier @/* int ioFd /@ file descriptor for character i/o @/* )* .CE** The telnet server calls the control routine with a <telnetdEvent>* parameter of REMOTE_INIT during inititialization. The telnet server then* calls the control routine with a <telnetdEvent> parameter of REMOTE_START * when a client establishes a new connection.* The <sessionId> parameter provides a unique identifier for the session.* * In the default configuration, the telnet server calls the control routine* with a <telnetdEvent> parameter of REMOTE_STOP when a session ends. ** The telnet server does not call the control routine when a session ends* if it is configured to spawn all tasks and allocate all resources in* advance of any connections. The associated file descriptors will be reused* by later clients and cannot be released. In that case, the REMOTE_STOP* operation only occurs to allow the command interpreter to close those* files when the server encounters a fatal error.** VXWORKS AE PROTECTION DOMAINS* Under VxWorks AE, you can call this function from within the kernel * protection domain only. In addition, all arguments to this function can * reference only that data which is valid in the kernel protection domain. * This restriction does not apply under non-AE versions of VxWorks. ** RETURNS: OK if parser control routine installed, or ERROR otherwise.** INTERNAL: Can be called before or after telnetdInit() and telnetdStart()*/STATUS telnetdParserSet ( FUNCPTR pParserCtrlRtn /* provides parser's file descriptors */ ) { /* We must have a valid parser */ if (pParserCtrlRtn == NULL) return (ERROR); /* We can not change parsers */ if (telnetdParserControl != NULL) return (ERROR); /* Store the provided control routine. */ telnetdParserControl = pParserCtrlRtn; /* Allow client connections. */ telnetdParserFlag = TRUE; return (OK); }/********************************************************************************* telnetdIoTasksCreate - Create tasks to transferring i/o between socket and fd* * Two tasks are created: An input task and an output task. The name is based on* the pSlot argument for uniqueness.** NOMANUAL* * RETURNS: OK if parser control routine installed, or ERROR otherwise.*/LOCAL STATUS telnetdIoTasksCreate ( TELNETD_SESSION_DATA *pSlot ) { char sessionTaskName[IO_TASK_NAME_MAX_LEN]; char sessionInTaskName[IO_TASK_NAME_MAX_LEN]; char sessionOutTaskName[IO_TASK_NAME_MAX_LEN]; int result; /* * Spawn the input and output tasks which transfer data between * the socket and the i/o file descriptor. * * If created in advance (static) the task pend on a semaphore */ sprintf (sessionTaskName, "_%x", (unsigned int)pSlot); sprintf (sessionInTaskName, "tTelnetIn%s", sessionTaskName); sprintf (sessionOutTaskName,"tTelnetOut%s", sessionTaskName); if (telnetdTaskFlag) { pSlot->startOutput = semBCreate (SEM_Q_FIFO, SEM_EMPTY); pSlot->startInput = semBCreate (SEM_Q_FIFO, SEM_EMPTY); if ((pSlot->startInput == NULL) || (pSlot->startInput == NULL)) { TELNETD_DEBUG ("telnetd: Unable to create semaphore. errno:%#x\n", errno, 0, 0, 0, 0, 0); result = ERROR; return ERROR; } } pSlot->outputTask = taskSpawn (sessionOutTaskName, telnetTaskPriority, telnetTaskOptions, telnetTaskStackSize, (FUNCPTR)telnetOutTask, (int)pSlot, 0, 0, 0, 0, 0, 0, 0, 0, 0); if (pSlot->outputTask == ERROR) { TELNETD_DEBUG ("telnetd: Unable to create task. errno:%#x\n", errno, 0, 0, 0, 0, 0); result = ERROR; return ERROR; } pSlot->inputTask = taskSpawn (sessionInTaskName, telnetTaskPriority, telnetTaskOptions, telnetTaskStackSize, (FUNCPTR)telnetInTask, (int)pSlot, 0, 0, 0, 0, 0, 0, 0, 0, 0); if (pSlot->inputTask == ERROR) { TELNETD_DEBUG ("telnetd: Unable to create task. errno:%#x\n", errno, 0, 0, 0, 0, 0); taskDelete (pSlot->outputTask); result = ERROR; return ERROR; } return OK; }/********************************************************************************* telnetdSessionPtysCreate - Create a pty pair and open them * * Two file descriptors are created: An input and an output fd. The name is * based on the pSlot argument for uniqueness. The file descriptors are * stored in the session structure.** NOMANUAL* * RETURNS: OK if successfull, or ERROR otherwise.*/LOCAL STATUS telnetdSessionPtysCreate ( TELNETD_SESSION_DATA *pSlot ) { char sessionPtyRemoteName[PTY_DEVICE_NAME_MAX_LEN]; char sessionPtyRemoteNameM[PTY_DEVICE_NAME_MAX_LEN]; char sessionPtyRemoteNameS[PTY_DEVICE_NAME_MAX_LEN]; /* Create unique names for the pty device */ sprintf (sessionPtyRemoteName, "%s_%x.", ptyRemoteName, (int)pSlot); sprintf (sessionPtyRemoteNameM, "%sM", sessionPtyRemoteName); sprintf (sessionPtyRemoteNameS, "%sS", sessionPtyRemoteName); /* pseudo tty device creation */ if (ptyDevCreate (sessionPtyRemoteName, PTY_BUFFER_SIZE, PTY_BUFFER_SIZE) == ERROR) { return ERROR; } /* Master-side open of pseudo tty */ strcpy (pSlot->ptyRemoteName, sessionPtyRemoteName); if ((masterFd = open (sessionPtyRemoteNameM, O_RDWR, 0)) == ERROR) { return ERROR; } else { pSlot->inputFd = masterFd; pSlot->outputFd = masterFd; } /* Slave-side open of pseudo tty */ if ((pSlot->slaveFd = open (sessionPtyRemoteNameS, O_RDWR, 0)) == ERROR) { return ERROR; } /* setup the slave device to act like a terminal */ (void) ioctl (pSlot->slaveFd, FIOOPTIONS, OPT_TERMINAL); return OK; }/********************************************************************************* telnetdStart - initialize the telnet services** Following the telnet server initialization, this routine creates a socket* for accepting remote connections and spawns the primary telnet server task.* It executes automatically during system startup when the INCLUDE_TELNET* configuration macro is defined since a parser control routine is available.* The server will not accept connections otherwise.** By default, the server will spawn a pair of secondary input and output* tasks after each client connection. Changing the TELNETD_TASKFLAG setting* to TRUE causes this routine to create all of those tasks in advance of* any connection. In that case, it calls the current parser control routine* repeatedly to obtain file descriptors for each possible client based on* the <numClients> argument to the initialization routine. The server will* not start if the parser control routine returns ERROR.** The TELNETD_PORT constant provides the <port> argument, which assigns the* port where the server accepts connections. The default value is the standard* setting of 23. ** VXWORKS AE PROTECTION DOMAINS* Under VxWorks AE, you can call this function from within the kernel * protection domain only. This restriction does not apply under non-AE * versions of VxWorks. ** RETURNS: OK, or ERROR if startup fails*/STATUS telnetdStart ( int port /* target port for accepting connections */ ) { struct sockaddr_in serverAddr; if (!telnetdInitialized) { TELNETD_DEBUG ("telnetd: Must be initialized with telnetdInit() first.\n", 0, 0, 0, 0, 0, 0); return (ERROR); } if (telnetdStartFlag) return (OK); /* * At this point (for both static and dynamic task initialization) we * are ready to create the server socket. */ telnetdServerSock = socket (AF_INET, SOCK_STREAM, 0); if (telnetdServerSock < 0) return (ERROR); bzero ((char *)&serverAddr, sizeof (serverAddr)); serverAddr.sin_family = AF_INET; serverAddr.sin_port = htons (port); if (bind (telnetdServerSock, (struct sockaddr *) &serverAddr, sizeof (serverAddr)) < 0) { close (telnetdServerSock); if (telnetdTaskFlag) telnetdTaskDelete (telnetdMaxClients); return (ERROR); } if (listen (telnetdServerSock, 5) < 0) { close (telnetdServerSock); if (telnetdTaskFlag) telnetdTaskDelete (telnetdMaxClients); return (ERROR); } /* Create a telnet server task to receive connection requests. */ telnetdTaskId = taskSpawn ("tTelnetd", telnetTaskPriority, telnetTaskOptions, telnetTaskStackSize, (FUNCPTR)telnetd, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); if (telnetdTaskId == ERROR) { close (telnetdServerSock); if (telnetdTaskFlag) telnetdTaskDelete (telnetdMaxClients); return (ERROR); } return (OK); }/********************************************************************************* telnetdTaskDelete - remove task data from task list** This routine releases the system objects which monitor the secondary input* and output tasks for telnet clients. The server uses this routine to clean* up the (partial) task list if an error occurs during multiple task enabled * startup.** RETURNS: N/A** NOMANUAL*/LOCAL void telnetdTaskDelete ( int numTasks /* number of entries to remove */ ) { int count; BOOL telnetdTaskFlagSave; telnetdTaskFlagSave = telnetdTaskFlag; /* Save original state */ /* * Make sure the flag is set to FALSE so we delete objects instead of * restart objects with telnetdSessionDisconnectFromShell () */ telnetdTaskFlag = FALSE; for (count = 0; count < numTasks; count++) { if (telnetdParserControl != NULL) (*telnetdParserControl) (REMOTE_STOP, telnetdTaskList [count].pSession, 0); if (telnetdTaskList [count].pSession != NULL) { telnetdSessionDisconnect (telnetdTaskList [count].pSession, TRUE); free (telnetdTaskList [count].pSession); } } free (telnetdTaskList); semDelete (telnetdMutexSem); telnetdTaskFlag = telnetdTaskFlagSave; /* Restore original state */ return; }/********************************************************************************* telnetdExit - close an active telnet session** This routine supports the session exit command for a command interpreter* (such as logout() for the VxWorks shell). Depending on the TELNETD_TASKFLAG* setting, it causes the associated input and output tasks to restart or exit.* The <sessionId> parameter must match a value provided to the command* interpreter with the REMOTE_START option.** INTERNAL* This routine is used for termination via the shell. The inTask may also * terminate the connection via telnetdSessionDisconnectFromShell()** RETURNS: N/A.** ERRNO: N/A*/void telnetdExit ( UINT32 sessionId /* identifies the session to be deleted */ ) { telnetdSessionDisconnectFromShell ((TELNETD_SESSION_DATA *)sessionId); return; }/********************************************************************************* telnetdSessionAdd - add a new entry to the telnetd session slot list** Each of the telnet clients is associated with an entry in the server's* session list which records the session-specific context for each* connection, including the file descriptors that access the command* interpreter. This routine creates and initializes a new entry in the* session list, unless the needed memory is not available or the upper* limit for simultaneous connections is reached.** RETURNS: A pointer to the session list entry, or NULL if none available.** ERRNO: N/A** NOMANUAL**/LOCAL TELNETD_SESSION_DATA *telnetdSessionAdd (void) { TELNETD_SESSION_DATA * pSlot; int count = 0; semTake (telnetdMutexSem, WAIT_FOREVER); if (telnetdCurrentClients == telnetdMaxClients) { semGive (telnetdMutexSem); return (NULL); } /* Find an idle pair of input/output tasks, if needed. */ if (telnetdTaskFlag) /* Tasks created during server startup? */ { for (count = 0; count < telnetdMaxClients; count++) if (!telnetdTaskList [count].pSession->busyFlag) break; } /* Are there no more sessions available ? */ if (telnetdTaskFlag && (count == telnetdMaxClients)) { semGive (telnetdMutexSem); return ((TELNETD_SESSION_DATA *) NULL); } /* get memory for the new session entry */ if (telnetdTaskFlag) pSlot = telnetdTaskList [count].pSession; else { pSlot = (TELNETD_SESSION_DATA *) calloc (sizeof (TELNETD_SESSION_DATA), 1); if (pSlot == NULL) { semGive (telnetdMutexSem); return (NULL); } telnetdTaskList [count].pSession = pSlot; } pSlot->busyFlag = TRUE; pSlot->loggedIn = FALSE; telnetdCurrentClients++; if (!telnetdTaskFlag) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -