Я думал, можно ли создать две розетки.
Один разъем типа DGRAM, используемый исключительно для отправки
Одна необработанная розетка, используемая исключительно для приема.
Поскольку вы используете UDP, вы можете вызвать bind + recvFrom на Raw Sock Fd, а затем вручную распаковать заголовок IP, чтобы определить TOS или TTL.
Если вы хотите отправить, используйте DGRAM sockFd, чтобы вам не пришлось создавать пакет UDP и IP самостоятельно.
Могут быть проблемы, такие как ядро может передавать полученный буфер в оба сокета или в сокет UDP вместо сокета Raw или просто в сокет Raw. Если это так (или если это зависит от реализации), то мы вернемся к исходной точке. Однако вы можете попробовать вызвать bind для сокета Raw и посмотреть, поможет ли это. Я знаю, что это может быть взлом, но поиск в сети для setsockopt для BSD ничего не дал.
РЕДАКТИРОВАТЬ : я написал пример программы
Это как бы достигает цели.
Код ниже создает два сокета (один raw и один udp). Сокет udp связан с реальным портом, на который я рассчитываю получать данные, тогда как сокет raw связан с портом 0. Я протестировал это на Linux и, как и ожидал, любые данные для порта 2905 будут получены обоими сокетами. Однако я могу получить значения TTL & TOS. Не понизьте качество кода. Я просто экспериментирую, будет ли это работать.
Дальнейшее редактирование: отключено получение через сокет UDP.
Я еще более усовершенствовал код, чтобы отключить прием по UDP-пакету. Используя setsockopt, я установил для буфера приема сокета UDP значение 0. Это гарантирует, что ядро не передает пакет в сокет UDP. ИМХО, теперь вы можете использовать UDP-сокет исключительно для отправки и необработанный сокет для чтения. Это должно работать для вас также в BSD и Solaris.
#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<netinet/ip.h>
#include<arpa/inet.h>
#include<string.h>
#include "protHeaders.x"
#include "gen.h"
int main(void)
{
S32 rawSockFd;
S32 udpSockFd;
struct sockaddr_in rsin;
struct sockaddr_in usin;
S32 one = 1;
const S32* val = &one;
struct timeval tv;
fd_set rfds;
S32 maxFd;
S16 ret;
S8 rawBuffer[2048];
S8 udpBuffer[2048];
struct sockaddr udpFrom,rawFrom;
socklen_t rLen,uLen;
memset(rawBuffer,0,sizeof(rawBuffer));
memset(udpBuffer,0,sizeof(udpBuffer));
memset(udpFrom,0,sizeof(udpFrom));
memset(rawFrom,0,sizeof(rawFrom));
if ((rawSockFd = socket(PF_INET,SOCK_RAW,IPPROTO_UDP)) < 0)
{
perror("socket:create");
RETVALUE(RFAILED);
}
/* doing the IP_HDRINCL call */
if (setsockopt(rawSockFd,IPPROTO_IP,IP_HDRINCL,val,sizeof(one)) < 0)
{
perror("Server:setsockopt");
RETVALUE(RFAILED);
}
rsin.sin_family = AF_INET;
rsin.sin_addr.s_addr = htonl(INADDR_ANY);
rsin.sin_port = htons(0);
usin.sin_family = AF_INET;
usin.sin_addr.s_addr = htons(INADDR_ANY);
usin.sin_port = htons(2905);
if(bind(rawSockFd,(struct sockaddr *)&rsin, sizeof(rsin)) < 0 )
{
perror("Server: bind failed");
RETVALUE(RFAILED);
}
if ((udpSockFd = socket(PF_INET,SOCK_DGRAM,IPPROTO_UDP)) < 0)
{
perror("socket:create");
RETVALUE(RFAILED);
}
if(bind(udpSockFd,(struct sockaddr *)&usin, sizeof(usin)) < 0 )
{
perror("Server: bind failed on udpsocket");
RETVALUE(RFAILED);
}
/*set upd socket receive buffer to 0 */
one = 0;
if (setsockopt(udpSockFd,SOL_SOCKET,SO_RCVBUF,(char *)&one,sizeof(one)) < 0)
{
perror("Server:setsockopt on udpsocket failed");
RETVALUE(RFAILED);
}
tv.tv_sec = 0;
tv.tv_usec = 0;
maxFd = (rawSockFd > udpSockFd)? rawSockFd:udpSockFd;
while(1)
{
FD_ZERO(&rfds);
FD_SET(rawSockFd,&rfds);
FD_SET(udpSockFd,&rfds);
ret = select(maxFd+1,&rfds,0,0,&tv);
if ( ret == -1)
{
perror("Select Failed");
RETVALUE(RFAILED);
}
if(FD_ISSET(rawSockFd,&rfds))
{
printf("Raw Socked Received Message\n");
if(recvfrom(rawSockFd,rawBuffer,sizeof(rawBuffer),0,&rawFrom,&rLen) == -1)
{
perror("Raw socket recvfrom failed");
RETVALUE(RFAILED);
}
/*print the tos */
printf("TOS:%x\n",*(rawBuffer+1));
printf("TTL:%x\n",*(rawBuffer+8));
}
if(FD_ISSET(udpSockFd,&rfds))
{
printf("UDP Socked Received Message\n");
if(recvfrom(udpSockFd,udpBuffer,sizeof(udpBuffer),0,&udpFrom,&uLen) == -1)
{
perror("Udp socket recvfrom failed");
RETVALUE(RFAILED);
}
printf("%s\n",udpBuffer);
}
}
RETVALUE(ROK);
}