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

📄 udp-socket.c

📁 Serveez是一个服务器框架
💻 C
字号:
/* * udp-socket.c - udp socket implementations * * Copyright (C) 2000, 2001 Stefan Jahn <stefan@lkcc.org> * * This 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, or (at your option) * any later version. *  * This software 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 package; see the file COPYING.  If not, write to * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA.   * * $Id: udp-socket.c,v 1.13 2001/09/19 09:49:19 ela Exp $ * */#if HAVE_CONFIG_H# include <config.h>#endif#define _GNU_SOURCE#include <stdio.h>#include <string.h>#include <sys/types.h>#include <errno.h>#include <fcntl.h>#include <time.h>#if HAVE_UNISTD_H# include <unistd.h>#endif#ifndef __MINGW32__# include <sys/types.h># include <sys/socket.h># include <netinet/in.h>#endif#ifdef __MINGW32__# include <winsock2.h>#endif#include "libserveez/alloc.h"#include "libserveez/util.h"#include "libserveez/snprintf.h"#include "libserveez/socket.h"#include "libserveez/core.h"#include "libserveez/server-core.h"#include "libserveez/server.h"#include "libserveez/udp-socket.h"/* * This routine is the default reader for UDP sockets. Whenever the socket * descriptor is @code{select()}'ed for reading it is called by default and  * reads as much data as possible (whole packets only) and saves the sender  * into the @code{sock->remote_addr} field. The packet load is written into  * @code{sock->recv_buffer}. */intsvz_udp_read_socket (svz_socket_t *sock){  int do_read, num_read;  socklen_t len;  struct sockaddr_in sender;  len = sizeof (struct sockaddr_in);  /* Check if there is enough space to save the packet. */  do_read = sock->recv_buffer_size - sock->recv_buffer_fill;  if (do_read <= 0)    {      svz_log (LOG_ERROR, "receive buffer overflow on udp socket %d\n",	       sock->sock_desc);      return -1;    }    /* Receive data. */  if (!(sock->flags & SOCK_FLAG_CONNECTED))    {      num_read = recvfrom (sock->sock_desc,			   sock->recv_buffer + sock->recv_buffer_fill,			   do_read, 0, (struct sockaddr *) &sender, &len);    }  else    {      num_read = recv (sock->sock_desc,		       sock->recv_buffer + sock->recv_buffer_fill,		       do_read, 0);    }  /* Valid packet data arrived. */  if (num_read > 0)    {      sock->last_recv = time (NULL);      sock->recv_buffer_fill += num_read;      /* Save sender in socket structure. */      if (!(sock->flags & SOCK_FLAG_FIXED))	{	  sock->remote_port = sender.sin_port;	  sock->remote_addr = sender.sin_addr.s_addr;	}#if ENABLE_DEBUG      svz_log (LOG_DEBUG, "udp: recv%s: %s:%u (%d bytes)\n",	       sock->flags & SOCK_FLAG_CONNECTED ? "" : "from",	       svz_inet_ntoa (sock->remote_addr),	       ntohs (sock->remote_port), num_read);#endif /* ENABLE_DEBUG */      /* Check access lists. */      if (svz_sock_check_access (sock, sock) < 0)	return 0;      /* Handle packet. */      if (sock->check_request)        if (sock->check_request (sock))	  return -1;    }  /* Some error occurred. */  else    {      svz_log (LOG_ERROR, "udp: recv%s: %s\n",	       sock->flags & SOCK_FLAG_CONNECTED ? "" : "from", NET_ERROR);      if (svz_errno != SOCK_UNAVAILABLE)	return -1;    }  return 0;}/* * The @code{svz_udp_write_socket()} callback should be called whenever  * the UDP socket descriptor is ready for sending. It sends a single packet  * within the @code{sock->send_buffer} to the destination address specified  * by @code{sock->remote_addr} and @code{sock->remote_port}. */intsvz_udp_write_socket (svz_socket_t *sock){  int num_written;  unsigned do_write;  char *p;  socklen_t len;  struct sockaddr_in receiver;  /* return here if there is nothing to send */  if (sock->send_buffer_fill <= 0)    return 0;  len = sizeof (struct sockaddr_in);  receiver.sin_family = AF_INET;  /* get destination address, port and data length from buffer */  p = sock->send_buffer;  memcpy (&do_write, p, sizeof (do_write));  p += sizeof (do_write);  memcpy (&receiver.sin_addr.s_addr, p, sizeof (sock->remote_addr));  p += sizeof (sock->remote_addr);  memcpy (&receiver.sin_port, p, sizeof (sock->remote_port));  p += sizeof (sock->remote_port);  /* if socket is `connect ()' ed use `send ()' instead of `sendto ()' */  if (!(sock->flags & SOCK_FLAG_CONNECTED))    {      num_written = sendto (sock->sock_desc, p,			    do_write - (p - sock->send_buffer),			    0, (struct sockaddr *) &receiver, len);    }  else    {      num_written = send (sock->sock_desc, p,			  do_write - (p - sock->send_buffer), 0);    }  /* some error occurred while sending */  if (num_written < 0)    {      svz_log (LOG_ERROR, "udp: send%s: %s\n", 	       sock->flags & SOCK_FLAG_CONNECTED ? "" : "to", NET_ERROR);      if (svz_errno == SOCK_UNAVAILABLE)	num_written = 0;    }  /* packet data could be transmitted */  else    {      sock->last_send = time (NULL);      svz_sock_reduce_send (sock, (int) do_write);    }#if ENABLE_DEBUG  svz_log (LOG_DEBUG, "udp: send%s: %s:%u (%u bytes)\n",	   sock->flags & SOCK_FLAG_CONNECTED ? "" : "to", 	   svz_inet_ntoa (receiver.sin_addr.s_addr),	   ntohs (receiver.sin_port), do_write - (p - sock->send_buffer));#endif /* ENABLE_DEBUG */  return num_written < 0 ? -1 : 0;}/* * This is the default @code{check_request()} routine for UDP servers.  * Whenever new data arrived at an UDP server socket we call this function to * process the packet data. Any given @code{handle_request()} callback MUST  * return zero if it successfully processed the data and non-zero if it  * could not. */intsvz_udp_check_request (svz_socket_t *sock){  int n;  svz_server_t *server;  if (sock->data == NULL && sock->handle_request == NULL)    return -1;  /*    * If there is a valid `handle_request ()' callback (dedicated udp    * connection) call it. This kind of behaviour is due to a socket creation    * via `udp_connect ()' and setting up a static `handle_request ()'   * callback.   */  if (sock->handle_request)    {      if (sock->handle_request (sock, sock->recv_buffer,				sock->recv_buffer_fill))	return -1;      sock->recv_buffer_fill = 0;      return 0;    }  /* go through all udp servers on this server socket */  svz_array_foreach (sock->data, server, n)    {      sock->cfg = server->cfg;            if (server->handle_request)	{	  if (!server->handle_request (sock, sock->recv_buffer,				       sock->recv_buffer_fill))	    {	      sock->recv_buffer_fill = 0;	      break;	    }        }    }  /* check if any server processed this packet */  if (sock->recv_buffer_fill)    {#if ENABLE_DEBUG      svz_log (LOG_DEBUG, "rejecting udp packet on socket %d\n",	       sock->sock_desc);#endif      sock->recv_buffer_fill = 0;    }  sock->cfg = NULL;  return 0;}/* * Write the given @var{buf} into the send queue of the UDP socket. If the * length argument supersedes the maximum length for UDP messages it * is split into smaller packets. */intsvz_udp_write (svz_socket_t *sock, char *buf, int length){  char *buffer;  unsigned len, size;  int ret = 0;  /* return if the socket has already been killed */  if (sock->flags & SOCK_FLAG_KILLED)    return 0;  /* allocate memory block */  buffer = svz_malloc ((length > UDP_MSG_SIZE ? UDP_MSG_SIZE : length) + 		       sizeof (len) + sizeof (sock->remote_addr) +		       sizeof (sock->remote_port));  while (length)    {      /*        * Put the data length, destination address and port in front       * of each data packet.       */      len = sizeof (len);      memcpy (&buffer[len], &sock->remote_addr, sizeof (sock->remote_addr));      len += sizeof (sock->remote_addr);      memcpy (&buffer[len], &sock->remote_port, sizeof (sock->remote_port));      len += sizeof (sock->remote_port);      /* copy the given buffer */      if ((size = length) > UDP_MSG_SIZE)	size = UDP_MSG_SIZE;      memcpy (&buffer[len], buf, size);      len += size;      memcpy (buffer, &len, sizeof (len));      buf += size;      length -= size;      /* actually send the data or put it into the send buffer queue */      if ((ret = svz_sock_write (sock, buffer, len)) == -1)	{	  sock->flags |= SOCK_FLAG_KILLED;	  break;	}    }  /* release memory block */  svz_free (buffer);  return ret;}/* * Print a formatted string on the UDP socket @var{sock}. @var{fmt} is  * the printf()-style format string, which describes how to format the  * optional arguments. See the printf(3) manual page for details. The  * destination address and port is saved for sending. This you might  * specify them in @code{sock->remote_addr} and @code{sock->remote_port}. */intsvz_udp_printf (svz_socket_t *sock, const char *fmt, ...){  va_list args;  static char buffer[VSNPRINTF_BUF_SIZE];  int len;  if (sock->flags & SOCK_FLAG_KILLED)    return 0;  va_start (args, fmt);  len = svz_vsnprintf (buffer, VSNPRINTF_BUF_SIZE, fmt, args);  va_end (args);  return svz_udp_write (sock, buffer, len);}/* * Create a UDP connection to @var{host} and set the socket descriptor in * structure @var{sock} to the resulting socket. Return a @code{NULL} value  * on errors. This function can be used for port bouncing. If you assign the * @code{handle_request} callback to something server specific and the  * @var{cfg} field to the server's configuration to the returned socket  * structure this socket is able to handle a dedicated UDP connection to  * some other UDP server. */svz_socket_t *svz_udp_connect (unsigned long host, unsigned short port){  SOCKET sockfd;  svz_socket_t *sock;  /* Create a client socket. */  if ((sockfd = svz_socket_create (PROTO_UDP)) == (SOCKET) -1)      return NULL;  /* Try to connect to the server. Does it make sense for ICMP ? */  if (svz_socket_connect (sockfd, host, port) == -1)     return NULL;  /* Create socket structure and enqueue it. */  if ((sock = svz_sock_alloc ()) == NULL)    {      closesocket (sockfd);      return NULL;    }  svz_sock_resize_buffers (sock, UDP_BUF_SIZE, UDP_BUF_SIZE);  svz_sock_unique_id (sock);  sock->sock_desc = sockfd;  sock->flags |= (SOCK_FLAG_SOCK | SOCK_FLAG_CONNECTED | SOCK_FLAG_FIXED);  svz_sock_enqueue (sock);  svz_sock_intern_connection_info (sock);  sock->read_socket = svz_udp_read_socket;  sock->write_socket = svz_udp_write_socket;  sock->check_request = svz_udp_check_request;  svz_sock_connections++;  return sock;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -