socket 'listen' error in C - sockets

i'm trying to create server with TCP IP protocol
But it doesn't accept connection, or may be because of listen
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <netdb.h>
#include <strings.h>
#include <arpa/inet.h>
#include <unistd.h>
void error(char *msg)
{
perror(msg);
exit(1);
}
int main(int argc, char *argv[])
{
int sockfd,newsockfd,num_port,serveur_T;
socklen_t client_T;
char buffer[200];
struct sockaddr_in adr_serveur, adr_client;
int n;
if (argc < 2)
{
fprintf(stderr, "nombre d'arguments est insuffisant\n");
exit(1);
}
sockfd=socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd < 0)
{
error("erreur de creation de socket");
}
serveur_T=sizeof(adr_serveur);
bzero((char*)&adr_serveur, serveur_T);
num_port=atoi(argv[1]);
adr_serveur.sin_family=AF_INET;
adr_serveur.sin_addr.s_addr=INADDR_ANY;
adr_serveur.sin_port=htons(num_port);
serveur_T=sizeof(adr_serveur);
if (bind ( sockfd,(struct sockaddr *) &adr_serveur,serveur_T)<0)
{
error(" Erreur de binding");
}
listen (sockfd,5);
client_T= sizeof(adr_client);
newsockfd= accept(sockfd,(struct sockaddr *) &adr_client,&client_T);
if ( newsockfd<0)
{
error("Erreur socket accept");
}
bzero(buffer, 200);
return 0;}
When I execute server I got this error
Erreur socket accept: Operation not supported
Second question: Can I use an IRC client and connect it to my server ? In my school we have Linux servers so I'm wondering if I can use them as a hostname ?
Thanks

i'm trying to create server with TCP IP protocol
You have created a SOCK_DGRAM (UDP) socket, not a SOCK_STREAM (TCP) socket. You cannot call listen() or accept() on a UDP socket, only on a TCP socket. listen() is reporting an EOPNOTSUPP error:
listen(2)
EOPNOTSUPP
The socket is not of a type that supports the listen() operation.
You are ignoring that error, and then accept() is reporting the same error:
accept(2)
EOPNOTSUPP
The referenced socket is not of type SOCK_STREAM.
There are no connections in UDP, so there is nothing to accept. Once you have bound a UDP socket to a port, you can start calling recvfrom() and sendto() on it.
In order to connect an IRC client to this server code, you need to change the socket type to SOCK_STREAM. IRC runs on TCP, not on UDP.

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.

systemd-activate socket activation for UDP daemons

I like using systemd-activate(8) for testing socket-activated daemons during development,
however, it seems it only listens for TCP connections:
% /usr/lib/systemd/systemd-activate -l 5700 ./prog
Listening on [::]:5700 as 3.
% netstat -nl |grep 5700
tcp6 0 0 :::5700 :::* LISTEN
I am using a program that handles datagrams (UDP). How can I make systemd-activate listen on a UDP port? Or is there a
simple way to do this using other tools, without going to the trouble of crafting and installing a systemd unit file?
This was recently added to systemd-activate: https://github.com/systemd/systemd/pull/2411, and will be part of systemd-229 when it is released.
I'm not sure that there is a way to do it with systemd-activate.
You may want to employ some .service unit file and a .socket unit file with dependencies. In a .socket unit you will describe ListenDatagram= option. See here for more details.
I ended up writing a simple C program to do this; code below (public domain).
The usage is:
./a.out <port-number> <prog> [<arg1> ...]
The program opens a UDP socket on <port-number>, sets the environment variables that systemd socket-activated daemons expect, then executes <prog> with whatever arguments follow.
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <netinet/in.h>
int main(int argc, char **argv) {
if (argc < 2) {
printf("no port specified\n");
return -1;
}
if (argc < 3) {
printf("no program specified\n");
return -1;
}
uint16_t port = htons((uint16_t) strtoul(argv[1], NULL, 10));
if (port == 0 || errno) {
printf("failed to parse port: %s\n", argv[1]);
return -1;
}
/* create datagram socket */
int fd = socket(AF_INET, SOCK_DGRAM, 0);
if (fd < 0) {
printf("failed to open socket; errno: %d\n", errno);
return -1;
}
struct sockaddr_in sa;
sa.sin_family = AF_INET;
sa.sin_port = port;
sa.sin_addr.s_addr = INADDR_ANY;
/* bind socket to port */
int r = bind(fd, (struct sockaddr *) &sa, sizeof(struct sockaddr_in));
if (r < 0) {
printf("bind failed; errno: %d\n", errno);
return -1;
}
/* execute subprocess */
setenv("LISTEN_FDS", "1", 0);
execvp(argv[2], argv + 2);
}

WINSOCK error 10022 on listen when include thread

I am implementing a simple multithreaded FTP client server where I am facing a problem which is strange for me( as I am no master in C++ and threads).
The code I have written works normally until I #include <thread>.
Once I include the thread class the program fails on listen and gives a 10022 error. (I haven't done anything related to threads yet, only import).
Below is the code. The method is called from main().
#include <winsock2.h>
#include <ws2tcpip.h>
#include <process.h>
#include <winsock.h>
#include <iostream>
#include <windows.h>
#include <fstream>
#include <string>
#include <stdio.h>
#include <time.h>
#include <thread>
using namespace std;
void initializeSockets()
{
try{
logEvents("SERVER", "Initializing the server");
WSADATA wsadata;
if (WSAStartup(0x0202,&wsadata)!=0){
cout<<"Error in starting WSAStartup()\n";
logEvents("SERVER", "Error in starting WSAStartup()");
}else{
logEvents("SERVER", "WSAStartup was suuccessful");
}
gethostname(localhost,20);
cout<<"hostname: "<<localhost<< endl;
if((hp=gethostbyname(localhost)) == NULL) {
cout << "gethostbyname() cannot get local host info?"
<< WSAGetLastError() << endl;
logEvents("SERVER", "Cannot get local host info. Exiting....");
exit(1);
}
//Create the server socket
if((serverSocket = socket(AF_INET,SOCK_STREAM,0))==INVALID_SOCKET)
throw "can't initialize socket";
//Fill-in Server Port and Address info.
serverSocketAddr.sin_family = AF_INET;
serverSocketAddr.sin_port = htons(port);
serverSocketAddr.sin_addr.s_addr = htonl(INADDR_ANY);
//Bind the server port
if (bind(serverSocket,(LPSOCKADDR)&serverSocketAddr,sizeof(serverSocketAddr)) == SOCKET_ERROR)
throw "can't bind the socket";
cout << "Bind was successful" << endl;
logEvents("SERVER", "Socket bound successfully.");
if(listen(serverSocket,10) == SOCKET_ERROR)
throw "couldn't set up listen on socket";
else
cout << "Listen was successful" << endl;
logEvents("SERVER", "Socket now listening...");
//Connection request accepted.
acceptUserConnections();
}
catch(char* desc)
{
cerr<<str<<WSAGetLastError()<<endl;
logEvents("SERVER", desc);
}
logEvents("SERVER", "Closing client socket...");
closesocket(clientSocket);
logEvents("SERVER", "Closed. \n Closing server socket...");
closesocket(serverSocket);
logEvents("SERVER", "Closed. Performing cleanup...");
WSACleanup();
}
int main(void){
initializeSockets();
return 0;
}
I have read the thread Winsock Error 10022 on Listen but I don't think that this has solution to my problem.
Error 10022 is WSAEINVAL. The documentation for listen() clearly states:
WSAEINVAL
The socket has not been bound with bind.
The reason your code stops working when you add #include <thread> is because your call to bind() is being altered to no longer call WinSock's bind() function, but to instead call the STL's std::bind() function. Your using namespace std statement is masking that issue (this is one of many reasons why using namespace std is such a bad practice - teach yourself to stop using that!).
So you need to either:
get rid of using namespace std.
qualify bind() with the global namespace so it calls WinSock's function:
if (::bind(...) == SOCKET_ERROR)

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().

how to bind a UDP socket to a range of port

I want to write a kernel thread for an application that will read all UDP packets. I am facing problem in binding as these packet can arrive in range of ports (say 5001 to 5005).
How to do this.
Any pointer/link will be helpful.
You can't bind a socket to more than one port, do as 0verbose suggested in a comment and use one socket per port
Besides opening multiple sockets, you need to use select()/poll() to listen to all sockets at once.
If you are programming in C/C++ under Linux, here is a pseudo-code in C:
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
...
int main()
{
fd_set afds;
fd_set rfds;
int maxfd = -1;
int fd, ret;
/* initialize fdsets */
FD_ZERO(&afds);
/* create a socket per port */
foreach (port p) {
fd = create_udp_socket(p); /* also bind to port p */
if (fd < 0) error_exit("error: socket()\n");
FD_SET(fd, &afds);
if (fd > maxfd) maxfd = fd;
}
while (1) {
memcpy(&rfds, &afds, sizeof(rfds));
/* wait for a packet from any port */
ret = select(maxfd + 1, &rfds, NULL, NULL, NULL);
if (ret < 0) error_exit("error: select()\n");
/* which socket that i received the packet */
for (fd=0; fd<=maxfd; ++fd)
if (FD_ISSET(fd, &rfds))
process_packet(fd); /* read the packet from socket fd */
}
}
Hope this code will help you