[PATCH 3/6] telnetd: Create server socket at start

Sebastian Huber sebastian.huber at embedded-brains.de
Wed Oct 10 12:12:30 UTC 2018


Update #3543.
---
 cpukit/telnetd/telnetd.c | 162 +++++++++++++++++++++++++----------------------
 1 file 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);
 }
-- 
2.16.4




More information about the devel mailing list