summaryrefslogtreecommitdiffstats
path: root/cpukit/telnetd/telnetd.c
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2018-10-10 09:04:47 +0200
committerSebastian Huber <sebastian.huber@embedded-brains.de>2018-10-10 14:06:28 +0200
commitbf4c7ff6ab8df166c42007501eb690ec738ef0f5 (patch)
treed4d85412e285ec637ff704670f16133a305f6ec5 /cpukit/telnetd/telnetd.c
parenttelnetd: Rename shell_args to telnetd_session (diff)
downloadrtems-bf4c7ff6ab8df166c42007501eb690ec738ef0f5.tar.bz2
telnetd: Create server socket at start
Update #3543.
Diffstat (limited to 'cpukit/telnetd/telnetd.c')
-rw-r--r--cpukit/telnetd/telnetd.c162
1 files changed, 86 insertions, 76 deletions
diff --git a/cpukit/telnetd/telnetd.c b/cpukit/telnetd/telnetd.c
index 1fcd4c54d9..0fd3b317a9 100644
--- a/cpukit/telnetd/telnetd.c
+++ b/cpukit/telnetd/telnetd.c
@@ -72,6 +72,7 @@ typedef struct telnetd_session {
struct telnetd_context {
rtems_telnetd_config_table config;
+ int server_socket;
uint16_t active_clients;
};
@@ -80,21 +81,14 @@ typedef union uni_sa {
struct sockaddr sa;
} uni_sa;
-static int sockpeername(int sock, char *buf, int bufsz);
-
/***********************************************************/
static telnetd_context telnetd_instance;
-static telnetd_session *grab_a_Connection(
- telnetd_context *ctx,
- int des_socket,
- uni_sa *srv,
- char *peername,
- int sz
-)
+static telnetd_session *grab_a_Connection(telnetd_context *ctx)
{
telnetd_session *session;
- socklen_t size_adr = sizeof(srv->sin);
+ uni_sa peer;
+ socklen_t address_len;
int acp_sock;
if (ctx->active_clients >= ctx->config.client_maximum) {
@@ -107,7 +101,8 @@ static telnetd_session *grab_a_Connection(
return NULL;
}
- acp_sock = accept(des_socket,&srv->sa,&size_adr);
+ address_len = sizeof(peer.sin);
+ acp_sock = accept(ctx->server_socket, &peer.sa, &address_len);
if (acp_sock<0) {
perror("telnetd:accept");
free(session);
@@ -121,13 +116,21 @@ static telnetd_session *grab_a_Connection(
return NULL;
}
- if (sockpeername(acp_sock, peername, sz))
- strncpy(peername, "<UNKNOWN>", sz);
+ if (
+ inet_ntop(
+ AF_INET,
+ &peer.sin.sin_addr,
+ session->peername,
+ sizeof(session->peername)
+ ) == NULL
+ ) {
+ strlcpy(session->peername, "<UNKNOWN>", sizeof(session->peername));
+ }
#ifdef PARANOIA
syslog(LOG_DAEMON | LOG_INFO,
"telnetd: accepted connection from %s on %s",
- peername,
+ session->peername,
session->pty.name);
#endif
@@ -137,15 +140,20 @@ static telnetd_session *grab_a_Connection(
}
-static void release_a_Connection(telnetd_context *ctx, const char *devname,
- const char *peername, FILE **pstd, int n)
+static void release_a_Connection(
+ telnetd_context *ctx,
+ telnetd_session *session,
+ FILE **pstd,
+ int n
+)
{
-
#ifdef PARANOIA
- syslog( LOG_DAEMON | LOG_INFO,
- "telnetd: releasing connection from %s on %s",
- peername,
- devname );
+ syslog(
+ LOG_DAEMON | LOG_INFO,
+ "telnetd: releasing connection from %s on %s",
+ session->peername,
+ session->pty.name
+ );
#endif
--ctx->active_clients;
@@ -153,22 +161,7 @@ static void release_a_Connection(telnetd_context *ctx, const char *devname,
while (--n>=0)
if (pstd[n]) fclose(pstd[n]);
- unlink(devname);
-}
-
-static int sockpeername(int sock, char *buf, int bufsz)
-{
- uni_sa peer;
- int rval = sock < 0;
- socklen_t len = sizeof(peer.sin);
-
- if ( !rval )
- rval = getpeername(sock, &peer.sa, &len);
-
- if ( !rval )
- rval = !inet_ntop( AF_INET, &peer.sin.sin_addr, buf, bufsz );
-
- return rval;
+ unlink(session->pty.name);
}
static rtems_id telnetd_spawn_task(
@@ -205,42 +198,15 @@ telnetd_session_task(rtems_task_argument arg);
static void
telnetd_server_task(rtems_task_argument arg)
{
- int des_socket;
- uni_sa srv;
- char peername[16];
- int i=1;
- int size_adr;
telnetd_session *session = NULL;
rtems_id task_id;
telnetd_context *ctx = (telnetd_context *) arg;
- if ((des_socket=socket(PF_INET,SOCK_STREAM,0))<0) {
- perror("telnetd:socket");
- rtems_task_exit();
- };
- (void)setsockopt(des_socket,SOL_SOCKET,SO_KEEPALIVE,&i,sizeof(i));
-
- memset(&srv,0,sizeof(srv));
- srv.sin.sin_family=AF_INET;
- srv.sin.sin_port=htons(23);
- size_adr=sizeof(srv.sin);
- if ((bind(des_socket,&srv.sa,size_adr))<0) {
- perror("telnetd:bind");
- close(des_socket);
- rtems_task_exit();
- };
- if ((listen(des_socket,5))<0) {
- perror("telnetd:listen");
- close(des_socket);
- rtems_task_exit();
- };
-
/* we don't redirect stdio as this probably
* was started from the console anyway ..
*/
do {
- session = grab_a_Connection(ctx, des_socket, &srv, peername,
- sizeof(peername));
+ session = grab_a_Connection(ctx);
if (session == NULL) {
/* if something went wrong, sleep for some time */
@@ -248,8 +214,6 @@ telnetd_server_task(rtems_task_argument arg)
continue;
}
- strncpy(session->peername, peername, sizeof(session->peername));
-
task_id = telnetd_spawn_task(
rtems_build_name('T', 'N', 'T', 'a'),
ctx->config.priority,
@@ -269,25 +233,64 @@ telnetd_server_task(rtems_task_argument arg)
if ( !(dummy=fopen(session->pty.name,"r+")) )
perror("Unable to dummy open the pty, losing a slot :-(");
- release_a_Connection(ctx, session->pty.name, peername, &dummy, 1);
+ release_a_Connection(ctx, session, &dummy, 1);
free(session);
sleep(2); /* don't accept connections too fast */
}
} while(1);
+}
- /* TODO: how to free the connection semaphore? But then -
- * stopping the daemon is probably only needed during
- * development/debugging.
- * Finalizer code should collect all the connection semaphore
- * counts and eventually clean up...
- */
- close(des_socket);
+static void telnetd_destroy_context(telnetd_context *ctx)
+{
+ if (ctx->server_socket >= 0) {
+ close(ctx->server_socket);
+ }
+}
+
+static rtems_status_code telnetd_create_server_socket(telnetd_context *ctx)
+{
+ uni_sa srv;
+ socklen_t address_len;
+ int enable;
+
+ ctx->server_socket = socket(PF_INET, SOCK_STREAM, 0);
+ if (ctx->server_socket < 0) {
+ syslog(LOG_DAEMON | LOG_ERR, "telnetd: cannot create server socket");
+ return RTEMS_UNSATISFIED;
+ }
+
+ enable = 1;
+ (void)setsockopt(
+ ctx->server_socket,
+ SOL_SOCKET,
+ SO_KEEPALIVE,
+ &enable,
+ sizeof(enable)
+ );
+
+ memset(&srv, 0, sizeof(srv));
+ srv.sin.sin_family = AF_INET;
+ srv.sin.sin_port = htons(23);
+ address_len = sizeof(srv.sin);
+
+ if (bind(ctx->server_socket, &srv.sa, address_len) != 0) {
+ syslog(LOG_DAEMON | LOG_ERR, "telnetd: cannot bind server socket");
+ return RTEMS_RESOURCE_IN_USE;
+ };
+
+ if (listen(ctx->server_socket, ctx->config.client_maximum) != 0) {
+ syslog(LOG_DAEMON | LOG_ERR, "telnetd: cannot listen on server socket");
+ return RTEMS_UNSATISFIED;
+ };
+
+ return RTEMS_SUCCESSFUL;
}
rtems_status_code rtems_telnetd_start(const rtems_telnetd_config_table* config)
{
telnetd_context *ctx = &telnetd_instance;
rtems_id task_id;
+ rtems_status_code sc;
if (config->command == NULL) {
syslog(LOG_DAEMON | LOG_ERR, "telnetd: configuration with invalid command");
@@ -320,6 +323,12 @@ rtems_status_code rtems_telnetd_start(const rtems_telnetd_config_table* config)
ctx->config.client_maximum = 5;
}
+ sc = telnetd_create_server_socket(ctx);
+ if (sc != RTEMS_SUCCESSFUL) {
+ telnetd_destroy_context(ctx);
+ return sc;
+ }
+
task_id = telnetd_spawn_task(
rtems_build_name('T', 'N', 'T', 'D'),
ctx->config.priority,
@@ -330,6 +339,7 @@ rtems_status_code rtems_telnetd_start(const rtems_telnetd_config_table* config)
if (task_id == RTEMS_ID_NONE) {
ctx->config.command = NULL;
syslog(LOG_DAEMON | LOG_ERR, "telnetd: cannot create server task");
+ telnetd_destroy_context(ctx);
return RTEMS_UNSATISFIED;
}
@@ -404,6 +414,6 @@ telnetd_session_task(rtems_task_argument arg)
}
cleanup:
- release_a_Connection(ctx, session->pty.name, session->peername, nstd, i);
+ release_a_Connection(ctx, session, nstd, i);
free(session);
}