⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 connection.c

📁 网络端口的服务程序
💻 C
📖 第 1 页 / 共 2 页
字号:
/*
    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 + -