bind () error : Cannot assign requested address.
new_socket= socket(AF_INET, SOCK_DGRAM, 0);
localIP = "128.1.1.64";
memset(&socket_data, 0, sizeof(socket_data));
// Fill the socket structure
socket_data.sin_family = AF_INET;
socket_data.sin_addr.s_addr = inet_addr(localIP);
socket_data.sin_port = htons(PortNumber);
bind( new_socket, (struct sockaddr*) &socket_data, sizeof(socket_data))
Does any one know why the bind() is failing?
I guess 128.1.1.64 is an arbitrary IP which does not exist in any of your net interface. If you want to spoof the source IP, probably you need to use RAW_SOCKET.
You have a socket already bound to that address/port combination is my guess
Related
I'm trying to send and receive UDP packets through the same endpoint. As far as I know this should be possible. But I can not get it to work with the asio library (version 1.20.0).
This is what I do:
asio::io_context io_context;
asio::ip::udp::socket* udpSendRecvSocket = new asio::ip::udp::socket(io_context, asio::ip::udp::endpoint(asio::ip::udp::v4(), 7782));
asio::error_code ec;
char data[1000];
//
// send packet
//
std::string ipAddress = "127.0.0.1";
asio::ip::address ip_address = asio::ip::address::from_string(ipAddress);
asio::ip::udp::endpoint remoteTarget_endpoint(ip_address, 5500);
udpSendRecvSocket->send_to(asio::buffer(data, 50), remoteTarget_endpoint, 0, ec);
if (ec) {
return 0;
}
//
// receive packets
//
size_t avLen = udpSendRecvSocket->available(ec);
while (avLen) {
asio::ip::udp::endpoint remote_endpoint;
size_t length = udpSendRecvSocket->receive_from(asio::buffer(data, 1000), remote_endpoint, 0, ec);
int p = remote_endpoint.port();
if (ec) {
return 0;
}
avLen -= length;
}
The receive does not work correctly. I do receive a packet that I send (from some other app). I know because avLen gets the right value. But when executing the receive_from(), if fails. And the port number in p gets the value 5500. This is the value of the target port of the send_to() call that was executed before.
The strange thing is that when I remove the send_to() call, the receive does work correctly and the p will reflect the correct port number of the sending application.
Is this a bug?
I'm trying to send data to and from my computer and an STM32H745 over Ethernet using LwIP and UDP. I have successfully configured the card and right now I can send data from the card to a Python script running on the computer. However, I don't understand how udp_recv works <udp,lwip> or how to receive data with UDP on LwIP in general, and I can't find examples that do just that. Where is the data being received? Should I even use udp_recv?
In the main loop I run MX_LWIP_Process, which runs ethernetif_input which somehow handles the received data, but I don't understand where it puts it.
Below is the main code, just for reference.
const char* message = "a";
HAL_GPIO_TogglePin(GPIOE, GPIO_PIN_1); // orange
ip_addr_t PC_IPADDR;
IP_ADDR4(&PC_IPADDR, 192, 168, 1, 200);
u16_t port = 8000;
struct udp_pcb* my_udp = udp_new();
struct pbuf* udp_buffer = NULL;
/* Infinite loop */
for (;; )
{
MX_LWIP_Process();
HAL_GPIO_TogglePin(GPIOE, GPIO_PIN_1); // orange
HAL_Delay(1000);
udp_buffer = pbuf_alloc(PBUF_TRANSPORT, strlen(message), PBUF_RAM);
if (udp_buffer != NULL)
{
memcpy(udp_buffer->payload, message, strlen(message));
udp_sendto(my_udp, udp_buffer,&PC_IPADDR, port);
pbuf_free(udp_buffer);
}
//udp_recv (struct udp_pcb *pcb, udp_recv_fn recv, void *recv_arg)
}
udp_recv() does not actually receive UDP datagrams (despite its name). It registers a callback function that will then be called by MX_LWIP_Process() when a datagram has been buffered. It would better be called udp_set_recv_callback(), but it is what it is.
To that end you should call it once before your executive loop:
udp_bind( my_udp, IP_ADDR_ANY, port ) ;
udp_recv( my_udp, udp_receive_callback, NULL ) ;
/* Infinite loop */
for (;; )
{
// Run the CubeMX LwIP stack
MX_LWIP_Process() ;
...
}
Where udp_receive_callback is a function that will be invoked on receipt of a datagram:
void udp_receive_callback( void* arg, // User argument - udp_recv `arg` parameter
struct udp_pcb* upcb, // Receiving Protocol Control Block
struct pbuf* p, // Pointer to Datagram
const ip_addr_t* addr, // Address of sender
u16_t port ) // Sender port
{
// Process datagram here (non-blocking code)
...
// Must free receive pbuf before return
pbuf_free(p);
}
Examples include:
https://gist.github.com/iwanbk/1399729
https://github.com/STMicroelectronics/STM32CubeF2/blob/master/Projects/STM322xG_EVAL/Applications/LwIP/LwIP_UDP_Echo_Client/Src/udp_echoclient.c
Documentation can be found at https://www.nongnu.org/lwip/2_0_x/group__udp__raw.html
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 5 years ago.
Improve this question
Apple requires IPv6 Compatibility. Seems a little premature, but I suppose someone has to force it's wide adoption.
I have a client who has some legacy code that will no longer be approved for the App Store because of this incompatibility. I did not write the software by myself, and specifically have never touched this part of the code. I am not much of a ninja when it comes to low-level C networking.
I told the client that part of the problem was that they had an IPv4-only server and had us hardcode an IPv4 address to that server. I updated the IPv4 address to a domain name and told them their servers had to support IPv6. So, they moved them all over, and flipped the switch before any testing could be done. I was notified a few days ago that all their software on the store no longer worked. That's the predicament we are in.
Here is one of potentially many issues that I could use some help on.
Not only does the server that is connected to the port not respond to IPv6, but there are some lower level APIs that are being used that are incompatible.
The first thing I encountered is the use of gethostbyname(). Apparently this is not IPv6 capable. I have been trying to fix it with getaddrinfo() but my sockaddr's are not quite the same.
The second issue I can see is that apparently I need to be using AF_UNSPEC instead of AF_INET. So I am attempting to open a socket in the following way:
int sockfd = socket(AF_UNSPEC, SOCK_STREAM, 0);
I always get -1.
If I open a sock using AF_INET I get further, but then I have this issues:
otherAddr sockaddr * 0x618000220680 0x0000618000220680
sa_len __uint8_t '\x1c'
sa_family sa_family_t '\x1e'
sa_data char [14] "\x13\x88"
otherAddrCast sockaddr * 0x7000052d3c28 0x00007000052d3c28
sa_len __uint8_t '\0'
sa_family sa_family_t '\0'
sa_data char [14] "\x13\x88\"Ԛ\\"
So some of the sa_data is the same. and if I don't cast the sockaddr_in to a struct sockaddr* then the sa_data is the same.
Problem is I don't know what most of this means. Help?
EDIT: Here is my code. Assume that I am only getting 1 addr back (because I am)
struct hostent* server = gethostbyname([_hostname UTF8String]);
struct addrinfo *ai;
struct addrinfo hints;
memset(&hints, 0x00, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
NSString* portString = [NSString stringWithFormat:#"%d", _port];
getaddrinfo([_hostname UTF8String], [portString cStringUsingEncoding:kCFStringEncodingASCII] , &hints, &ai);
struct sockaddr_in addr = {0};
addr.sin_family = AF_INET;
bcopy(server->h_addr, &addr.sin_addr.s_addr, server->h_length);
addr.sin_port = htons(_port);
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
_addr = (struct sockaddr*)&addr;
int status = connect(sockfd, (struct sockaddr*)&addr, sizeof(addr));
int status2 = connect(socket(ai->ai_family,ai->ai_socktype,0), ai->ai_addr, ai->ai_addrlen);
You are NOT supposed to use AF_UNSPEC with socket() at all. You MUST use either AF_INET (IPv4) or AF_INET6 (IPv6).
You can use AF_UNSPEC with the hints input parameter of getaddrinfo() to indicate that you are willing to accept both IPv4 and IPv6 addresses as output. The actual addresses in the output will be either AF_INET or AF_INET6. Or, you can set the hints to AF_INET for IPv4-only output. Or AF_INET6 for IPv6-only output.
You are supposed to loop through the list that is returned by getaddrinfo(). For each address in the list:
pass its ai_family, ai_socktype, and ai_protocol fields to socket()
then pass its ai_addr and ai_addrlen fields to bind() (servers) or connect() (clients).
Repeat this for all addresses reported for a listening server, and for all addresses reported for a client until one successfully connects.
This way, each socket you create matches the IP version of the address it is working with, and you are passing an appropriate matching sockaddr_in (IPv4) or sockaddr_in6 (IPv6) to bind()/connect().
Once you have successful listening server socket(s), or a successfully connected client socket, if you need to retrieve an IP from a socket using accept(), getsockname() or getpeername(), be sure to pass it a sockaddr_storage struct to fill in. sockaddr_storage is large enough to hold all defined sockaddr-based structures (and there are many). If successful, you can then type-cast it to a sockaddr_in or sockaddr_in6 based on its sa_family field (AF_INET or AF_INET6, respectively). Same goes for other similar functions, like inet_pton() and inet_ntop().
Update: given the client code you have shown, try this instead:
struct addrinfo hints = {0};
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
NSString* portString = [NSString stringWithFormat:#"%d", _port];
struct addrinfo *ai;
int sockfd = -1;
int status = getaddrinfo([_hostname UTF8String], [portString cStringUsingEncoding:kCFStringEncodingASCII] , &hints, &ai);
if (status == 0) {
sockfd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
if (sockfd == -1) {
status = errno;
}
else if (connect(sockfd, ai->ai_addr, ai->ai_addrlen) < 0) {
status = errno;
close(sockfd);
sockfd = -1;
}
freeaddrinfo(ai);
}
if (sockfd == -1) {
// handle status error as needed...
}
else {
// use sockfd as needed...
close(sockfd);
}
I'm building a DNS client. A child process handles the request through an UDP socket, while the parent handles the reply. I need the parent to know how many bytes were sent, in order to print the URLs. I tried the following approach with pipe()
childPID = fork();
pipe(fd);
if(childPID == 0){
close(fd[0]);
sent_bytes = sendDNS(sock_udp, &serverAddr, argv[2]);
memcpy(in_buf, &sent_bytes, sizeof(sent_bytes));
write(fd[1], in_buf, sizeof(sent_bytes));
exit(0);
}
else{
close(fd[1]);
int inBytes = -1;
struct sockaddr reply_addr;
n = sizeof(reply_addr);
while(inBytes < 0){
inBytes = recvfrom(sock_udp, buffer, DNS_MAX_RESPONSE, 0, &reply_addr, (socklen_t*)&n);
read(fd[0], out_buf, sizeof(sent_bytes));
memcpy(pipe_msg, out_buf, sizeof(sent_bytes));
printDNSmsg((struct dnsReply*)buffer);
}
}
But GDB shows a SIGPIPE received on the child process. What am I missing?
How would you print a DNS reply (variable length buffer)?
You need to call pipe() before fork(), of course. But you're not actually using the information anywhere. Why do you care how many bytes were sent, as long as you got a reply? And why would you do a UDP send in a separate thread, let alone a separate process? It all seems completely pointless.
I have used the ICMP example provided in the ASIO documentation to create a simple ping utility. However, the example covers IPv4 only and I have a hard time to make it work with IPv6.
Upgrading the ICMP header class to support IPv6 requires a minor change - the only difference between ICMP and ICMPv6 header is the different enumeration of ICMP types. However, I have a problem computing the checksum that needs to be incorporated in the ICMPv6 header.
For IPv4 the checksum is based on the ICMP header and payload. However, for IPv6 the checksum should include the IPv6 pseudo-header before the ICMPv6 header and payload. The ICMPv6 checksum function needs to know the source and destination address that will be in the IPv6 header. However, we have no control over what goes into the IPv6 header. How can this be done in Asio-Boost?
For reference please find below the function for IPv4 checksum calculation.
void compute_checksum(icmp_header& header, Iterator body_begin, Iterator body_end)
{
unsigned int sum = (header.type() << 8) + header.code()
+ header.identifier() + header.sequence_number();
Iterator body_iter = body_begin;
while (body_iter != body_end)
{
sum += (static_cast<unsigned char>(*body_iter++) << 8);
if (body_iter != body_end)
sum += static_cast<unsigned char>(*body_iter++);
}
sum = (sum >> 16) + (sum & 0xFFFF);
sum += (sum >> 16);
header.checksum(static_cast<unsigned short>(~sum));
}
[EDIT]
What are the consequences if the checksum is not calculated correctly? Will the target host send echo reply if the echo request has invalid checksum?
If the checksum is incorrect, a typical IPv6 implementation will drop the packet. So, it is a serious issue.
If you insist on crafting the packet yourself, you'll have to do it
completely. This incldues finding the source IP address, to put it in
the pseudo-header before computing the checksum. Here is how I do it
in C, by calling connect() for my intended destination address
(even when I use UDP, so it should work for ICMP):
/* Get the source IP addresse chosen by the system (for verbose display, and
* for checksumming) */
if (connect(sd, destination->ai_addr, destination->ai_addrlen) < 0) {
fprintf(stderr, "Cannot connect the socket: %s\n", strerror(errno));
abort();
}
source = malloc(sizeof(struct addrinfo));
source->ai_addr = malloc(sizeof(struct sockaddr_storage));
source_len = sizeof(struct sockaddr_storage);
if (getsockname(sd, source->ai_addr, &source_len) < 0) {
fprintf(stderr, "Cannot getsockname: %s\n", strerror(errno));
abort();
}
then, later:
sockaddr6 = (struct sockaddr_in6 *) source->ai_addr;
op6.ip.ip6_src = sockaddr6->sin6_addr;
and:
op6.udp.check =
checksum6(op6.ip, op6.udp, (u_int8_t *) & message, messagesize);