|
发表于 2007-6-28 06:59:38
|
显示全部楼层
http://lists.cistron.nl/pipermai ... 2-March/005600.html- /*
- * recvfromto Like recvfrom, but also stores the destination
- * IP address. Useful on multihomed hosts.
- *
- * Should work on Linux and BSD.
- *
- * Copyright (C) 2002 Miquel van Smoorenburg.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- */
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <sys/uio.h>
- #include <netinet/in.h>
- #include <errno.h>
- #include <unistd.h>
- #include <fcntl.h>
- /* Remove this when autoconf can detect this. */
- #if defined(IP_PKTINFO) && !defined(HAVE_IP_PKTINFO)
- # define HAVE_IP_PKTINFO 1
- #elif defined(IP_RECVDSTADDR) && !defined(HAVE_IP_RECVDSTADDR)
- # define HAVE_IP_RECVDSTADDR
- #endif
- int recvfromto(int s, void *buf, size_t len, int flags,
- struct sockaddr *from, socklen_t *fromlen,
- struct sockaddr *to, socklen_t *tolen)
- {
- struct msghdr msgh;
- struct cmsghdr *cmsg;
- struct iovec iov;
- char cbuf[1024];
- int opt, err;
- /*
- * If from or to are set, they must be big enough
- * to store a struct sockaddr_in.
- */
- if ((from && (!fromlen || *fromlen < sizeof(struct sockaddr_in))) ||
- (to && (!tolen || *tolen < sizeof(struct sockaddr_in)))) {
- errno = EINVAL;
- return -1;
- }
- if (tolen) *tolen = 0;
- #ifdef HAVE_IP_PKTINFO
- /*
- * IP_PKTINFO doesn't provide sin_port so we have to
- * retrieve it using getsockname().
- */
- if (to) {
- struct sockaddr_in si;
- socklen_t l = sizeof(si);
- ((struct sockaddr_in *)to)->sin_family = AF_INET;
- ((struct sockaddr_in *)to)->sin_port = 0;
- l = sizeof(si);
- if (getsockname(s, (struct sockaddr *)&si, &l) == 0) {
- ((struct sockaddr_in *)to)->sin_port = si.sin_port;
- ((struct sockaddr_in *)to)->sin_addr = si.sin_addr;
- }
- *tolen = sizeof(struct sockaddr_in);
- }
- #endif
- /* Set MSG_DONTWAIT if O_NONBLOCK was set. */
- if (fcntl(s, F_GETFL) & O_NONBLOCK) flags |= MSG_DONTWAIT;
- /* Set up iov and msgh structures. */
- iov.iov_base = buf;
- iov.iov_len = len;
- msgh.msg_control = cbuf;
- msgh.msg_controllen = sizeof(cbuf);
- msgh.msg_name = from;
- msgh.msg_namelen = fromlen ? *fromlen : 0;
- msgh.msg_iov = &iov;
- msgh.msg_iovlen = 1;
- #ifdef HAVE_IP_PKTINFO
- /* Set the IP_PKTINFO option (Linux). */
- opt = 1;
- setsockopt(s, SOL_IP, IP_PKTINFO, &opt, sizeof(opt));
- #endif
- #ifdef HAVE_IP_RECVDSTADDR
- /* Set the IP_RECVDSTADDR option (BSD). */
- opt = 1;
- setsockopt(s, IPPROTO_IP, IP_RECVDSTADDR, &opt, sizeof(opt));
- #endif
- /* Receive one packet. */
- err = recvmsg(s, &msgh, flags);
- if (fromlen) *fromlen = msgh.msg_namelen;
- /* Process auxiliary received data in msgh */
- for (cmsg = CMSG_FIRSTHDR(&msgh);
- cmsg != NULL && cmsg->cmsg_len >= sizeof(*cmsg);
- cmsg = CMSG_NXTHDR(&msgh,cmsg)) {
- #ifdef HAVE_IP_PKTINFO
- if (cmsg->cmsg_level == SOL_IP
- && cmsg->cmsg_type == IP_PKTINFO) {
- struct in_pktinfo *i =
- (struct in_pktinfo *)CMSG_DATA(cmsg);
- if (to) {
- ((struct sockaddr_in *)to)->sin_addr =
- i->ipi_addr;
- *tolen = sizeof(struct sockaddr_in);
- }
- break;
- }
- #endif
- #ifdef HAVE_IP_RECVDSTADDR
- if (cmsg->cmsg_level == IPPROTO_IP
- && cmsg->cmsg_type == IP_RECVDSTADDR) {
- struct in_addr *i = (struct in_addr *)CMSG_DATA(cmsg);
- if (to) {
- ((struct sockaddr_in *)to)->sin_addr = *i;
- *tolen = sizeof(struct sockaddr_in);
- }
- }
- #endif
- }
- return err;
- }
- #ifdef STANDALONE
- #include <stdio.h>
- #include <stdlib.h>
- #include <arpa/inet.h>
- /*
- * Small test program to test recvfromto
- */
- int main(int argc, char **argv)
- {
- struct sockaddr_in from, to, in;
- char buf[1024];
- int port = 20000;
- int n, s, fl, tl;
- if (argc > 1) port = atoi(argv[1]);
- s = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
- in.sin_family = AF_INET;
- in.sin_port = htons(port);
- in.sin_addr.s_addr = INADDR_ANY;
- bind(s, &in, sizeof(in));
- while (1) {
- fl = tl = sizeof(struct sockaddr_in);
- memset(&from, 0, sizeof(from));
- memset(&to, 0, sizeof(to));
- if ((n = recvfromto(s, buf, sizeof(buf), 0,
- (struct sockaddr *)&from, &fl,
- (struct sockaddr *)&to, &tl)) < 0) {
- perror("recvfromto");
- break;
- }
- printf("Received a packet of %d bytes\n", n);
- printf(" src ip:port %s:%d\n",
- inet_ntoa(from.sin_addr), ntohs(from.sin_port));
- printf(" dst ip:port %s:%d\n",
- inet_ntoa(to.sin_addr), ntohs(to.sin_port));
- }
- return 0;
- }
- #endif /* STANDALONE */
复制代码 |
|