varp_socket.c
来自「xen虚拟机源代码安装包」· C语言 代码 · 共 768 行 · 第 1/2 页
C
768 行
/* * Copyright (C) 2004, 2005, 2006 Mike Wray <mike.wray@hp.com> * * 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., * 59 Temple Place, suite 330, Boston, MA 02111-1307 USA * */#include <linux/kernel.h>#include <linux/types.h>#include <linux/version.h>#include <asm/uaccess.h>#include <linux/net.h>#include <linux/in.h>#include <linux/ip.h>#include <linux/sched.h>#include <linux/file.h>#include <linux/version.h>#include <linux/smp_lock.h>#include <net/sock.h>#include <if_varp.h>#include <varp.h>#include <vnet_forward.h>/* Get macros needed to define system calls as functions in the kernel. */#define __KERNEL_SYSCALLS__int errno=0;#include <linux/unistd.h>#define MODULE_NAME "VARP"#define DEBUG 1#undef DEBUG#include "debug.h"/** @file * Support for the VARP udp sockets. */#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)/* Compensate for struct sock fields having 'sk_' added to them in 2.6. */#define sk_receive_queue receive_queue#define sk_sleep sleep/* Here because inline in 'socket.c' (2.4, in net.h for 2.6). */#define sockfd_put(sock) fput((sock)->file)#endifstatic inline mm_segment_t change_fs(mm_segment_t fs){ mm_segment_t oldfs = get_fs(); set_fs(fs); return oldfs;}/** Define the fcntl() syscall. */static inline _syscall3(int, fcntl, unsigned int, fd, unsigned int, cmd, unsigned long, arg)/* Replicate the user-space socket API. * The parts we need anyway. * * Some architectures use socketcall() to multiplex the socket-related calls, * but others define individual syscalls instead. * Architectures using socketcall() define __ARCH_WANT_SYS_SOCKETCALL. * NB. x86_64 architecture asserts __ARCH_WANT_SYS_SOCKETCALL in error. */#if defined(__ARCH_WANT_SYS_SOCKETCALL) && !defined(__x86_64__)/* Define the socketcall() syscall. * Multiplexes all the socket-related calls. * * @param call socket call id * @param args arguments (upto 6) * @return call-dependent value */static inline _syscall2(int, socketcall, int, call, unsigned long *, args)int socket(int family, int type, int protocol){ unsigned long args[6]; args[0] = (unsigned long)family; args[1] = (unsigned long)type; args[2] = (unsigned long)protocol; return socketcall(SYS_SOCKET, args);}int bind(int fd, struct sockaddr *umyaddr, int addrlen){ unsigned long args[6]; args[0] = (unsigned long)fd; args[1] = (unsigned long)umyaddr; args[2] = (unsigned long)addrlen; return socketcall(SYS_BIND, args);}int connect(int fd, struct sockaddr *uservaddr, int addrlen){ unsigned long args[6]; args[0] = (unsigned long)fd; args[1] = (unsigned long)uservaddr; args[2] = (unsigned long)addrlen; return socketcall(SYS_CONNECT, args);}int sendto(int fd, void * buff, size_t len, unsigned flags, struct sockaddr *addr, int addr_len){ unsigned long args[6]; args[0] = (unsigned long)fd; args[1] = (unsigned long)buff; args[2] = (unsigned long)len; args[3] = (unsigned long)flags; args[4] = (unsigned long)addr; args[5] = (unsigned long)addr_len; return socketcall(SYS_SENDTO, args);}int recvfrom(int fd, void * ubuf, size_t size, unsigned flags, struct sockaddr *addr, int *addr_len){ unsigned long args[6]; args[0] = (unsigned long)fd; args[1] = (unsigned long)ubuf; args[2] = (unsigned long)size; args[3] = (unsigned long)flags; args[4] = (unsigned long)addr; args[5] = (unsigned long)addr_len; return socketcall(SYS_RECVFROM, args);}int setsockopt(int fd, int level, int optname, void *optval, int optlen){ unsigned long args[6]; args[0] = (unsigned long)fd; args[1] = (unsigned long)level; args[2] = (unsigned long)optname; args[3] = (unsigned long)optval; args[4] = (unsigned long)optlen; return socketcall(SYS_SETSOCKOPT, args);}int getsockopt(int fd, int level, int optname, void *optval, int *optlen){ unsigned long args[6]; args[0] = (unsigned long)fd; args[1] = (unsigned long)level; args[2] = (unsigned long)optname; args[3] = (unsigned long)optval; args[4] = (unsigned long)optlen; return socketcall(SYS_GETSOCKOPT, args);}int shutdown(int fd, int how){ unsigned long args[6]; args[0] = (unsigned long)fd; args[1] = (unsigned long)how; return socketcall(SYS_SHUTDOWN, args);}int getsockname(int fd, struct sockaddr *usockaddr, int *usockaddr_len){ unsigned long args[6]; args[0] = (unsigned long)fd; args[1] = (unsigned long)usockaddr; args[2] = (unsigned long)usockaddr_len; return socketcall(SYS_GETSOCKNAME, args);}#else /* !__ARCH_WANT_SYS_SOCKETCALL *//* No socketcall - define the individual syscalls. */static inline _syscall3(int, socket, int, family, int, type, int, protocol);static inline _syscall3(int, bind, int, fd, struct sockaddr *, umyaddr, int, addrlen);static inline _syscall3(int, connect, int, fd, struct sockaddr *, uservaddr, int, addrlen);static inline _syscall6(int, sendto, int, fd, void *, buff, size_t, len, unsigned, flags, struct sockaddr *, addr, int, addr_len);static inline _syscall6(int, recvfrom, int, fd, void *, ubuf, size_t, size, unsigned, flags, struct sockaddr *, addr, int *, addr_len);static inline _syscall5(int, setsockopt, int, fd, int, level, int, optname, void *, optval, int, optlen);static inline _syscall5(int, getsockopt, int, fd, int, level, int, optname, void *, optval, int *, optlen);static inline _syscall2(int, shutdown, int, fd, int, how);static inline _syscall3(int, getsockname, int, fd, struct sockaddr *, usockaddr, int *, usockaddr_len);#endif /* __ARCH_WANT_SYS_SOCKETCALL *//*============================================================================*//** Socket flags. */enum VsockFlag { VSOCK_REUSE = 1, VSOCK_BIND = 2, VSOCK_CONNECT = 4, VSOCK_BROADCAST = 8, VSOCK_MULTICAST = 16, VSOCK_NONBLOCK = 32, };/** Convert socket flags to a string. * * @param flags flags * @return static string */char * socket_flags(int flags){ static char s[7]; int i = 0; s[i++] = (flags & VSOCK_CONNECT ? 'c' : '-'); s[i++] = (flags & VSOCK_BIND ? 'b' : '-'); s[i++] = (flags & VSOCK_REUSE ? 'r' : '-'); s[i++] = (flags & VSOCK_BROADCAST ? 'B' : '-'); s[i++] = (flags & VSOCK_MULTICAST ? 'M' : '-'); s[i++] = (flags & VSOCK_NONBLOCK ? 'N' : '-'); s[i++] = '\0'; return s;}/** Control flag for whether varp should be running. * If this is set 0 then the varp thread will notice and * (eventually) exit. */atomic_t varp_run = ATOMIC_INIT(0);enum { VARP_STATE_EXITED = 2, VARP_STATE_RUNNING = 1, VARP_STATE_NONE = 0, VARP_STATE_ERROR = -1,};/** State indicating whether the varp thread is running. */atomic_t varp_state = ATOMIC_INIT(VARP_STATE_NONE);int varp_thread_err = 0;/** The varp multicast socket. */int varp_mcast_sock = -1;/** The varp unicast socket. */int varp_ucast_sock = -1;/** Set socket option to reuse address. * * @param sock socket * @param reuse flag * @return 0 on success, error code otherwise */int setsock_reuse(int sock, int reuse){ int err = 0; err = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)); if(err < 0){ eprintf("> setsockopt SO_REUSEADDR: %d %d\n", err, errno); } return err;}/** Set socket broadcast option. * * @param sock socket * @param bcast flag * @return 0 on success, error code otherwise */int setsock_broadcast(int sock, int bcast){ int err = 0; err = setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &bcast, sizeof(bcast)); if(err < 0){ eprintf("> setsockopt SO_BROADCAST: %d %d\n", err, errno); } return err;}/** Join a socket to a multicast group. * * @param sock socket * @param saddr multicast address * @return 0 on success, error code otherwise */int setsock_multicast(int sock, uint32_t saddr){ int err = 0; struct ip_mreqn mreq = {}; int mloop = 0; // See 'man 7 ip' for these options. mreq.imr_multiaddr.s_addr = saddr; // IP multicast address. mreq.imr_address.s_addr = INADDR_ANY; // Interface IP address. mreq.imr_ifindex = 0; // Interface index (0 means any). err = setsockopt(sock, SOL_IP, IP_MULTICAST_LOOP, &mloop, sizeof(mloop)); if(err < 0){ eprintf("> setsockopt IP_MULTICAST_LOOP: %d %d\n", err, errno); goto exit; } err = setsockopt(sock, SOL_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)); if(err < 0){ eprintf("> setsockopt IP_ADD_MEMBERSHIP: %d %d\n", err, errno); goto exit; } exit: return err;}/** Set a socket's multicast ttl (default is 1). * @param sock socket * @param ttl ttl * @return 0 on success, error code otherwise */int setsock_multicast_ttl(int sock, uint8_t ttl){ int err = 0; err = setsockopt(sock, SOL_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)); return err;}/** Create a socket. * The flags can include values from enum VsockFlag. * * @param socktype socket type * @param saddr address * @param port port * @param flags flags * @param val return value for the socket connection * @return 0 on success, error code otherwise */int create_socket(int socktype, uint32_t saddr, uint32_t port, int flags, int *val){ int err = 0;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?