-
-
Save marten-seemann/36a2558b48d060d063ecb3b005f47320 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <errno.h> | |
#include <string.h> | |
#include <sys/types.h> | |
#include <sys/socket.h> | |
#include <netinet/in.h> | |
#include <arpa/inet.h> | |
#include <linux/udp.h> | |
#include <unistd.h> | |
#define PORT 6121 | |
#define BUFFER_SIZE 4096 | |
ssize_t send_with_fallback(int sockfd, const struct sockaddr_in *addr, const char *buffer, size_t len) { | |
struct msghdr msg = {0}; | |
struct iovec iov = {(char *) buffer, len}; // Cast away the const | |
char cmsg_buffer[CMSG_SPACE(sizeof(uint16_t))]; | |
struct cmsghdr *cmsg; | |
msg.msg_name = (void *)addr; | |
msg.msg_namelen = sizeof(*addr); | |
msg.msg_iov = &iov; | |
msg.msg_iovlen = 1; | |
// GSO setup | |
msg.msg_control = cmsg_buffer; | |
msg.msg_controllen = sizeof(cmsg_buffer); | |
cmsg = CMSG_FIRSTHDR(&msg); | |
cmsg->cmsg_level = IPPROTO_UDP; | |
cmsg->cmsg_type = UDP_SEGMENT; | |
cmsg->cmsg_len = CMSG_LEN(sizeof(uint16_t)); | |
*(uint16_t *)CMSG_DATA(cmsg) = 6; // GSO segment size | |
printf("Sending with GSO...\n"); | |
ssize_t ret = sendmsg(sockfd, &msg, 0); | |
if (ret == -1 && errno == EIO) { | |
printf("GSO failed. Attempting without GSO...\n"); | |
msg.msg_control = NULL; | |
msg.msg_controllen = 0; | |
ret = sendmsg(sockfd, &msg, 0); | |
if (ret == -1) { | |
printf("Fallback also failed.\n"); | |
} | |
} else { | |
printf("Message sent with GSO.\n"); | |
} | |
return ret; | |
} | |
int main() { | |
int sockfd = socket(AF_INET, SOCK_DGRAM, 0); | |
if (sockfd == -1) { | |
perror("socket"); | |
return 1; | |
} | |
struct sockaddr_in local_address; | |
memset(&local_address, 0, sizeof(local_address)); | |
local_address.sin_family = AF_INET; | |
local_address.sin_port = htons(PORT); | |
local_address.sin_addr.s_addr = htonl(INADDR_ANY); | |
if (bind(sockfd, (struct sockaddr *)&local_address, sizeof(local_address)) == -1) { | |
perror("bind"); | |
close(sockfd); | |
return 1; | |
} | |
// If enabled, the fallback will NOT work. | |
// Comment these lines to make it work. | |
int val = 1; | |
if (setsockopt(sockfd, IPPROTO_UDP, UDP_SEGMENT, &val, sizeof(val)) < 0) { | |
perror("setsockopt UDP_SEGMENT"); | |
close(sockfd); | |
return 1; | |
} | |
// Send a message using GSO, with fallback | |
struct sockaddr_in remote_address; | |
memset(&remote_address, 0, sizeof(remote_address)); | |
remote_address.sin_family = AF_INET; | |
remote_address.sin_port = htons(PORT); | |
inet_pton(AF_INET, "8.8.8.8", &remote_address.sin_addr); | |
char buffer[BUFFER_SIZE] = "Hello, World!"; | |
if (send_with_fallback(sockfd, &remote_address, buffer, strlen(buffer)) == -1) { | |
perror("send_with_fallback"); | |
} | |
close(sockfd); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment