CFSocketSendData won't send Data? - sockets

I am a newbie to objective C networking. I have put together the code below for a simple WOL application. I can successfully create a socket, and then set an address (I only am able to set the local machine address but thats another question).
However when trying to send the data using CFSocketSendData, it does not send the data(Data not sent message displayed).
Am I using CFSocketSendData correctly, or is there a problem elsewhere?
Any help will be greatly appreciated, thanks.
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_len = sizeof(addr);
addr.sin_family = AF_INET;
addr.sin_port = htons(PORT); //port
inet_aton(IP, &addr.sin_addr);//IP is the network IP of the machine e.g 192.168.0.2
NSData *address = [NSData dataWithBytes: &addr length: sizeof(addr)];
if (CFSocketSetAddress(WOLsocket, (CFDataRef)address) != kCFSocketSuccess){
NSLog(#"Address could not be set!");
}
else{
NSLog(#"Address set");
char ethadd []= "helloworld";
CFDataRef Data = CFDataCreate(NULL, (const UInt8*)ethadd, sizeof(ethadd));
if (CFSocketSendData(WOLsocket, NULL, Data, 0) < 0){
NSLog(#"Data could not be sent!");
}
else NSLog(#"Data Sent");
}

You didn't include the CFSocketCreate(...) code in your snippet, but I assume that you chose the defaults, the PF_INET family and the TCP protocol.
With the TCP protocol, setting the address is not enough, you need to establish a
connection to your destination endpoint.
First call the function...
CFSocketConnectToAddress (WOLsocket, address, 10.0);
then send your data...
CFSocketSendData(WOLsocket, NULL, Data, 0)

Related

Sending Large files using TCP

My client program needs to send a large file to the server program. After the client connects to the server and the server accepts it, the clients specifies the name of the file which it would be sending. Now, the client needs to send the file using TCP.
I know that if the size of the file is small (less than 1k bytes?), I can send it directly using a single call to the "send" function in socket programming. However, does the same work if my file size is large, say about 100 MB? I want to know does "send" by itself handle the task of breaking the large data into packets and sending them reliably or should I be the one handling this?
Thanks.
I am trying something similar & My client code looks like this
static void send_file(char *ipAddress, char *filename)
{
struct sockaddr_in serverAddr;
int skt;
uint32_t addr_size;
uint32_t sz;
int32_t sent_bytes;
FILE *fp;
if ( inet_pton(AF_INET, ipAddress, &(serverAddr.sin_addr)) ){
skt = socket(PF_INET, SOCK_STREAM, 0);
serverAddr.sin_family = AF_INET;
}
else {
inet_pton(AF_INET6, ipAddress, &(serverAddr.sin_addr));
skt = socket(PF_INET6, SOCK_STREAM, 0);
serverAddr.sin_family = AF_INET6;
}
serverAddr.sin_port = htons(7891);
memset(serverAddr.sin_zero, '\0', sizeof(serverAddr.sin_zero));
addr_size = sizeof(serverAddr);
connect(skt, (struct sockaddr *) &serverAddr, addr_size);
/*find file size*/
fp = fopen(filename, "r");
fseek(fp,0,SEEK_END);
sz = ftell(fp);
rewind(fp);
sent_bytes = send(skt, fp, sz, 0);
printf("sent %d bytes\n", sent_bytes);
fclose(fp);
}

Retrieving source address in a recvmmsg UDP socket

I am receiving multiple messages through a socket using:
result = recvmmsg(socket_, &messages_[0], MAX_NUM_MSG, MSG_WAITFORONE, NULL);
And I want get the source address and port, but I am getting an error in the struct assignment when I try:
msg = &messages_[0];
***struct sockaddr *src = &msg->msg_hdr.msg_name;***
srcport = ntohs(src->sin_port);
srcaddr = ntohl(src->sin_addr.s_addr);
invalid conversion from ‘void**’ to ‘sockaddr*'
The recvmmsg system call is an extension of recvmsg. As described in recvmsg: The msg_name field points to a caller-allocated buffer that is used to return the source address
That means you should preallocate memory space for msg_name by yourself, and also you should specify msg_namelen, please try:
sockaddr_in addrs[MAX_NUM_MSG];
for (int i = 0; i < MAX_NUM_MSG; ++i) {
messages_[i].msg_hdr.msg_name = &addrs[i];
messages_[i].msg_hdr.msg_namelen = sizeof(sockaddr_in);
}
So that you can access address when you have at least one message by doing (Remember to use sockaddr_in but not sockaddr):
struct sockaddr_in *src = messages_[0].msg_hdr.msg_name;

MSG_PROXY not working to provide/specify alternate addresses for transparent proxying

I'm trying to write a transparent proxy that translates arbitrary UDP packets to a custom protocol and back again. I'm trying to use transparent proxying to read the incoming UDP packets that need translation, and to write the outgoing UDP packets that have just been reverse-translated.
My setup for the socket I use for both flavors of UDP sockets is as follows:
static int
setup_clear_sock(uint16_t proxy_port)
{
struct sockaddr_in saddr;
int sock;
int val = 1;
socklen_t ttllen = sizeof(std_ttl);
sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (sock < 0)
{
perror("Failed to create clear proxy socket");
return -1;
}
if (getsockopt(sock, IPPROTO_IP, IP_TTL, &std_ttl, &ttllen) < 0)
{
perror("Failed to read IP TTL option on clear proxy socket");
return -1;
}
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0)
{
perror("Failed to set reuse address option on clear socket");
return -1;
}
if (setsockopt(sock, IPPROTO_IP, IP_TRANSPARENT, &val, sizeof(val)) < 0)
{
perror("Failed to set transparent proxy option on clear socket");
return -1;
}
saddr.sin_family = AF_INET;
saddr.sin_port = htons(proxy_port);
saddr.sin_addr.s_addr = INADDR_ANY;
if (bind(sock, (struct sockaddr *) &saddr, sizeof(saddr)) < 0)
{
perror("Failed to bind local address to clear proxy socket");
return -1;
}
return sock;
}
I have two distinct, but possibly related problems. First, when I read an incoming UDP packet from this socket, using this code:
struct sock_double_addr_in
{
__SOCKADDR_COMMON (sin_);
in_port_t sin_port_a;
struct in_addr sin_addr_a;
sa_family_t sin_family_b;
in_port_t sin_port_b;
struct in_addr sin_addr_b;
unsigned char sin_zero[sizeof(struct sockaddr) - __SOCKADDR_COMMON_SIZE - 8
- sizeof(struct in_addr) - sizeof(in_port_t)];
};
void
handle_clear_sock(void)
{
ssize_t rcvlen;
uint16_t nbo_udp_len, coded_len;
struct sockaddr_in saddr;
struct sock_double_addr_in sdaddr;
bch_coding_context_t ctx;
socklen_t addrlen = sizeof(sdaddr);
rcvlen = recvfrom(sock_clear, &clear_buf, sizeof(clear_buf),
MSG_DONTWAIT | MSG_PROXY,
(struct sockaddr *) &sdaddr, &addrlen);
if (rcvlen < 0)
{
perror("Failed to receive a packet from clear socket");
return;
}
....
I don't see a destination address come back in sdaddr. The sin_family_b, sin_addr_b, and sin_port_b fields are all zero. I've done a block memory dump of the structure in gdb, and indeed the bytes are coming back zero from the kernel (it's not a bad placement of the field in my structure definition).
Temporarily working around this by hard-coding a fixed IP address and port for testing purposes, I can debug the rest of my proxy application until I get to the point of sending an outgoing UDP packet that has just been reverse-translated. That happens with this code:
....
udp_len = ntohs(clear_buf.u16[2]);
if (udp_len + 6 > decoded_len)
fprintf(stderr, "Decoded fewer bytes (%u) than outputting in clear "
"(6 + %u)!\n", decoded_len, udp_len);
sdaddr.sin_family = AF_INET;
sdaddr.sin_port_a = clear_buf.u16[0];
sdaddr.sin_addr_a.s_addr = coded_buf.u32[4];
sdaddr.sin_family_b = AF_INET;
sdaddr.sin_port_b = clear_buf.u16[1];
sdaddr.sin_addr_b.s_addr = coded_buf.u32[3];
if (sendto(sock_clear, &(clear_buf.u16[3]), udp_len, MSG_PROXY,
(struct sockaddr *) &sdaddr, sizeof(sdaddr)) < 0)
perror("Failed to send a packet on clear socket");
}
and the packet never shows up. I've checked the entire contents of the sdaddr structure I've built, and all fields look good. The UDP payload data looks good. There's no error coming back from the sendto() syscall -- indeed, it returns zero. And the packet never shows up in wireshark.
So what's going on with my transparent proxying? How do I get this to work? (FWIW: development host is a generic x86_64 ubuntu 14.04 LTS box.) Thanks!
Alright, so I've got half an answer.
It turns out if I just use a RAW IP socket, with the IP_HDRINCL option turned on, and build the outgoing UDP packet in userspace with a full IP header, the kernel will honor the non-local source address and send the packet that way.
I'm now using a third socket, sock_output, for that purpose, and decoded UDP packets are coming out correctly. (Interesting side note: the UDP checksum field must either be zero, or the correct checksum value. Anything else causes the kernel to silently drop the packet, and you'll never see it go out. The kernel won't fill in the proper checksum for you if you zero it out, but if you specify it, it will verify that it's correct. No sending UDP with intentionally bad checksums this way.)
So the first half of the question remains: when I read a packet from sock_clear with the MSG_PROXY flag to recvfrom(), why do I not get the actual destination address in the second half of sdaddr?

iOS timeout of ping and ttl

I want make ping with timeout and TTL. I use code by Apple ("Simple Ping"). I read it
"iOS ping with timeout". I change code:
CFSocketNativeHandle sock = CFSocketGetNative(self->_socket);
struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = 100000; // 0.1 sec
setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (void *)&tv, sizeof(tv));
bytesSent = sendto(
sock,
[packet bytes],
[packet length],
0,
(struct sockaddr *) [self.hostAddress bytes],
(socklen_t) [self.hostAddress length]
);
But I don't understand where I should put code that will show me timeout of receiving packets. Also I need to make ping with TTL (time-to-live) information. I want get information based on this pattern: icmp_seq=count from=ip_address ttl=value_of_ttl time=value_of_replytime_ms
To modify the default TTL in the IP Header, call setsockopt with IP_TTL as parameter (tested with IPv4):
- (BOOL)setTTL:(int)ttl{
CFSocketNativeHandle sock = CFSocketGetNative(self->_socket);
int status = setsockopt(sock, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl));
if(status < 0)
{
return NO;
}
return YES;
}
The "iOS ping with timeout" example add a output timeout to the socket. From what I understand, it will timeout if the packet is not been sent by the socket within this period. I could be wrong, but I cannot find this "timeout" value from the ICMP header and IPv4 header (ICMP Packet format).
Here are the console log and request, response packet captured using apple's simple ping:
If you only want to know the response time of the ping, I guess you can track it yourself in the delegate methods. Get timestamps when "didSendPacket" and "didReceivePingResponsePacket" functions called and then compare the difference.
You can always put some limit time on the receivefrom:
tv.tv_sec = 0;
tv.tv_usec = 10000;
setsockopt(recv_sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv,sizeof(struct timeval));

local vs remote socket connections on iphone

I want to send OSC messages from iphone to another programme (max/msp) by creating and connecting to a udp socket. this works from the iphone simulator, i.e. when both apps are running on the same computer but not when i install the app on the phone itself.
I think the problem could be with specifying the IP of the remote computer. I am using the sockaddr_in struct to specify IP and port info. when i run the code in the simulator it is fine to specify the IP as INADDR_ANY:
sin_addr.s_addr = INADDR_ANY;
when i run it on the device i'm trying to convert my IP into a hexidecimal number and specifying that instead of INADDR_ANY. This doesn't work for either the simulator or the device.
The console shows that the the socket is connecting and sending data fine but the remote programme (max/msp) doesn't receive any data at all.
I have tried importing the right frameworks so that it should work on both device and simulator.
the full code follows:
import "UDPSocketCreate.h"
#implementation UDPSocketCreate
-(id)init
{
in_addr_t myAddress = 0xC0A80145;
if(self =[super init])
{
//addr is an instance variable of type struct sockaddr_in
memset(&addr, 0, sizeof(addr));
addr.sin_len = sizeof(addr);
addr.sin_family = PF_INET;
addr.sin_port = htons(3333);
addr.sin_addr.s_addr = myAddress;INADDR_ANY
connectAddr = CFDataCreate(NULL, (unsigned char *)&addr, sizeof(addr));
OSC_initBuffer(&myOSCBuff, sizeof(packetBuffer), packetBuffer);
NSString *address = #"/test";
const char *utf8Address = [address UTF8String];
int addressResult = OSC_writeAddress(&myOSCBuff, (char*)utf8Address);
}
return self;
}
CFSocketRef udpSocket;
// this method is called from app delegate after init
-(void)createUDPSocketRef
{
udpSocket = CFSocketCreate(NULL, PF_INET, SOCK_DGRAM, IPPROTO_UDP, kCFSocketWriteCallBack, myCallBack, NULL);
if(udpSocket == NULL)
{
NSLog(#"socket create failed");
return;
}
CFRunLoopSourceRef runLoopSrceRef = CFSocketCreateRunLoopSource(NULL, udpSocket, 1);
CFRunLoopRef rl = CFRunLoopGetCurrent();
CFRunLoopAddSource(rl, runLoopSrceRef, kCFRunLoopCommonModes);
}
// pressing a button on the UI triggers this method
-(void)bang
{
int myInt = 1;
int writeRestult = OSC_writeIntArg(&myOSCBuff, myInt);
int buffDoneResult;
if (buffDoneResult = OSC_isBufferDone(&myOSCBuff))
{
NSLog(#"valid message in buff");
char *pack = OSC_getPacket(&myOSCBuff);
int packSize = OSC_packetSize(&myOSCBuff);
CFDataRef OSCPacketWithAddressTest = CFDataCreate(NULL, pack, packSize);
CFSocketError sendError = CFSocketSendData(udpSocket, connectAddr, OSCPacketWithAddressTest, 30);
NSLog(#"send error: %d", sendError);
}
OSC_resetBuffer(&myOSCBuff);
NSString *address = #"/test";
const char *utf8Address = [address UTF8String];
int addressResult = OSC_writeAddress(&myOSCBuff, (char*)utf8Address);
}
#end
any help would be greatly appreciated
Change;
in_addr_t myAddress = 0xC0A80145
to
in_addr_t myAddress = inet_addr("192.168.1.2");
or whatever that IP is.
S.
Unless I misunderstood you are trying to connect with INADDR_ANY as server address. INADDR_ANY is only for listening server to tell the IP stack that it wants to listen on any network interface (versus a specific interface on a multi-homed machine.) The client needs explicit server address of the server to send packets to. Look into inet_pton function for how to convert IP address from character string to network representation.