I had a simple TCP echo server with one thread per client (it works), so i tried to transform it into UDP but faced problem after running server:
"pthread_create() resource temporarily unavailable"
. Here is my server code:
#include <errno.h>
#include <netinet/in.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
#define PORT 1027
#define BACKLOG 5
#define MAXLINE 256
#define SA struct sockaddr
typedef struct serve_clientArg {
int socket;
SA *addr;
socklen_t addrlen;
} SCARGS;
void Pthread_create(pthread_t *thread, pthread_attr_t *attr,
void *(*start_routine)(void *), void *arg)
{
int rc;
rc = pthread_create(thread, attr, start_routine, arg);
if(rc) {
errno = rc;
error("pthread_create()");
}
}
reads() and writen() are using recvfrom() and sendto() functions
void *serve_client(void* arg)
{
char s[MAXLINE];
ssize_t rc;
SCARGS *args = Malloc(sizeof (SCARGS));
args = (SCARGS*) arg;
int socket = args->socket;
SA *addr = args->addr;
socklen_t addrlen = args->addrlen;
free(arg);
pthread_detach(pthread_self());
while((rc = reads(socket, s, MAXLINE, addr, &addrlen)) > 0) {
writen(socket, s, rc, addr, addrlen);
}
Close(socket);
return NULL;
}
int main(void)
{
int socket;
struct sockaddr_in servaddr;
struct sockaddr_in cliaddr;
SCARGS *arg;
pthread_t thread;
socket = Socket(AF_INET, SOCK_DGRAM, 0);
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(PORT);
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
Bind(socket, (SA *) &servaddr, sizeof(servaddr));
for(;;) {
arg = Malloc(sizeof (SCARGS));
arg->socket = socket;
arg->addr = (SA*) &cliaddr;
arg->addrlen = sizeof (cliaddr);
Pthread_create(&thread, NULL, serve_client, (void*) arg);
}
return 0;
}
I also had a TCP client and after transformation into UDP it works. I think i have done a stupid mistake, but i cant find it... Please help me find mistakes!
for(;;) {
arg = Malloc(sizeof (SCARGS));
arg->socket = socket;
arg->addr = (SA*) &cliaddr;
arg->addrlen = sizeof (cliaddr);
Pthread_create(&thread, NULL, serve_client, (void*) arg);
}
You allocate memory and create new threads inside an endless loop with no kind of blocking (as you might have done in TCP with accept). Therefore it quickly runs out of resources:
"pthread_create() resource temporarily unavailable"
Apart from that you use the same socket in all threads. But when you have only a single socket it does not really make sense to have multiple threads handling it. I'm not sure what you were trying to achieve with this design.
Related
So here is the code, code successfully compiles...
#include <stdio.h> // for printf
#include <linux/if_tun.h> //for IFF_TUN
#include <sys/socket.h> //socket, struct sockaddr_in
#include <fcntl.h> // for O_RDWR macros
#include <string.h> //for strcpy
#include <unistd.h> //for read();
#include <netdb.h> //for struct sockaddr
#include <net/if.h> //struct ifreq and IFNAMSIZ and other macros
#include <errno.h>
#include <stdlib.h>
// _check: error handler
static int _check(int retval, const char *msg)
{
if(retval == -1)
{
fprintf(stderr, "%s: %s\n", msg, strerror(errno));
exit(EXIT_FAILURE);
}
return retval;
}
int tcp_listen_sock(int listen_connection)
{
/*-------------------------socket-----------------------*/
int sock, tcp_sock;
struct addrinfo hints, *result;
struct sockaddr *addrin;
memset(&hints ,0 , sizeof(hints));
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
const char *host;
host = "0.0.0.0";
_check(getaddrinfo(host, NULL, &hints, &result), "getaddrinfo");
if (result->ai_family == AF_INET)
((struct sockaddr_in *)result->ai_addr)->sin_port = htons(5678);
else if (result->ai_family == AF_INET6)
((struct sockaddr_in6 *)result->ai_addr)->sin6_port = htons(5678);
else {
fprintf(stderr, "unknown ai_family %d", result->ai_family);
freeaddrinfo(result);
return -1;
}
memcpy(addrin, result->ai_addr, result->ai_addrlen);
// *client_len = result->ai_addrlen;
_check((sock = socket(AF_INET, SOCK_STREAM, 0)), "socket");
struct ifreq ifr;
memset(&ifr, 0, sizeof(ifr));
snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "enp0s3");
_check(setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, (void *)&ifr, sizeof(ifr)), "setsockopt");
int flags;
if((flags = fcntl(sock, F_GETFL)) != -1)
{
fcntl(sock, F_SETFL, flags | O_NONBLOCK);
}
else
perror("socket fcntl");
_check(bind(sock,result->ai_addr, result->ai_addrlen), "tcp bind");
int len = sizeof(struct sockaddr);
_check(listen(sock, listen_connection), "listen");
tcp_sock = accept(sock, result->ai_addr, &result->ai_addrlen );
printf("now listening on tcp!\n");
return tcp_sock;
}
int main(int argc, char **argv)
{
printf("Starting program\n");
int tcp = tcp_listen_sock(5);
printf("ending program\n");
return 0;
}
and ,
OUTPUT
Starting program
now listening on tcp!
ending program
but server socket is not actually listening...
expected output:
Starting program
now listening on tcp!
read...
write...
read...
write...
read...
write..
I can't figure our what I am missing, I know I didn't implemented read, write yet but I will do it after when server socket seems to working fine and listening properly.
NOTE: I am doing this in linux (specifically ubuntu)
Any help will be appreciated...
Calling getaddrinfo to initialize a local list socket seems like overkill.
Start with this. This is a simple "create a listen socket and wait for an incoming TCP connection" code sample.
int tcp_socket_listen(int listen_connection)
{
struct sockaddr_in addr = {0};
sockaddr_in addrRemote = {0};
socklen_t sizeRemote = 0;
int tcp_socket = -1;
s = socket(AF_INET, SOCK_STREAM, 0);
_check(s, "socket");
addr.sin_family = AF_INET;
addr.sin_port = htons(5678);
_check(bind(s, (sockaddr*)&addr, sizeof(addr)), "bind");
_check(listen(sock, listen_connection), "listen");
sizeRemote = sizeof(addrRemote);
tcp_sock = accept(s, (sockaddr*)&addrRemote, &sizeRemote);
_check(tcp_sock, "accept");
printf("now listening on TCP\n");
return tcp_sock;
}
Now if you want to bind to a specific adapter (e.g. "enp0s3") instead of the default ("all adapters") or need IPV6 support, you can peruse my sample code on github here for the GetSocketAddressForAdapter and use that address for the bind call instead of the default addr address above. It's C++, but you can probably port it to straight C with a little work.
I wrote a server program and a client program that communicate with sockets on linux ubuntu. The client program outputs Received: 艎��
This my server code:
/*** tcp_server.c ***/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
int main() {
int sock_fd, new_fd, bytes;
struct sockaddr_in seraddr, cliaddr;
char data[1024];
socklen_t cli_addr_size;
cli_addr_size = sizeof(cliaddr);
sock_fd = socket(AF_INET, SOCK_STREAM, 0);
memset(&seraddr, 0, sizeof(seraddr));
seraddr.sin_family = AF_INET;
seraddr.sin_addr.s_addr = htonl(INADDR_ANY); // INADDR_ANY : It received Network Interface that connected server defined interface, htonl :
seraddr.sin_port = htons(5050);
bind(sock_fd, (struct sockaddr *)&seraddr, sizeof(seraddr));
listen(sock_fd, 10);
while (1) {
new_fd = accept(sock_fd, (struct sockaddr *)&cliaddr, &cli_addr_size);
bytes = recv(new_fd, data, 1024, 0);
send(new_fd, data, bytes, 0);
close(new_fd);
}
close(sock_fd);
}
My client code is:
/*** tcp_client.c ***/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
int main(int argc, char *argv[]) {
int sock_fd, bytes;
struct sockaddr_in ser_addr;
char *snddata, rcvdata[1024];
snddata = argv[2];
sock_fd = socket(AF_INET, SOCK_STREAM, 0);
memset(&ser_addr, 0,sizeof(ser_addr));
ser_addr.sin_family = AF_INET;
ser_addr.sin_addr.s_addr = inet_addr(argv[1]); // INADDR_ANY : It received Network Interface that connected server defined interface, htonl :
ser_addr.sin_port = htons(5050);
connect(sock_fd, (struct sockaddr *)&ser_addr, sizeof(ser_addr));
send(sock_fd, snddata, strlen(snddata), 0);
printf("Received: ");
bytes = recv(sock_fd, rcvdata, 1024, 0);
rcvdata[bytes] = '\0';
printf("%s\n", rcvdata);
close(sock_fd);
}
First I got an error for argument 3 of accept, then I changed
new_fd = accept(sock_fd, (struct sockaddr *)&cliaddr, sizeof(cliaddr);
But It still produces this strange word.
Try to change your send() and receive() functions so that you have full control over how much and which byte you send from the buffer (data[1024]) like in this thread : C socket: recv and send all data and also see Beej's Guide to Network Programming (http://beej.us/guide/bgnet/)
Also make sure that you initialize your data buffers:
data[1024] = "";
rcvdata[1024] = "";
or
data[1024];
data[0] = '\0';
rcvdata[1024];
rcvdata[0] = '\0';
, background is in this thread : Why I am getting this unusually symbols by printing char string
Hello i have some problem with threads and client and server implementation, i created 2 clients that write on the socket infinite numbers.
to managed the 2 client in the sever.c i create threads everytime a new connection is accept.
it runs but if one client run it works but if i run the second one the first interrupted itself; how can i printf alternately ?
i would like : G1
G2
G1 etc
G1.
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <signal.h>
#include <time.h>
void error(char *msg)
{
perror(msg);
exit(0);
}
struct message { //dichiarazione struct
time_t timestamp;
char g; //process identifier
int x;
};
int main(int argc, char *argv[])
{
int sockfd, portno, n,i;
struct message m1;
struct sockaddr_in serv_addr;
struct hostent *server;
struct timespec delay;
delay.tv_sec = 1;
delay.tv_nsec = 0; //in microseconds
long int offset=1000000;
struct timeval tv;
char buffer[256];
if (argc < 3) {
fprintf(stderr,"usage %s hostname port\n", argv[0]);
exit(0);
}
portno = atoi(argv[2]);
sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
if (sockfd < 0)
error("ERROR opening socket");
server = gethostbyname(argv[1]);
if (server == NULL) {
fprintf(stderr,"ERROR, no such host\n");
exit(0);
}
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_UNIX;
bcopy((char *)server->h_addr,
(char *)&serv_addr.sin_addr.s_addr,
server->h_length);
serv_addr.sin_port = htons(portno);
if (connect(sockfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr)) < 0)
error("ERROR connecting");
while(1){
m1.timestamp=time(NULL);
m1.x=i;
m1.g=getpid();
n = write(sockfd,&m1,sizeof(m1));
if (n < 0)
error("ERROR writing to socket");
i++;
delay.tv_nsec=offset+rand()%offset;
nanosleep(&delay,NULL);
}
return 0;
}`
R.c(server)
#include<stdio.h>
#include<stdlib.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<string.h>
#include <arpa/inet.h>
#include <fcntl.h> // for open
#include <unistd.h> // for close
#include<pthread.h>
struct message { //dichiarazione struct
time_t timestamp;
char g; //process identifier
int x;
};
struct message client_message;
char buffer[1024];
static void * socketThread(void *arg)
{
while(1) {
int newSocket = *((int *)arg);
recv(newSocket , &client_message , sizeof(client_message), 0);
printf("message %d %d %ld\n",client_message.x,client_message.g,client_message.timestamp);
fflush(stdout);
sleep(1);
}
}
int main(){
int serverSocket, newSocket;
struct sockaddr_in serverAddr;
struct sockaddr_storage serverStorage;
socklen_t addr_size;
//Create the socket.
serverSocket = socket(AF_UNIX, SOCK_STREAM, 0);
// Configure settings of the server address struct
// Address family = Internet
serverAddr.sin_family = AF_UNIX;
//Set port number, using htons function to use proper byte order
serverAddr.sin_port = htons(6005);
//Set IP address to localhost
serverAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
//Set all bits of the padding field to 0
memset(serverAddr.sin_zero, '\0', sizeof serverAddr.sin_zero);
//Bind the address struct to the socket
bind(serverSocket, (struct sockaddr *) &serverAddr, sizeof(serverAddr));
//Listen on the socket, with 40 max connection requests queued
if(listen(serverSocket,50)!=0)
{
printf("Error\n");
return -1;
}
printf("Listening\n");
pthread_t tid[60];
int i = 0;
while(1)
{
//Accept call creates a new socket for the incoming connection
addr_size = sizeof serverStorage;
newSocket = accept(serverSocket, (struct sockaddr *) &serverStorage, &addr_size);
//for each client request creates a thread and assign the client request to it to process
//so the main thread can entertain next request
if( pthread_create(&tid[i], NULL, socketThread, &newSocket) != 0 )
printf("Failed to create thread\n");
else
++i;
}
return 0;
}
Thanks !
As I understand in server code in thread function socketThread() you get value of socket descriptor on each iteration. But when you accept new connection in this address writes new value of new socket descriptor. And after that each thread gets data only from last socket.
You should pass in socketThread() socket descriptor by value (not by a pointer)!
I'd like to know how I can bind a socket to a specific interface in C.
My #IP is X.Y.Z.3, the gateway is X.Y.Z.1 on eth1
But if I send my packet, it'll be send on the loopback interface.
The strange thing is, if I make my packet with X.Y.Z.9 (for example) as the IP SOURCE (instead of mine), it works.
Any clue?
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <string.h>
#include <netdb.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/time.h>
#define PCK_MAX_LEN 1024
#define IP_NAMESERV "172.20.10.1"
#define IP_ATTACKER "172.20.10.3"
#define PORT_QUERY 5555
pthread_cond_t ans_listen = PTHREAD_COND_INITIALIZER;
pthread_cond_t ans_receiv = PTHREAD_COND_INITIALIZER;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
void *fctThreadSendQuery (void *arg); // Send 1 query to random.example.com
void *fctThreadListenResponse (void *arg); // Listen for response to that query
int main (void)
{
pthread_t threadSendQuery;
pthread_t threadListenResponse;
pthread_create (&threadSendQuery, NULL, fctThreadSendQuery, NULL);
pthread_create (&threadListenResponse, NULL, fctThreadListenResponse, NULL);
pthread_join (threadListenResponse, NULL);
pthread_join (threadSendQuery, NULL);
return 0;
}
void *fctThreadSendQuery(void *arg) {
unsigned int nQuery = 1;
struct sockaddr_in *sin_attacker, *sin_resolver;
sin_attacker = calloc(1, sizeof(struct sockaddr_in));
sin_resolver = calloc(1, sizeof(struct sockaddr_in));
sin_attacker->sin_family = AF_INET;
sin_attacker->sin_addr.s_addr = inet_addr(IP_ATTACKER);
sin_attacker->sin_port = htons(PORT_QUERY);
int fd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
bind(fd, sin_attacker, sizeof(struct sockaddr_in));
sin_resolver->sin_family = AF_INET;
sin_resolver->sin_addr.s_addr = inet_addr(IP_RESOLVER);
sin_resolver->sin_port = htons(53);
while (1) {
// Now, we can build and send the query
char *packet = calloc(PCK_MAX_LEN, sizeof(char));
int pck_len = 0;
int id = 0;
char *target = calloc(16, sizeof(char));
strcpy(target, randomTarget(nQuery-1));
build_packet(IP_SRC, IP_DST, PORT_QUERY, 53, packet, &pck_len, target, NAME_LEN, id, QUERY);
// Before sending the packet, we want to be sure that fctThreadListenResponse is listening
pthread_mutex_lock (&mutex);
puts("SEND: wait for RECV to LISTEN");
pthread_cond_wait (&ans_listen, &mutex);
puts("SEND: wait for RECV to LISTEN - OK");
pthread_mutex_unlock(&mutex);
sendto (fd, packet, pck_len, 0, sin_attacker, sizeof(struct sockaddr_in));
puts("SEND: PCK SENT");
pthread_mutex_lock (&mutex);
puts("SEND: wait for RECV to RECV");
pthread_cond_wait (&ans_receiv, &mutex);
puts("SEND: wait for RECV to RECV - OK");
pthread_mutex_unlock(&mutex);
nQuery++;
free(target);
free(packet);
}
free(sin_resolver);
free(sin_attacker);
pthread_exit(NULL);
}
void *fctThreadListenResponse (void *arg) {
usleep(100);
struct sockaddr_in *sin_attacker, *sin_resolver;
sin_attacker = calloc(1, sizeof(struct sockaddr_in));
sin_resolver = calloc(1, sizeof(struct sockaddr_in));
sin_attacker->sin_family = AF_INET;
sin_attacker->sin_addr.s_addr = inet_addr(IP_ATTACKER);
sin_attacker->sin_port = htons(PORT_QUERY);
int fd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
bind(fd, sin_attacker, sizeof(struct sockaddr_in));
while (1) {
char *packet = calloc(PCK_MAX_LEN, sizeof(char));
unsigned int pck_len;
pthread_mutex_lock (&mutex);
pthread_cond_signal (&ans_listen);
puts("RECV: LISTENING");
pthread_mutex_unlock(&mutex);
pck_len = recvfrom(fd, packet, PCK_MAX_LEN, 0, NULL, sin_resolver);
puts("RECV: PCK RECEIVED");
if (pck_len > 0) {
pthread_mutex_lock (&mutex);
pthread_cond_signal (&ans_receiv);
pthread_mutex_unlock (&mutex);
}
free(packet);
}
pthread_exit(NULL);
}
I don't know what build_packet does, but the documentation for sendto lists only a few possible prototypes, of which only one has the parameter list you are using:
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
const struct sockaddr *dest_addr, socklen_t addrlen);
In your call you use:
sendto (fd, packet, pck_len, 0, sin_attacker, sizeof(struct sockaddr_in));
Where you have configured sin_attacker (the dest_addr parameter) using IP_ATTACKER, which seems to be your own address. Thus sendto sees a destination address that is hosted on the local system and sends the packet using the loopback adapter.
I am writing a TCP client in C.
Following several tutorial I wrote my code but it can accept only the first connection to the server.
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <arpa/inet.h> //inet_addr for INADDR_ANY
#include <string.h> //for splitting (strtok)
#include <pthread.h> //thread library
#include <time.h>
#include <unistd.h> //for function close()
void* SocketHandler(void*);
int main(void) {
//socket parameters
int server_socket_desc;
int clientAddressLength = sizeof(struct sockaddr_in);
struct sockaddr_in server_addr, client_addr;
const unsigned short int PORT_NUMBER = 8963;
server_socket_desc = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (server_socket_desc < -1) {
printf("Could not create socket");
}
puts("Socket created");
//Prepare the sockaddr_in structure
server_addr.sin_family = AF_INET; //it should be always set to AF_INET
//set the server address
server_addr.sin_addr.s_addr = inet_addr("192.168.123.240");
//server_addr.sin_addr.s_addr = inet_addr("31.185.101.35");
//server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
server_addr.sin_port = htons(PORT_NUMBER);
//Bind
if (bind(server_socket_desc, (struct sockaddr *) &server_addr,
sizeof(server_addr)) < 0) {
//print the error message
perror("bind failed. Error");
return 1;
}
puts("bind done");
//Listen
listen(server_socket_desc, 10);
//Accept and incoming connection
puts("Waiting for incoming connections...");
//accept connection from an incoming client
while (1) {
int *temp_socket_desc = (int*) malloc(sizeof(int));
if ((*temp_socket_desc = accept(server_socket_desc,
(struct sockaddr *) &client_addr,
(socklen_t*) &clientAddressLength)) != -1) {
printf("----------\nConnection accepted \n");
sleep(1);
pthread_t thread_id;
int *client_socket_desc = (int*) malloc(sizeof(int));
client_socket_desc = temp_socket_desc;
pthread_create(&thread_id, NULL, &SocketHandler,
(void*) client_socket_desc);
//if thread has not terminated, pthread_detach() shall not cause it to terminate
pthread_detach(thread_id);
puts("handler assigned");
} else
puts("connection refused");
}
close(server_socket_desc);
//mysql_close(mysql_conn);
return 0;
}
/*
* This will handle connection for each client
* */
void* SocketHandler(void* lp) {
int *csock = (int*) lp;
char buffer[128];
int buffer_len = 128;
int bytecount;
memset(buffer, 0, buffer_len);
if ((bytecount = read(*csock, buffer, buffer_len) == -1)) {
fprintf(stderr, "Error receiving data\n");
close(*csock);
return 0;
}
printf("Received bytes %d\nReceived string \"%s\"\n", bytecount, buffer);
close(*csock);
free(csock);
puts("exiting thread");
//pthread_exit(0);
return 0;
}
I temporally solved the problem inserting a sleep() after the while loop but it is a very bad solution.
Can somebody explain me why the code does'n work without the sleep?
There is a problem in handling of client_socket_desc:
You allocate it only once. All threads will get the same pointer.
So later accepts will override socket descriptors value of earlier threads.
Try the following change, for allocating own memory block for each thread:
int fd = accept( server_socket_desc, (struct sockaddr *) &client_addr, (socklen_t*)
&clientAddressLength)
if ( fd != -1 )
{
pthread_t thread_id;
int *client_socket_desc = malloc(sizeof(int));
*client_socket_desc = fd;
pthread_create(&thread_id, NULL, &SocketHandler,(void*) client_socket_desc);
...
Or course you must add error handlings for malloc and pthread_create.
And also free the allocated memory when not needed anymore.
I don't understood why there is the following code in the while loop:
if(send(*client_socket_desc,buffer,1,MSG_NOSIGNAL)>0)
{
puts("closing client socket");
close(*client_socket_desc);
}
Close client sockets in client handler threads.