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 + -
显示快捷键?