Stun Server  Compliant with the latest RFCs including 5389, 5769, and 5780
discover the local host's own external IP address
recvfromex.cpp
Go to the documentation of this file.
1 /*
2  Copyright 2011 John Selbie
3 
4  Licensed under the Apache License, Version 2.0 (the "License");
5  you may not use this file except in compliance with the License.
6  You may obtain a copy of the License at
7 
8  http://www.apache.org/licenses/LICENSE-2.0
9 
10  Unless required by applicable law or agreed to in writing, software
11  distributed under the License is distributed on an "AS IS" BASIS,
12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  See the License for the specific language governing permissions and
14  limitations under the License.
15 */
16 
17 
18 
19 #include "commonincludes.hpp"
20 #include "socketaddress.h"
21 
22 
23 static void InitSocketAddress(int family, CSocketAddress* pAddr)
24 {
25  if (family == AF_INET)
26  {
27  sockaddr_in addr = {};
28  addr.sin_family = AF_INET;
29  *pAddr = CSocketAddress(addr);
30  }
31  else if (family == AF_INET6)
32  {
33  sockaddr_in6 addr = {};
34  addr.sin6_family = AF_INET6;
35  *pAddr = CSocketAddress(addr);
36  }
37  else
38  {
39  ASSERT(false);
40  }
41 }
42 
43 
44 ssize_t recvfromex(int sockfd, void* buf, size_t len, int flags, CSocketAddress* pSrcAddr, CSocketAddress* pDstAddr)
45 {
46  struct iovec vec;
47  ssize_t ret;
48 
49  char controldata[1000];
50 
51  struct msghdr hdr = {};
52  sockaddr_storage addrRemote = {};
53 
54  vec.iov_base = buf;
55  vec.iov_len = len;
56 
57  hdr.msg_name = &addrRemote;
58  hdr.msg_namelen = sizeof(addrRemote);
59  hdr.msg_iov = &vec;
60  hdr.msg_iovlen = 1;
61  hdr.msg_control = controldata;
62  hdr.msg_controllen = ARRAYSIZE(controldata);
63 
64  ret = ::recvmsg(sockfd, &hdr, flags);
65 
66  if (ret > 0)
67  {
68  if (pSrcAddr)
69  {
70  *pSrcAddr = CSocketAddress(*(sockaddr*)&addrRemote);
71  }
72 
73  if (pDstAddr)
74  {
75  struct cmsghdr* pCmsg = NULL;
76 
77  InitSocketAddress(addrRemote.ss_family, pDstAddr);
78 
79  for (pCmsg = CMSG_FIRSTHDR(&hdr); pCmsg != NULL; pCmsg = CMSG_NXTHDR(&hdr, pCmsg))
80  {
81  // IPV6 address ----------------------------------------------------------
82  if ((pCmsg->cmsg_level == IPPROTO_IPV6) && (pCmsg->cmsg_type == IPV6_PKTINFO) && CMSG_DATA(pCmsg))
83  {
84  struct in6_pktinfo* pInfo = (in6_pktinfo*)CMSG_DATA(pCmsg);
85  sockaddr_in6 addr = {};
86  addr.sin6_family = AF_INET6;
87  addr.sin6_addr = pInfo->ipi6_addr;
88  *pDstAddr = CSocketAddress(addr);
89  break;
90  }
91 
92 
93  // IPV4 address ----------------------------------------------------------
94  // if you change the ifdef's below, make sure you it's matched with the same logic in stunsocket.cpp
95  // Might be worthwhile to just use IP_RECVORIGDSTADDR and IP_ORIGDSTADDR so we can merge with the bsd code
96 
97 #ifdef IP_PKTINFO
98  if ((pCmsg->cmsg_level == IPPROTO_IP) && (pCmsg->cmsg_type==IP_PKTINFO) && CMSG_DATA(pCmsg))
99  {
100  struct in_pktinfo* pInfo = (in_pktinfo*)CMSG_DATA(pCmsg);
101  sockaddr_in addr = {};
102  addr.sin_family = AF_INET;
103  addr.sin_addr = pInfo->ipi_addr;
104  *pDstAddr = CSocketAddress(addr);
105  break;
106  }
107 #endif
108 
109 #ifdef IP_RECVDSTADDR
110  // This code path for MacOSX and likely BSD as well
111  if ((pCmsg->cmsg_level == IPPROTO_IP) && (pCmsg->cmsg_type==IP_RECVDSTADDR) && CMSG_DATA(pCmsg))
112  {
113  sockaddr_in addr = {};
114  addr.sin_family = AF_INET;
115  addr.sin_addr = *(in_addr*)CMSG_DATA(pCmsg);
116  *pDstAddr = CSocketAddress(addr);
117  break;
118  }
119 #endif
120  }
121  }
122  }
123 
124  return ret;
125 }
126 
#define ASSERT(expr)
ssize_t recvfromex(int sockfd, void *buf, size_t len, int flags, CSocketAddress *pSrcAddr, CSocketAddress *pDstAddr)
Definition: recvfromex.cpp:44
#define ARRAYSIZE(arr)
static void InitSocketAddress(int family, CSocketAddress *pAddr)
Definition: recvfromex.cpp:23