telnetd: Create server socket at start

Update #3543.
This commit is contained in:
Sebastian Huber
2018-10-10 14:06:28 +02:00
parent 1c567c56c0
commit bf4c7ff6ab
+86 -76
View File
@@ -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);
}