I have used the linux part of code in windows to establish RDB communication. Though the socket opening is successful, I am unable to bind the socket with the IP Address defined. Is there any limitation between Linux and Windows over socket?
Here's my code,
SOCKET sock;
SOCKET sClient;
struct sockaddr_in server;
char szServer128; // Server to connect to
char szBuffer204800; // allocate on heap
sClient = udpsock_open(&server, szServer, DEFAULT_RX_PORT);
int udpsock_open(struct sockaddr_in *psa, char *ipv4, uint16_t port) {
WSADATA wsaData;
int opt;
int domain = AF_INET;
int type = SOCK_DGRAM;
int proto = IPPROTO_UDP;
sClient = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (sClient 0)
printf(" WSAStartup Successful %I64d\n", sClient);
else
printf("Failed. Error Code : %d\n", WSAGetLastError());
// Prepare a socket to listen for connections
if ((sock = WSASocket(domain, type, 0, NULL, 0, WSA_FLAG_OVERLAPPED)) INVALID_SOCKET)
{
printf("WSASocket() failed with error %d\n", WSAGetLastError());
return 1;
}
else
{
printf("WSASocket() is OK!\n");
}
if (sock < 0)
{
//rtos_log ( LOG_ERR, "Failed to open socket %m" );
printf("Failed to open socket %I64d\n", sock);
return -1;
}
set_reuse(sock);
memset(psa, 0x00, sizeof(struct sockaddr_in));
psa->sin_family = domain;
psa->sin_port = htons(port);
psa->sin_addr.s_addr = inet_addr(ipv4);
if (bind(sock, ( struct sockaddr *)psa, sizeof(struct sockaddr_in)) < 0)
{
printf("Failed to bind socket Error: %d\n", WSAGetLastError());
closesocket(sock);
WSACleanup();
return -4;
}
opt = 1;
char buf[2048];
DWORD dwBytesRet;
//ioctlsocket(sock, FIONBIO, &opt)
if (WSAIoctl(sock, SIO_ADDRESS_LIST_QUERY,NULL,0, buf,2048, &dwBytesRet,NULL,NULL) == SOCKET_ERROR)
{
printf("ioctlsocket() failed with error %d\n", WSAGetLastError());
return 1;
}
else
{
printf("ioctlsocket() is OK!\n");
}
return sock;
}
Related
I'm trying to run a simple C program which uses the bind() function to bind a IPv4/IPv6 address to a socket.
Below is the code:
int main(int argc, char *argv[])
{
int socket_fd = -1, addrlen = 0, af;
struct sockaddr_storage addr = {0};
unsigned connections = 0;
pthread_t workers[WORKER_NUM] = { 0 };
int client_sock_fds[WORKER_NUM] = { 0 };
char ip_string[64];
if (argc > 1 && strcmp(argv[1], "inet6") == 0) {
af = AF_INET6;
init_sockaddr_inet6((struct sockaddr_in6 *)&addr);
}
else {
af = AF_INET;
init_sockaddr_inet((struct sockaddr_in *)&addr);
}
printf("[Server] Create socket\n");
socket_fd = socket(af, SOCK_STREAM, 0);
if (socket_fd < 0) {
perror("Create socket failed");
goto fail;
}
printf("[Server] Bind socket\n");
addrlen = sizeof(addr);
if (bind(socket_fd, (struct sockaddr *)&addr, addrlen) < 0) {
perror("Bind failed");
goto fail;
}
printf("[Server] Listening on socket\n");
if (listen(socket_fd, 3) < 0) {
perror("Listen failed");
goto fail;
}
printf("[Server] Wait for clients to connect ..\n");
while (connections < WORKER_NUM) {
client_sock_fds[connections] =
accept(socket_fd, (struct sockaddr *)&addr, (socklen_t *)&addrlen);
if (client_sock_fds[connections] < 0) {
perror("Accept failed");
break;
}
if (sockaddr_to_string((struct sockaddr *)&addr, ip_string,
sizeof(ip_string) / sizeof(ip_string[0]))
!= 0) {
printf("[Server] failed to parse client address\n");
goto fail;
}
printf("[Server] Client connected (%s)\n", ip_string);
if (pthread_create(&workers[connections], NULL, run,
&client_sock_fds[connections])) {
perror("Create a worker thread failed");
shutdown(client_sock_fds[connections], SHUT_RDWR);
break;
}
connections++;
}
if (connections == WORKER_NUM) {
printf("[Server] Achieve maximum amount of connections\n");
}
for (int i = 0; i < WORKER_NUM; i++) {
pthread_join(workers[i], NULL);
}
printf("[Server] Shuting down ..\n");
shutdown(socket_fd, SHUT_RDWR);
sleep(3);
printf("[Server] BYE \n");
return EXIT_SUCCESS;
fail:
printf("[Server] Shuting down ..\n");
if (socket_fd >= 0)
close(socket_fd);
sleep(3);
return EXIT_FAILURE;
}
static void
init_sockaddr_inet(struct sockaddr_in *addr)
{
/* 0.0.0.0:1234 */
addr->sin_family = AF_INET;
addr->sin_port = htons(1234);
addr->sin_addr.s_addr = htonl(INADDR_ANY);
}
static void
init_sockaddr_inet6(struct sockaddr_in6 *addr)
{
/* [::]:1234 */
addr->sin6_family = AF_INET6;
addr->sin6_port = htons(1234);
addr->sin6_addr = in6addr_any;
}
When this program is compiled and run on Linux it works without any errors. But when the same program is compiled and run on MacOS, the bind() function returns an "Invalid Argument" error.
I checked the man page for the bind() function to see what the possible reasons for this error could be. The three possible reasons were:
The socket was already bound to another address
The addrlen value passed to the function is incorrect
The addr is not a valid address for this socket's domain
I was able to verify that it wasn't due to the first and third reason.
My question would be as to why does the addrlen value passed to the bind() function throw an "Incorrect argument" error when ran on a Unix system but works perfectly fine when ran on a Linux system?
The addrlen value you pass to bind() must exactly match the address family you specify in socket(). That means addrlen must be set to sizeof(sockaddr_in) for AF_INET, and sizeof(sockaddr_in6) for AF_INET6. Using sizeof(sockaddr_storage) is the wrong value, as sockaddr_storage is designed to be large enough to hold all possible sockaddr_... types, so its size may be larger than sockaddr_in6.
On the other hand, when calling accept(), you need to set addrlen to the full size of addr beforehand, so it knows how much memory it has to work with when writing the client's address to addr. addrlen will be adjusted to the actual size written. However, you can't simply type-cast an int* into a socklen_t*, so addrlen needs to be an actual socklen_t type. Besides, bind() is expecting a socklen_t anyway, not an int.
Try something more like this instead:
int main(int argc, char *argv[])
{
int socket_fd = -1, af;
socklen_t addrlen; // <-- add this!
struct sockaddr_storage addr = {0};
unsigned connections = 0;
pthread_t workers[WORKER_NUM] = { 0 };
int client_sock_fds[WORKER_NUM] = { 0 };
char ip_string[64];
if (argc > 1 && strcmp(argv[1], "inet6") == 0) {
af = AF_INET6;
addrlen = sizeof(struct sockaddr_in6); // <-- add this!
init_sockaddr_inet6((struct sockaddr_in6 *)&addr);
}
else {
af = AF_INET;
addrlen = sizeof(struct sockaddr_in); // <-- add this!
init_sockaddr_inet((struct sockaddr_in *)&addr);
}
printf("[Server] Create socket\n");
socket_fd = socket(af, SOCK_STREAM, 0);
if (socket_fd < 0) {
perror("Create socket failed");
goto fail;
}
printf("[Server] Bind socket\n");
if (bind(socket_fd, (struct sockaddr *)&addr, addrlen) < 0) {
perror("Bind failed");
goto fail;
}
printf("[Server] Listening on socket\n");
if (listen(socket_fd, 3) < 0) {
perror("Listen failed");
goto fail;
}
printf("[Server] Wait for clients to connect ..\n");
while (connections < WORKER_NUM) {
addrlen = sizeof(addr); // <-- add this!
client_sock_fds[connections] =
accept(socket_fd, (struct sockaddr *)&addr, &addrlen);
if (client_sock_fds[connections] < 0) {
perror("Accept failed");
break;
}
if (sockaddr_to_string((struct sockaddr *)&addr, ip_string,
sizeof(ip_string) / sizeof(ip_string[0])) != 0) {
printf("[Server] failed to parse client address\n");
goto fail;
}
printf("[Server] Client connected (%s)\n", ip_string);
if (pthread_create(&workers[connections], NULL, run,
&client_sock_fds[connections]) != 0) {
perror("Create a worker thread failed");
shutdown(client_sock_fds[connections], SHUT_RDWR);
break;
}
connections++;
}
if (connections == WORKER_NUM) {
printf("[Server] Achieve maximum amount of connections\n");
}
for (int i = 0; i < connections; i++) { // <-- needs to be the actual thread count, not WORKER_NUM!
pthread_join(workers[i], NULL);
}
printf("[Server] Shuting down ..\n");
shutdown(socket_fd, SHUT_RDWR);
sleep(3);
printf("[Server] BYE \n");
return EXIT_SUCCESS;
fail:
printf("[Server] Shuting down ..\n");
if (socket_fd >= 0)
close(socket_fd);
sleep(3);
return EXIT_FAILURE;
}
That being said, you should use getaddrinfo() instead to initialize the sockaddr_... that you pass to bind(). You should not be initializing it manually at all.
...
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
int main(int argc, char *argv[])
{
int socket_fd = -1, res;
...
struct addrinfo hints = { 0 };
struct addrinfo *addrs = NULL;
if (argc > 1 && strcmp(argv[1], "inet6") == 0)
hints.ai_family = AF_INET6;
else
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
hints.ai_flags = AI_PASSIVE;
printf("[Server] Initializing socket address\n");
res = getaddrinfo(NULL, "1234", &hints, &addrs);
if (res != 0) {
fprintf(stderr, "getaddrinfo failed: %s\n", gai_strerror(res));
goto fail;
}
printf("[Server] Create socket\n");
socket_fd = socket(addrs->ai_family, addrs->ai_socktype, addrs->ai_protocol);
if (socket_fd < 0) {
perror("Create socket failed");
freeaddrinfo(addrs);
goto fail;
}
printf("[Server] Bind socket\n");
if (bind(socket_fd, addrs->ai_addr, addrs->ai_addrlen) < 0) {
perror("Bind failed");
freeaddrinfo(addrs);
goto fail;
}
freeaddrinfo(addrs);
...
}
I try to use connect() & O_NONBLOCK to connect to a port in localhost asynchronously. In order to get the connect result, I use getsockopt to check the socket error status. I can sure no one listen to this port, so ECONNREFUSED should be returned. But in my test, this error may not be returned in some cases.
My test program:
int main() {
uint64_t p = 0;
while (1) {
int fd = ::socket(PF_INET, SOCK_STREAM, 0);
assert(fd > 0);
int flags = ::fcntl(fd, F_GETFL, 0);
flags |= O_NONBLOCK;
int ret = ::fcntl(fd, F_SETFL, flags);
assert(ret != -1);
sockaddr_in addr;
bzero(&addr, sizeof(sockaddr_in));
addr.sin_family = AF_INET;
addr.sin_port = htons(25400);
addr.sin_addr.s_addr = inet_addr("127.0.0.1");
ret = ::connect(fd, (sockaddr *)&addr, sizeof(sockaddr));
assert(ret != 0);
switch (errno) {
case EINPROGRESS:
case EINTR:
case EISCONN:
break;
default:
assert(false);
}
int epfd = epoll_create1(0);
assert(epfd > 0);
epoll_event ev;
ev.events = EPOLLOUT;
ev.data.fd = fd;
ret = epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev);
assert(ret == 0);
epoll_event events;
auto nfds = epoll_wait(epfd, &events, 1, -1);
assert(nfds == 1);
assert(events.data.fd == fd);
int err;
socklen_t optlen = static_cast<socklen_t>(sizeof err);
ret = ::getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &optlen);
assert(ret == 0);
assert(err != 0);
::close(fd);
::close(epfd);
if (p++ % 10000 == 0) {
std::cout << p << std::endl;
}
}
}
assert(err != 0); will be triggered.
In this test code, I use connect() without bind(), in this case, the source port is choosen by kernel. So the source port may be the same as destination port 25400. Due to the destination ip address is localhost, this TCP connection can be established in this case.
Hi I'm trying to write a client application which will try to connect a remote server. If it can not connect to the server, it will try once again after 5 seconds. If the socket is closed somehow, it will try to connect once again.
I'm getting an error like connect: Transport endpoint is already connected
What could be the problem ?
static void sig_chld(int signo)
{
pid_t pid;
int stat;
while ( (pid = waitpid(-1, &stat, WNOHANG)) > 0)
printf("child %d terminated\n", pid);
return;
}
int main(int argc, char *argv[])
{
int sockfd, numbytes;
char buf[MAXDATASIZE];
pid_t childpid;
struct hostent *he;
struct sockaddr_in their_addr; /* connector's address information */
if ((he=gethostbyname(argv[1])) == NULL) { /* get the host info */
herror("gethostbyname");
exit(1);
}
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
perror("socket");
exit(1);
}
their_addr.sin_family = AF_INET; /* host byte order */
their_addr.sin_port = htons(PORT); /* short, network byte order */
their_addr.sin_addr = *((struct in_addr *)he->h_addr);
bzero(&(their_addr.sin_zero), 8); /* zero the rest of the struct */
for ( ; ; ) {
while (connect(sockfd, (struct sockaddr *)&their_addr, sizeof(struct sockaddr)) == -1)
{
perror("connect");
sleep(5);
}
if ( (childpid = fork()) == 0)
{ /* child process */
while(1)
{
if (send(sockfd, "Hello, world!\n", 14, 0) == -1)
{
perror("send");
}
sleep(3);
}
close(sockfd);
}
}
return 0;
}
You can't reconnect a socket once you have even tried to connect it before, even if it failed. You have to close it and create a new one.
I use netlink to receive an interrupt number from kernel. The application in user space uses libevent to handle TCP/IP request and netlink message. Does libevent support Linux netlink socket? I will appreciate for a simple example.
Yes, libevent supports netlink socket.
There is https://github.com/libevent/libevent/blob/master/sample/hello-world.c, it is modified below to listen to netlink socket.
The basic example listens to Linux network interface creation/deletion and can be executed with sudo to gain privilege needed. It listens to same events as ip monitor link.
Another example of listening to RAW sockets with libevent is here https://github.com/bodgit/libevent-natpmp/blob/master/natpmp.c.
static void link_recvmsg(int fd, short event, void *arg)
{
char buf[NLMSG_SPACE(BUF_SIZE)] = {0};
socklen_t socklen;
struct iovec iov = {.iov_base = buf, .iov_len = sizeof(buf)};
struct sockaddr addr;
memset(&addr, 0, sizeof(struct sockaddr));
if (!fd || -1 == fd)
return;
int status = getsockname(fd, &addr, &socklen);
if(-1 == status)
return;
struct msghdr mh = {.msg_name = NULL, .msg_namelen = 0, .msg_iov = &iov, .msg_iovlen = 1,
.msg_flags = 0, .msg_name = &addr, .msg_namelen = sizeof(struct sockaddr)};
status = recvmsg(fd, &mh, 0);
if ((-1 == status) && ((EINTR == errno) || (EAGAIN == errno)))
return;
if(-1 == status)
return;
if ((mh.msg_flags & MSG_TRUNC) == MSG_TRUNC)
return;
if ((mh.msg_flags & MSG_CTRUNC) == MSG_CTRUNC)
return;
for (const struct nlmsghdr *h = (struct nlmsghdr *)buf; NLMSG_OK(h, status); h = NLMSG_NEXT(h, status)) {
switch (h->nlmsg_type) {
case RTM_NEWLINK:
fprintf(stderr, "got RTM_NEWLINK\n");
break;
case RTM_DELLINK:
fprintf(stderr, "got RTM_DELLINK\n");
break;
default:
fprintf(stderr, "unexpected case in swtch statement\n");
break;
}
}
}
int main(int argc, char **argv)
{
/* some init code here */
/* NETLINK socket */
int status;
int buf_size = BUF_SIZE;
struct sockaddr_nl src_addr;
int socket_nl = socket(AF_NETLINK, SOCK_RAW | SOCK_NONBLOCK, NETLINK_ROUTE);
if(-1 == socket_nl) return -1;
memset(&src_addr, 0, sizeof(struct sockaddr_nl));
src_addr.nl_family = AF_NETLINK;
src_addr.nl_pid = getpid();
src_addr.nl_groups |= RTNLGRP_LINK;
status = setsockopt(socket_nl, SOL_SOCKET, SO_RCVBUF,
&buf_size, sizeof(buf_size));
if(-1 == status) return -1;
status = bind(socket_nl, (struct sockaddr *)&src_addr, sizeof(struct sockaddr_nl));
if(status < 0) return -1;
static struct event nl_ev;
event_set(&nl_ev, socket_nl, EV_READ|EV_PERSIST, link_recvmsg,
NULL);
if (base) {
event_base_set(base, &nl_ev);
}
event_add(&nl_ev, NULL);
/* some other code, dispatch event and deinit */
}
I want to read and write over Wanpipe driver (a network device driver for Sangoma cards) via socket programming but i get this message error: "resource temporarily unavailable". The card is working and i see it send and receive packets in ifconfig. I have included my code and would be very pleased if somebody help me in this.
A related question: I set the socket to blocking mode but the recv message does not block? how could i block the recv?
int main(void)
{
int sd;
int buflen=WP_HEADER + MAX_PACKET;
char buf[buflen];
struct wan_sockaddr_ll sa;
sd = socket(AF_WANPIPE, SOCK_RAW,0);
if (sd < 0) /* if socket failed to initialize, exit */
{
perror("Error Creating Socket");
exit(1);
}
printf("Socket Descriptor:%d\n",sd);
memset(&sa,0,sizeof(struct wan_sockaddr_ll));
strncpy((char*)sa.sll_card,"wanpipe1",sizeof(sa.sl l_card));
strncpy((char*)sa.sll_device,"w1g1",sizeof(sa.sll_ device));
sa.sll_protocol = htons(PVC_PROT);
sa.sll_family = AF_WANPIPE;
if(bind(sd, (struct sockaddr *)&sa, sizeof(sa)) < 0)
{
perror("error bind failed");
close(sd);
exit(1);
}
int data=0;
int ret=ioctl(sd,FIONBIO,&data);
if (ret < 0)
{
perror("ioctl error!");
close(sd);
return 1;
}
fd_set read_fds;
struct timeval timeout;
timeout.tv_sec = 10;
timeout.tv_usec = 0;
FD_ZERO(&read_fds);
FD_SET(sd,&read_fds);
if(select(sd+1, &read_fds, NULL, NULL, &timeout) < 0)
{
perror("select() error!");
exit(1);
}
if (FD_ISSET(sd,&read_fds))
printf("There is data for reading\n");
else
printf("There is no data for reading\n");*/
// MSG_WAITALL | MSG_PEEK | MSG_OOB
int r=recv(sd,buf,buflen,0);
if (r < 0)
{
perror("Wanpipe raw socket reading");
close(sd);
exit(1);
}
printf("\nNumber of bytes read into the buffer: %d",r);
printf("\nThe read buffer: ");
puts(buf);
close(sd);
}
thank you in advance.