Cannot do network programming in XCode anymore - sockets

Until recently, the following code worked perfectly in my project. But since a few days ago, it no longer works. I can replace the NSLog statements with printf statements, replace the other Obj-C style statements and compile with g++ in terminal it works just fine.
It should just connect to a very primitive server on a Raspberry Pi, send a single character 'R', and read back a 2-Byte integer. When I compiled or ran it in XCode months ago it worked. When I compile now in terminal with g++ it works. When I run in XCode now, though, it fails to open the socket and reports setDAC: connection failed.
I fear I may be going insane. Did Apple hide some new setting I need to turn on network access in XCode 9.4.1? Any advice?
Previously functional code in XCode:
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include "stdio.h"
.
.
.
float readDAC(uint8_t ch){
if(!isConnected){
const char *servIP = [[txtIPAddress stringValue] UTF8String];
in_port_t servPort = 5001;
int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(sock < 0){
NSLog(#"setDAC: Socket creation failed\n");
ok = false;
}
struct sockaddr_in servAddr;
memset(&servAddr, 0, sizeof(servAddr));
servAddr.sin_family = AF_INET;
int rtnVal = inet_pton(AF_INET, servIP, &servAddr.sin_addr.s_addr);
if(ok){
if(rtnVal == 0){
NSLog(#"setDAC: inet_pton() failed: invalid address string\n");
ok = false;
}
else if (rtnVal < 0){
NSLog(#"setDAC: inet_pton() failed\n");
ok = false;
}
servAddr.sin_port = htons(servPort);
}
if(ok) if(connect(sock, (struct sockaddr *) &servAddr, sizeof(servAddr)) < 0){
NSLog(#"setDAC: connection failed\n");
ok = false;
}
datastream = fdopen(sock, "r+");
isConnected = true;
}
//send 'R' to read
//send 'W' to write
char writeChar = 'R';
if([AD5754 intValue]==1){
uint8_t writeChannel;
int16_t setVal;
float theVal;
uint8_t nDAC = 0;
if(ch>3) nDAC = 1;
ch = ch%4;
ch = 16*nDAC+ch;
writeChannel = ch;
fwrite(&writeChar, sizeof(writeChar), 1, datastream);
fwrite(&writeChannel, sizeof(writeChannel), 1, datastream);
fread(&setVal, sizeof(setVal), 1, datastream);
int16_t theSetVal;
theSetVal = ntohs(setVal);
theVal = (float)theSetVal/100;
NSLog(#"Read channel %i: %0.2f", ch, theVal);
fflush(datastream);
fclose(datastream);
return theVal;
}

I paid Apple the $99 annual fee to join the developer program and now the network coding works again. Not impressed with Apple, but ok.
I wouldn't mind paying to recover the functionality if it was documented or some notice was given. But I struggled for a few days before getting desperate enough to try throwing money at the problem, randomly.

Related

Epoll events(EPOLLLT) only triggered once on udp socket

From online resource, they said that if epoll listening on file descriptors using default mode(level trigger), when the fd(file descriptor) is ready to read and the buffer data associated with fd not fully consumed, epoll will continue to trigger until all data is consumed, however, when I test with epoll(LT mode) listening on udp socket, when multiple characters comes epoll only trigger once.
the process like below:
step 1: create epoll, udp socket fd, then make epoll listening on socket for write event.
step 2: send multiple characters("abc") to the udp socket
step 3: each time epoll triggered, then read 1 character from the udp socket.
I am expecting that epoll trigger three times as udp socket receive 3 characters, but the result is epoll only trigger once.
here is my code:
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/epoll.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <sys/errno.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#define BUFFER_SIZE 512
#define log(fmt, arg...) printf(""fmt, ##arg)
void main(){
int fd1,efd, fds, i, fd;
int ret, addr_len;
struct epoll_event g_event;
struct epoll_event *epoll_events_ptr;
char buffer[BUFFER_SIZE] = {0};
struct sockaddr_in addr1;
fd1 = socket(AF_INET, SOCK_DGRAM, 0);
if (fd1 == -1) {
log("create socket fail \r\n");
return ;
}
addr1.sin_family = AF_INET;
addr1.sin_addr.s_addr = INADDR_ANY;
addr1.sin_port = htons(3500);
addr_len = sizeof(struct sockaddr_in);
if (0 != bind(fd1, (struct sockaddr *)&addr1, sizeof(struct sockaddr_in))) {
log("bind local listening addr fail,errno : %d \r\n", errno);
goto err;
}
efd = epoll_create1(0);
if (efd == -1) {
log("create epoll fail \r\n");
goto err;
}
log("create epoll instance success \r\n");
epoll_events_ptr = (struct epoll_event *)calloc(2, sizeof(struct epoll_event));
if (epoll_events_ptr == NULL) {
log("calloc fail \r\n");
goto err;
}
g_event.data.fd = fd1;
g_event.events = EPOLLIN;
epoll_ctl(efd, EPOLL_CTL_ADD, fd1, &g_event);
while(1) {
fds = epoll_wait(efd, epoll_events_ptr, 2, -1);
for (i = 0; i<fds; i++)
{
if (epoll_events_ptr[i].events & EPOLLIN)
{
ret = recv(fd1, buffer, 1, MSG_DONTWAIT);
if(ret != -1)
log("recv msg : %s \n", buffer);
}
memset(buffer, 0, BUFFER_SIZE);
}
}
err:
close(fd1);
if(epoll_events_ptr)
free(epoll_events_ptr);
return ;
}
enter image description here
You are treating UDP as though it was a streaming protocol, i.e. TCP. It isn't. It is a datagram protocol. If you read a UDP datagram into a buffer that is too small to receive it, the remainder of the datagram is discarded. Not left in the buffer for next time.
Reading one character at a time is therefore pointless in UDP, not to mention extremely inefficient in any protocol.
NB You don't need the memset(), and this:
log("recv msg : %s \n", buffer);
is invalid. It should be:
log("recv msg : %.*s \n", ret, buffer);
You can't assume the received data is null-terminated.

Calling setsockopt many times

I have application which uses sockets to transfer data between two clients. It uses a single socket to communicate control and data traffic (over UDP).
Qos and tos fields of IP header can be changed using
setsockopt(sockfd, IPPROTO_IP, IP_TOS, &tos, toslen);
setsockopt(sockfd, SOL_SOCKET, SO_PRIORITY, &cos, coslen);
But how many calls to setsockopt (to the same socket) is too many?
For example, lets assume it will be called every 1ms.
To narrow question scope, I am asking about modern linux system (generic explanation is more than welcomed).
Here is an example to demonstrate it (this is the sending-only part of the application):
#include <stdlib.h>
#include <memory.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#define NPACK 10000
#define PORT 44444
#define BUFLEN 128
void diep(char *s) {
perror(s);
exit(1);
}
#define SRV_IP "12.34.56.78"
int main(void) {
struct sockaddr_in si_other, si_me;
int s, i, slen = sizeof(si_other);
int toss[2] = { 56, 160 }, coss[] = { 1, 3 };
char buf[BUFLEN];
//Create UDP socket
if ((s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
diep("socket");
//Create remote socket
memset((char *) &si_other, 0, sizeof(si_other));
si_other.sin_family = AF_INET;
si_other.sin_port = htons(PORT);
if (inet_aton(SRV_IP, &si_other.sin_addr) == 0) {
fprintf(stderr, "inet_aton() failed\n");
exit(1);
}
//Create local socket and bind to it.
memset((char *) &si_me, 0, sizeof(si_me));
si_me.sin_family = AF_INET;
si_me.sin_port = htons(PORT);
si_me.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(s, &si_me, sizeof(si_me)) == -1)
diep("bind");
//Loop on number of packets
for (i = 0; i < NPACK; i++) {
sprintf(buf, "This is packet %d, %d\n", i, toss[i % 2]);
printf("Sending packet %d. %s", i, buf);
//Change tos and cos. odd packets high priority , even packets low priority.
setsockopt(s, IPPROTO_IP, IP_TOS, &toss[i % 2], sizeof(int));
setsockopt(s, SOL_SOCKET, SO_PRIORITY, &coss[i % 2], sizeof(int));
//Send!
if (sendto(s, buf, strlen(buf), 0, &si_other, slen) == -1)
diep("sendto()");
}
close(s);
return 0;
}
NOTES:
Both control and data should share the same socket (same UDP source port).
Multiple threads will use the same socket (so some locking mechanism needed between setsockopt and sendto; but this is outside the scope of the question).
SO_PRIORITY is linux only.

How to find Address already in use?

This is my code which can run CentOS and Windows just fixing some headers.
#define _WIN32_WINNT 0x0501
#include <WinSock2.h>
#include <WS2tcpip.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
/*
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
*/
int main()
{
int sock;
int ret = 0;
int port= 12345;
struct sockaddr_in addr;
char buf[1024];
WSADATA wsaData;
WSAStartup(MAKEWORD(2,2), &wsaData);
sock = socket(AF_INET, SOCK_STREAM, 0);
if(sock<0){
printf("socket() ret = %d : %s\n",ret,strerror(errno));
return ret;
}
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = INADDR_ANY;
ret = bind(sock, (struct sockaddr *)&addr, sizeof(addr));
if(ret<0){
printf("bind() ret = %d errno =%d : %s\n",ret,errno,strerror(errno));
return ret;
}
printf("############# Binding port %d type Enter to stop \t",port);
fgets(buf,sizeof(buf),stdin);
return 0;
}
When I tried to bind same port by this program with runing tow process, there must be the messages that Address already in use like below.
[The first proc#centOS ]
$ ./udp
############# Binding port 12345 type Enter to stop
[The second proc#centOS]
$ ./udp
bind() ret = -1 errno =98 : Address already in use
$
However when I do same thing with same code on windows, message is different.
[The first proc#windows]
C:\ >udp
############# Binding port 12345 type Enter to stop
[The second proc#windows]
C:\ >udp
bind() ret = -1 errno =34 : Result too large
C:\ >
How can I get Address already in use on Windows?
I don't think you should use errno on windows for sockets code. You could try to use WSAGetLastError which returns WSAEADDRINUSE.
The MSDN page for errno suggests EADDRINUSE is not supported for errno.
I think you should devise a scheme where you have a my_errno function that depending on the platform uses errno or WSAGetLastError.
printf("socket() ret = %d : %s\n",ret,strerror(errno));
There may be a subtle issue with this call. The order of argument evaluation is unspecified and strerror itself can change errno, which means it has side-effects. You should print errno separately, before doing anything else.
Like cnicular said, you have to use WSAGetLastError() on Windows, not errno. To get a text message for a socket error code, you can use FormatMessage().
To answer your question, if you want to find out who is using the port, you can use the command-line netstat tool, or programmably using GetTcpTable2().

'sendto()' function won't send data to an application on another computer

i wrote a client application in c using the posix sockets api on linux that sends information to a server, which then gets printed to the servers terminal window. If the server is on the same machine as the client and the client sends to the loopback or to its own IP address then all is good. However, if the server is running on another machine, then sendto returns an "invalid argument" error.
Here is the code for the client application:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>
#include "utils.h" // for 'errexit()'
#define PEER_PORT 54321
#define BUFFSIZE 100
#define local_net_ip "192.168.0.10"
int main( int argc, char *argv[] )
{
int clientfd;
clientfd = socket( AF_INET, SOCK_DGRAM, 0 );
if( clientfd == -1 )
errexit( "socket()" );
struct sockaddr_in servaddr;
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons( PEER_PORT );
if( inet_pton( AF_INET, local_net_ip, (void *) &(servaddr.sin_addr) ) == -1 )
errexit( "inet_pton()" );
char addrStr[ INET_ADDRSTRLEN ];
inet_ntop( servaddr.sin_family, &(servaddr.sin_addr), addrStr, INET_ADDRSTRLEN );
printf("Server IPv4 addr: [ %s ]\n", addrStr);
char buff[ BUFFSIZE ];
int writebytes;
for( ;; ) {
printf( "Enter text: ");
fgets( buff, BUFFSIZE, stdin );
writebytes = sendto( clientfd, buff, BUFFSIZE, 0, (struct sockaddr *) &servaddr, sizeof( struct sockaddr_in ) );
if( writebytes == -1 )
errexit( "sendto()" );
}
exit( EXIT_SUCCESS );
}
I would greatly appreciate any information as to why the application won't send to another computer! Thanks in advance!!
clientfd = socket( AF_INET, SOCK_DGRAM, 0 );
You are creating a socket with protocol 0, e.g. IP. But later you use and IP:Port as a target. You probably wanted to use an UDP socket here (proto 17).

Why is Windows 7 firewall preventing PASV FTP connections?

I was trying to get CFtpServer's first example program running on a Windows 7 Pro, x64 system. After much beating around the bush and not believing what I was seeing, I got the problem down to the following simple program:
#include <iostream>
using namespace std;
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdio.h>
#define die(code) { cerr << "die at " << __FILE__ << " " << __LINE__ << " "; exit(code); }
int main(int argc, char **argv)
{
short port = 21;
if (argc == 2) {
port = atoi(argv[1]);
}
WSADATA WSAData;
if ( WSAStartup( MAKEWORD(2, 2), &WSAData) != 0)
die(1);
SOCKET ls = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);//!!! proto 0 in ftpdmin!
if (ls == INVALID_SOCKET) die(1);
struct sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = INADDR_ANY;
sin.sin_port = htons( port );
if (bind( ls, (struct sockaddr *) &sin, sizeof( struct sockaddr_in ) )
== SOCKET_ERROR) die(2);
if (listen( ls, 1 ) == SOCKET_ERROR ) //!!! backlog 1 in ftpdmin!
die(3);
// wait for connect, transmit till error
SOCKET ts;
for( ;; ) {
ts = accept( ls, NULL, NULL );
if (ts == INVALID_SOCKET) die(5);
// now write some things to that socket.
int i=0;
for(;;) {
char buf[256];
sprintf(buf, "%d Testing...\r\n",i+224);
if (send(ts, buf, strlen(buf), 0) < 0) {
DWORD err = WSAGetLastError();
cerr << "send failed with " << err << endl;
break;
}
Sleep(1000);
i = (i+1)%10;
}
Sleep(1000);
closesocket(ts);
}
}
This program opens the specified socket, listens on it for connections. When it gets a connection, it proceeds to write strings that bear a passing resemblance to the string an FTP server might use to respond to the PASV command. It will keep transmitting strings, once a second, until something goes wrong.
On my system, connecting to this 'server' using the nc.exe command, I see a few strings, then the socket will close (the error printed by the 'server' is 10053).
If I disabled the Windows firewall, I see strings as long as I care to leave the nc command running.
I've seen two different variations, and I don't know what causes the difference: Sometimes it would stop when it transmitted the string '227 ', later it started dying on '229 '. It's giving every appearance of being sensitive to the text being sent.
After 3 days of beating my head on this one, I have an answer: Window KB2754804. It's a bug, known to MS since somewhere in 2011. There is a Hotfix in the referenced Knowledge base article, but it doesn't seem to work for my tests, so I had to take the alternative route of disabling the Stateful FTP firewall.
I finally got to the KB article, from this SO entry.