📄 connection.c
字号:
/*
Portserver - Use RTERM protocol to serve serial ports over a network
Copyright (C) 1998 Kenn Humborg
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <netdb.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <tcpd.h>
#include <unistd.h>
#include "buffer.h"
#include "command.h"
#include "connection.h"
#include "port.h"
#include "portserver.h"
#include "status.h"
/* The list head for the connection list */
struct Connection connection_list;
/* These define the LOG_xxx severity of syslog messages from tcp wrappers */
int allow_severity = LOG_INFO;
int deny_severity = LOG_ERR;
/* Forward declarations for local functions */
static void HandleCommandData(struct Connection *connection);
static STATUS CreateConnection(struct Connection **new_connection);
void NewConnection(void)
{
STATUS status;
struct Connection *connection;
struct sockaddr addr;
int addr_len;
int fd;
int flags;
struct request_info req;
status = CreateConnection(&connection);
if (IS_FAILURE(status)) {
syslog(LOG_ERR, "Cannot create connection: %s", ErrorMsg(status));
return;
}
addr_len = sizeof(addr);
fd = accept(main_socket, &addr, &addr_len);
if (fd == -1) {
syslog(LOG_ERR, "accept failed: %m");
DeleteConnection(connection);
return;
}
/* Do tcp-wrapper access control */
request_init(&req, RQ_DAEMON, argv0, RQ_FILE, fd, NULL);
fromhost(&req);
if (!hosts_access(&req)) {
syslog(LOG_ERR, "Connection denied from %s@%s", eval_user(&req),
eval_hostname(&req.client));
close(fd);
DeleteConnection(connection);
return;
}
flags = fcntl(fd, F_GETFL);
flags |= O_NONBLOCK;
fcntl(fd, flags);
/* We need to watch for incoming data from this socket */
FD_SET(fd, &read_fds);
FD_SET(fd, &excep_fds);
connection->fd = fd;
connection->remote_user = strdup(eval_user(&req));
if (connection->remote_user == NULL) {
syslog(LOG_ERR, "NewConnection: Out of memory, dropping connection");
close(fd);
DeleteConnection(connection);
return;
}
connection->remote_host = strdup(eval_hostname(&req.client));
if (connection->remote_user == NULL) {
syslog(LOG_ERR, "NewConnection: Out of memory, dropping connection");
free(connection->remote_user);
close(fd);
DeleteConnection(connection);
return;
}
AddConnection(connection);
GetMaxFD();
syslog(LOG_ERR, "Connection accepted from %s@%s", eval_user(&req),
eval_hostinfo(&req.client));
}
static STATUS CreateConnection(struct Connection **new_connection)
{
STATUS status;
struct Connection *connection;
connection = malloc(sizeof(struct Connection));
if (connection == NULL) {
return ERR_NOMEMORY;
}
connection->next = NULL;
connection->prev = NULL;
connection->fd = 0;
connection->port = NULL;
connection->flags = 0;
connection->remote_host = NULL;
connection->remote_user = NULL;
connection->command_buf = malloc(COMMAND_BUFFER_CHUNK_SIZE);
if (connection->command_buf == NULL) {
free(connection);
return ERR_NOMEMORY;
}
connection->command_buf_size = COMMAND_BUFFER_CHUNK_SIZE;
connection->command_len = 0;
connection->response_buf = malloc(RESPONSE_BUFFER_CHUNK_SIZE);
if (connection->response_buf == NULL) {
free(connection->command_buf);
free(connection);
return ERR_NOMEMORY;
}
connection->response_buf_size = RESPONSE_BUFFER_CHUNK_SIZE;
connection->response_len = 0;
status = BufferCreate(SOCKET_BUFFER_SIZE, &connection->read_buffer);
if (IS_FAILURE(status)) {
free(connection->response_buf);
free(connection->command_buf);
free(connection);
return status;
}
status = BufferCreate(SOCKET_BUFFER_SIZE, &connection->write_buffer);
if (IS_FAILURE(status)) {
BufferDelete(connection->read_buffer);
free(connection->response_buf);
free(connection->command_buf);
free(connection);
return status;
}
*new_connection = connection;
return SUCCESS;
}
void AddConnection(struct Connection *connection)
{
connection->next = &connection_list;
connection->prev = connection_list.prev;
connection_list.prev->next = connection;
connection_list.prev = connection;
}
void RemoveConnection(struct Connection *connection)
{
connection->next->prev = connection->prev;
connection->prev->next = connection->next;
/* Paranoia... This is to catch people using connections that are not on the list */
connection->next = NULL;
connection->prev = NULL;
}
void DeleteConnection(struct Connection *connection)
{
BufferDelete(connection->write_buffer);
BufferDelete(connection->read_buffer);
free(connection->command_buf);
if (connection->remote_host != NULL) {
free(connection->remote_host);
}
if (connection->remote_user != NULL) {
free(connection->remote_user);
}
free(connection);
}
/* This function handles any data received on the socket. It returns FALSE if the
socket is closed. In this case, the Connection structure will have been deleted,
so the passed pointer will be invalid. */
int SocketDataReceived(struct Connection *connection)
{
int bytes;
struct Buffer *buf;
if (connection->read_buffer->data_length != 0) {
syslog(LOG_ERR, "Connection fd=%d, read buffer not empty", connection->fd);
}
buf = connection->read_buffer;
bytes = read(connection->fd, buf->data, buf->length);
if (bytes == -1) {
syslog(LOG_ERR, "Connection fd=%d, read failed: %m", connection->fd);
return TRUE;
}
if (bytes == 0) {
/* socket is closed */
syslog(LOG_NOTICE, "Closing connection fd=%d\n", connection->fd);
connection->flags |= CONNECTION_CLOSING;
if (connection->port != NULL) {
DeassignPort(connection);
}
return FALSE;
}
buf->data_length = bytes;
HandleSocketData(connection);
return FALSE;
}
void HandleSocketData(struct Connection *connection)
{
struct Buffer *buf;
int end_of_data;
int bytes_sent;
buf = connection->read_buffer;
while (buf->data_length > 0) {
if (connection->flags & CONNECTION_COMMAND_MODE) {
HandleCommandData(connection);
/* Skip the rest of the loop because the buffer may
now be empty */
continue;
}
if (buf->data[0] == COMMAND_START) {
/* Command char received, what we do depends on whether the last
character was a command char as well */
if (connection->flags & CONNECTION_GOT_COMMAND_START) {
/* This is the second in a row, reset the flag and
fall through */
connection->flags &= ~CONNECTION_GOT_COMMAND_START;
} else {
/* We might have an incoming command. Set the command char
flag, remove the char from the buffer and hop back
to the beginning of the loop */
connection->flags |= CONNECTION_GOT_COMMAND_START;
BufferRemove(buf, 1);
continue;
}
}
/* At this stage, if GOT_COMMAND_START is set, then
we've just started to receive the beginning of a
command. Hop back to the beginning of the loop
to handle it. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -