Pass argc variable to thread - c

I'm creating a TCP socket-based server-client application for a roulette game. Before compiling the server, the admin needs to input two arguments for how the server should work: one for the port, and the other for the roulette's required time to spin. However, when I try to compile the code it gives me a segmentation fault error. The code works fine if all references to roulette_time are taken out, though.
#include <netinet/in.h>
#include <pthread.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include <semaphore.h>
#define BACKLOG 15
long bank = 0;
typedef struct pthread_arg_t{
int new_socket_fd;
struct sockaddr_in client_address;
int port;
int *roulette_time;
/*Inserire le variabili passate dal client qui*/
int picked_num;
long stake;
int won;
}pthread_arg_t;
void *pthread_routine(void *arg);
void signal_handler(int signal_number);
int main(int argc, char *argv[]){
int port, socket_fd, new_socket_fd, chosen_number, won, roulette_time;
long stake;
struct sockaddr_in address;
pthread_attr_t pthread_attr;
pthread_arg_t *pthread_arg;
pthread_t pthread;
socklen_t client_address_len;
port = atoi(argv[1]);
roulette_time = atoi(argv[2]);
if(port == NULL){
printf("Inserisci il port qui\n");
scanf("%d",&port);
}
if(roulette_time == NULL){
printf("Inserisci il tempo minimo da far trascorrere prima dell'azionamento della roulette\n");
scanf("%d",&roulette_time);
}
pthread_arg->roulette_time = &roulette_time;
memset(&address,0,sizeof(address));
address.sin_family = AF_INET;
address.sin_port = htons(port);
address.sin_addr.s_addr = INADDR_ANY;
if((socket_fd = socket(AF_INET,SOCK_STREAM,0)) == -1){
perror("creazione socket");
exit(1);
}
if(bind(socket_fd,(struct sockaddr*)&address, sizeof(address)) == -1){
perror("binding");
exit(1);
}
if(listen(socket_fd, BACKLOG) == -1){
perror("listen");
exit(1);
}
if((signal(SIGPIPE, SIG_IGN) == SIG_ERR) || (signal(SIGTERM, signal_handler) == SIG_ERR) || (signal(SIGINT, signal_handler) == SIG_ERR)){
perror("signal");
exit(1);
}
if(pthread_attr_init(&pthread_attr) != 0){
perror("pthread_attr_init");
exit(1);
}
if(pthread_attr_setdetachstate(&pthread_attr, PTHREAD_CREATE_DETACHED) != 0){
perror("pthread_attr_setdetachstate");
exit(1);
}
while(1){
pthread_arg = (pthread_arg_t *)malloc(sizeof *pthread_arg);
if(!pthread_arg){
perror("malloc");
continue;
}
client_address_len = sizeof(pthread_arg->client_address);
new_socket_fd = accept(socket_fd, (struct sockaddr *)&pthread_arg->client_address,&client_address_len);
if(new_socket_fd == -1){
perror("accept");
free(pthread_arg);
continue;
}
pthread_arg->new_socket_fd = new_socket_fd;
/*Inizializza tutte le variabili qui*/
chosen_number = pthread_arg->picked_num;
stake = pthread_arg->stake;
won = pthread_arg->won;
if(pthread_create(&pthread, &pthread_attr, pthread_routine, (void*)pthread_arg) != 0){
perror("pthread_create");
free(pthread_arg);
continue;
}
}
return 0;
}
void *pthread_routine(void *arg){
pthread_arg_t *pthread_arg = (pthread_arg_t *)arg;
int new_socket_fd = pthread_arg->new_socket_fd;
struct sockaddr_in client_address = pthread_arg->client_address;
int roulette_num, picked_num, won, accept_time = pthread_arg->roulette_time;
long stake;
time_t start, end;
sem_t mutex;
free(arg);
/*Inserisci codice roulette qui*/
while(1){
if(start == NULL){
start = time(NULL);
end = start + accept_time;
}
read(new_socket_fd, &picked_num, sizeof(picked_num));
read(new_socket_fd, &stake, sizeof(stake));
printf("Puntata ricevuta: numero %d, %d crediti\n",ntohl(picked_num), ntohl(stake));
bank = bank + stake;
printf("Soldi del banco: %d crediti\n",ntohl(bank));
start = time(NULL);
if(start >= end){
roulette_num = (rand() % (36 - 0 + 1)) + 0;
printf("Numero estrtatto dalla roulette: %d\n",roulette_num);
int converted_roulette_num = htonl(roulette_num);
write(new_socket_fd,&converted_roulette_num,sizeof(int));
if(read(new_socket_fd,&won,sizeof(int)) == 1){
int converted_bank = htonl(bank);
write(new_socket_fd,&converted_bank,sizeof(converted_bank));
bank = 0;
}
start = NULL;
}
}
close(new_socket_fd);
return NULL;
}
void signal_handler(int signal_number){
}
Edit: The input that this application accepts is ./server [socket port number] [seconds to activate roulette], for example: ./server 24106 30 (in this case 24106 is the socket port number, and we're asking the roulette to spin after 30 seconds have passed).
The output should appear in the following way: after the server receives an input from a connected client, the server prints the received number and the stake. After the amount of time passed as argument passed, the roulette spins and the server prints out the extracted number. However, as mentioned earlier, this only happens if I remove every instance of roulette_time from the code - otherwise I get Segmentation fault (core dumped) every time I try to run it.

Related

C recv function doesnt work all the time, it sometimes doesnt read and store all incoming data

We are working on a project where we want to communicate with a server.
This is our function to communicate with the server, but somehow it does not read the incoming messages correctly all the time.
Sometimes in the buffer there is something like:
(Server sends)"+ Client version acClient: ID 38ail6ii3s8jc"
instead of:
(Server sends)"+ Client version accepted - please send Game-ID to join"
(We send)"Client: ID 38ail6ii3s8jc"
So, I think the error is within the char *receiveAnswer(int sock) function.
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <string.h>
#define BUFFERSIZE 1024
#define bzeroNew(b,len) (memset((b), '\0', (len)), (void) 0) //buffer loeschen
#define VERSION "VERSION 3.4\n"
#include "functions.h"
char buffer[BUFFERSIZE];
int prologEnd = 0;
int proof;
//liest von Server eine Nachricht ein und speichert sie im buffer ab
char *receiveAnswer(int sock) {
bzeroNew(buffer, BUFFERSIZE);
if(recv(sock, buffer, sizeof(buffer), 0) < 0) {
perror("ERROR: Empfangen fehlgeschlagen\n");
}
printf("%s", buffer);
return buffer;
}
void sendResponse(int sock, char* message) {
bzeroNew(buffer, BUFFERSIZE);
strcpy(buffer, message);
proof = send(sock, buffer, strlen(buffer), 0);
if(proof < 0) {
perror("ERROR: Senden fehlgeschlagen\n");
}
printf("Client: %s\n", buffer);
receiveAnswer(sock);
}
int performConnection(int sock, char* gameID) {
bzeroNew(buffer, BUFFERSIZE);
receiveAnswer(sock);
while(strncmp(buffer, "+", 1) == 0 && prologEnd == 0) {
if(strncmp(buffer, "+ MNM Gameserver", 16) == 0) {
receiveAnswer(sock);
sendResponse(sock, VERSION);
}
else if(strncmp(buffer, "+ Client", 8) == 0) {
sendResponse(sock, gameID);
}
else if(strncmp(buffer, "+ PLAYING", 9) == 0) {
sendResponse(sock, "PLAYER\n");
receiveAnswer(sock);
}
else if(strncmp(buffer, "+ YOU", 5) == 0) {
receiveAnswer(sock);
printf("\n");
prologEnd = 1;
}
else if(strncmp(buffer, "+ TOTAL", 7) == 0) {
receiveAnswer(sock);
receiveAnswer(sock);
prologEnd = 1;
}
}
bzeroNew(buffer, BUFFERSIZE);
return 0;
}
This is our main() function, but I think the error is within the file above:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/wait.h> // für Warten auf Kindprozess
#include <unistd.h>
#include <netdb.h>
#include <netinet/in.h>
#include <fcntl.h>
#include <limits.h>
#include <signal.h>
// für Shared Memory:
#include <sys/ipc.h>
#include <sys/shm.h>
#include "functions.h"
#include "sharedMemory.h"
// dublicat, brauchen wir das?
#define GAMEKINDNAME "NMMorris"
#define HOSTNAME "sysprak.priv.lab.nm.ifi.lmu.de"
#define PORTNUMBER 1357
int main (int argc, char *argv[]) {
char gamekindname[256] = "NMMorris";
char hostname[256] = "sysprak.priv.lab.nm.ifi.lmu.de";
int portnumber = 1357;
char* gameID = argv[2];
char playerNumber[256];
char configFile[256] = "client.conf" ;
int fd[2]; // TODO: fd und client_fd vereinen
//gameID formatieren
char bufferGameID[64];
strcpy(bufferGameID, "ID ");
strcat(bufferGameID, gameID);
strcpy(gameID, bufferGameID);
strcat(gameID, "\n");
int i;
char tmp[256];
//Argumente einlesen und an Variablen übergeben
for(i = 3; i < 7; i++) {
strcpy(tmp, argv[i]);
if (strcmp(tmp, "-p") == 0){
strcpy(playerNumber, argv[i+1]);
} else if (strcmp(tmp, "-conf") == 0){
strcpy(configFile, argv[i+1]);
}
}
config configMain = readConfig(configFile);
strcpy(gamekindname, configMain.gameKind);
strcpy(hostname, configMain.hostServerName);
portnumber = configMain.portNmbr;
printf("\n>>>Config File Data<<<\n");
printf("HostServerName: %s\n", hostname);
printf("PortNumber: %d\n", portnumber);
printf("GameKind: %s\n\n ", gamekindname);
//From here: sockets
int sock, client_fd;
struct sockaddr_in serv_addr;
struct hostent *server;
sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0) {
perror("\nERROR: Socket creation error \n");
return - 1;
}
//ipAdresse nachschauen
server = gethostbyname(hostname);
if (server == NULL)
{
perror("ERROR: no such host\n");
}
memset(&serv_addr,0,sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(portnumber);
memcpy(&serv_addr.sin_addr.s_addr,server->h_addr,server->h_length);
if ((client_fd = connect(sock, (struct sockaddr*) &serv_addr, sizeof(serv_addr))) < 0) {
perror("ERROR: Connection Failed \n");
return -1;
}
printf(">>> Mit Host : %s verbunden <<<\n", hostname);
if(performConnection(sock, gameID) != 0) {
perror("performConnection Failed\n");
} // TODO: verlagern
close(client_fd);
return 0;
// Shared Memory Segment erstellen
int shmid_game = shmget(KEY, sizeof(gameInfo), IPC_CREAT | SHM_R | SHM_W);
if (shmid_game == -1) {
perror("Error while creating shared memory segment");
exit(EXIT_FAILURE);
} else {
printf("Creation successful\n");
}
int shmid_player = shmget(KEY, sizeof(playerInfo), IPC_CREAT | SHM_R | SHM_W);
if (shmid_player == -1) {
perror("Error while creating shared memory segment");
exit(EXIT_FAILURE);
} else {
printf("Creation successful\n");
}
// Prozess mit SHM verbinden
void* shm_game = shmat(shmid_game, 0, 0);
if (shm_game == NULL) {
perror("Error while attaching shared memory segment");
exit(EXIT_FAILURE);
} else {
printf("Attachment successful\n");
}
void* shm_player = shmat(shmid_player, 0, 0);
if (shm_player == NULL) {
perror("Error while attaching shared memory segment");
exit(EXIT_FAILURE);
} else {
printf("Attachment successful\n");
}
// Kindprozess (Connector) erstellen
pid_t pid;
pid = fork();
if (pid < 0) {
fprintf(stderr, "Fehler bei Erstellung des Kindprozesses.\n");
} else if (pid == 0) { // Kindprozess (Connector)
close(fd[1]);
performConnection(sock, gameID);
} else { // Elternprozess (Thinker)
close(fd[0]);
}
return 0;
}
TCP is a stream-oriented protocol, not a message-oriented one. A message sent as 100 bytes can be received as 1 100-byte read or as 100 1-byte reads, or any combination in between. This means that you must keep looping on the recv() until you have the whole message. That, in turn, means you need to know when a message is completely received. Either prepend the message's length before the message, use a fixed-size message, or have a unique recognizable terminator at the end of the message.
recv() returns the number of bytes that it has written into your buffer -- which is to say, it returns the number of bytes that it currently has available to give to you at the time you called it. Importantly, that will often be less than the number of bytes you requested, so it is mandatory that you check the return value of recv() to find out how many bytes you actually received, and not just assume that the value returned by recv() is equal to sizeof(buffer).
OTOH if you want recv() to not return until sizeof(buffer) bytes have been successfully read, you can pass the MSG_WAITALL flag to recv() in the fourth argument.
From the recv man page:
This flag requests that the operation block until the full
request is satisfied. However, the call may still return
less data than requested if a signal is caught, an error
or disconnect occurs, or the next data to be received is
of a different type than that returned. This flag has no
effect for datagram sockets.
It is not guaranteed that recv() will get all of the bytes sent at once. The convention is to call it in a loop until you've read all the bytes.
NB that recv() returns 0 when the client is stalling or closed the connection, and -1 on a read error.
Handling partial send()s:
int sendall(int s, char *buf, int *len)
{
int total = 0; // how many bytes we've sent
int bytesleft = *len; // how many we have left to send
int n;
while(total < *len) {
n = send(s, buf+total, bytesleft, 0);
if (n == -1) { break; }
total += n;
bytesleft -= n;
}
*len = total; // return number actually sent here
return n==-1?-1:0; // return -1 on failure, 0 on success
}
— From Beej's guide to Network Programming
The above code snippet calls send() in a loop until all the data has been sent.
You can now write a similar recv_all function that calls recv() in a loop until it has read all the data.
Handling partial recv()s:
Perhaps something like this:
/* Synopsis: Calls recv() in a loop to ensure
* len bytes have been read. Stores
* the total number of bytes sent in len.
*
* Returns: 0 on failure, 1 otherwise.
*/
static int recv_all(int sockfd, char *buf, size_t *len)
{
size_t bytes_left = *len;
size_t total = 0;
ssize_t rv = 0;
errno = 0;
while (total < *len) {
rv = recv(sockfd, buf + total, bytes_left, 0);
if (rv == 0) { /* Client closed the connection or is stalling */
return 0;
} else if (rv == -1) { /* A read error */
perror("recv");
return 0;
}
total += rv;
bytes_left -= rv;
}
*len = total;
return 1;
}
recv() may also return 0 when 0 characters were read. In that case, len can be compared against the original len to see if the call to recv() was successful.
Note: The above recv_all function has not been tested, and hence is not guaranteed to be bug free. It's meant to be an example.

Run mutex, but fails to create multiple threads

I am trying to simulate a server/client socket communication, and using threads for each client and then use mutex to lock and unlock those clients.
Mutex is working fine, even if I open another terminal and run the client script, it gets blocked till server unlocks it, but for some bad coding reason, this second client gets the same ID from the first client.
So, I want to create a new thread every time I run a new client. But I think that this "fork" is being the problem, for some reason...
int counter = 0;
int i = 0;
int j = 0;
void* operacoes (void*);
pthread_mutex_t mutexA = PTHREAD_MUTEX_INITIALIZER;
pthread_t thread_id [10];
int var;
int jo = 0;
int t = 0;
int main()
{
int sock_fd, sock_len, sock_novo, sock_novo_len,num;
struct sockaddr_un sock_ser, sock_cli;
char msg[100];
sock_fd = socket(AF_UNIX, SOCK_STREAM,0);
if(sock_fd<0)
{
printf("ERROR\n");
exit(0);
}
unlink("socket.unix.teste");
bzero((char*)&sock_ser, sizeof(sock_ser));
sock_ser.sun_family = AF_UNIX;
strcpy(sock_ser.sun_path,"socket.unix.teste");
sock_len = strlen(sock_ser.sun_path) +sizeof(sock_ser.sun_family);
if(bind(sock_fd,(struct sockaddr*)&sock_ser,sock_len)<0)
{
printf("ERROR\n");
exit(0);
}
listen(sock_fd,5);
for(;;)
{
sock_novo_len = sizeof(sock_cli);
sock_novo = accept(sock_fd, (struct sockaddr*)&sock_cli,&sock_novo_len);
if(fork() == 0)
{
close(sock_fd);
num = atoi(msg);
counter++;
for (i = jo; i<counter; i++)
{
pthread_create (&thread_id[i], NULL, operacoes, (void *)num);
jo++;
}
for (j = t; j<counter; j++)
{
pthread_join(thread_id[j], NULL);;
t++;
}
exit(0);
}
close(sock_novo);
}
return 0;
}
void* operacoes (void *arg)
{
if(arg == 1)
{
int id = pthread_self();
printf("Thread nummber: %d \n", id);
pthread_mutex_lock (&mutexA);
printf("Locked\n");
sleep(10);
pthread_mutex_unlock (&mutexA);
printf("Unlocked\n");
}
return 0;
}
On client side, I only send a single variable 'msg'.
How could I solve it? I tried to use those two variables 'jo' and 't', but every new client I create, it reads the whole code, and it gets back to 0 so I cant get next phthread_create's vector position.
Assuming I understand correctly what you want to achieve:
Create a unix domain socket and listen for incoming connections
Treat each connection in parallel
Have one global mutex being locked/unlocked during treatment of the connections
try this:
#include <pthread.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
pthread_mutex_t mutexA = PTHREAD_MUTEX_INITIALIZER;
struct oarg_t {
int con_socket;
};
void* operacoes (void *arg)
{
struct oarg_t* oarg = arg;
int id = pthread_self();
printf("Thread number: %d \n", id);
pthread_mutex_lock (&mutexA);
printf("Locked\n");
sleep(10);
pthread_mutex_unlock (&mutexA);
printf("Unlocked\n");
close(oarg->con_socket);
free(oarg);
return 0;
}
int main()
{
const char* domain_name = "socket_unix.teste";
int i = 0;
int j = 0;
int sock_fd;
sock_fd = socket(AF_UNIX, SOCK_STREAM,0);
if(sock_fd<0) goto error;
unlink(domain_name);
struct sockaddr_un sock_ser = {
.sun_family = AF_UNIX,
};
strncpy(sock_ser.sun_path, domain_name, sizeof(sock_ser.sun_path));
if(0 != bind(sock_fd, (struct sockaddr*) &sock_ser, sizeof(sock_ser)))
goto error;
listen(sock_fd,5);
size_t counter = 0;
while(1) {
struct sockaddr_un sock_cli = {0};
int sock_len = sizeof(sock_cli);
int sock_novo =
accept(sock_fd, (struct sockaddr*)&sock_cli, &sock_len);
if(0 > sock_novo) {
printf("Error accepting:% s\n", strerror(errno));
continue;
}
printf("Connection no %zu\n", counter++);
struct oarg_t* oarg = calloc(1, sizeof(struct oarg_t));
oarg->con_socket = sock_novo;
pthread_t id = 0;
pthread_create (&id, NULL, operacoes, oarg);
}
return EXIT_SUCCESS;
error:
printf("ERROR: %s\n", strerror(errno));
exit(EXIT_FAILURE);
}

Why is my printf printing the wrong values?

I can't figure out why my code is not working. I am trying to create something similar to P2P file transfer where multiple threads simultaneously grab different parts of a file from a pre-existing server program. The actual problem I am having right now, is much simpler, however.
Since you cannot pass multiple arguments into pthread_create, I created a structure that had the two pieces of information I want to pass. I also created an array of pointers to these structures and initialize each one individually before passing it's pointer in.
printf("In thread: port=%d & ipAddr=%s\n",conn->port,conn->ipAddr);
When that line runs, everything prints out correctly with the correct port number and IP address.
printf("Size of chunk %d received by %lu on port %d: %d bytes\n",chunkNum,pthread_self(),conn->port,sizeRec);
However, when that line runs shortly after, the port number does not print out correctly. Instead of 9210 and 9211, I get 0 and 134520848. Otherwise, everything seems to be working so I'm thinking it may just be a printf problem of some sort, but I want to be sure before I move on to implementing the next part of my project.
If anyone has any idea why the same variable would print with one value and a completely different a few lines later when no changes were made, it would be very helpful for me. I have included all of my code below for reference. Thanks for your help!
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
char * file_name = "output.txt";
int nextChunk = 0;
pthread_mutex_t lock1 = PTHREAD_MUTEX_INITIALIZER;
struct connection{
int port;
char* ipAddr;
};
void* getFile(void* args) {
int con_fd = 0;
int ret = 0;
struct sockaddr_in serv_addr;
struct connection* conn = (struct connection*)args;
printf("In thread: port=%d & ipAddr=%s\n",conn->port,conn->ipAddr);
memset(&serv_addr, 0, sizeof(struct sockaddr));
serv_addr.sin_family = AF_INET;
//printf("port number: %d\n",conn->port);
serv_addr.sin_port = htons(conn->port);
serv_addr.sin_addr.s_addr = inet_addr(conn->ipAddr);
int sizeRec;
char buf[1024];
while(1) {
con_fd = socket(PF_INET, SOCK_STREAM, 0);
if (con_fd == -1) {
printf("Socket Error\n");
fflush(stdout);
return 0;
}
ret = connect(con_fd, (struct sockaddr *)&serv_addr, sizeof(struct sockaddr));
if (ret < 0) {
printf("Connect error\n");
fflush(stdout);
return 0;
}
char chunkStr[128];
pthread_mutex_lock(&lock1);
int chunkNum = nextChunk++;
pthread_mutex_unlock(&lock1);
sprintf(chunkStr,"%d",chunkNum);
send(con_fd,chunkStr,128,0);
sizeRec = recv(con_fd,buf,1024,0);
printf("Size of chunk %d received by %lu on port %d: %d bytes\n",chunkNum,pthread_self(),conn->port,sizeRec);
if (sizeRec <= 0) {
return 0;
}
}
/*FILE *f = fopen(filename, "w");
if (!f) {
printf("Can't open %s for input. Program halting\n",filename);
exit(0);
}*/
/*while ((sizeReceived = recv(sock,buf,1024,0)) > 0) {
if (fwrite(buf,sizeof(char),sizeReceived,f) == -1) {
printf("Error writing file");
exit(0);
}
}
fclose(f);*/
close(con_fd);
return 0;
}
int main(int argc, char ** argv) {
if (argc < 3 || argc % 2 == 0) {
printf("Usage: ./client <ipaddr1> <port1> <ipaddr2> <port2> . . .\n");
return -1;
}
int numThreads = argc / 2;
pthread_t threads[numThreads];
struct connection** connections = malloc(sizeof(struct connection*)*numThreads);
//char* args[numThreads][2];
printf("numThreads: %d\n",numThreads);
for (int i=0; i<numThreads; i++) {
connections[i] = malloc(sizeof(struct connection));
connections[i]->ipAddr = argv[2*i+1];
connections[i]->port = atoi(argv[2*i+2]);
printf("port number: %d\n",connections[i]->port);
pthread_create(&threads[i], NULL, getFile, (void*)(connections[i]));
}
for (int i=0; i<numThreads; i++) {
free(connections[i]);
pthread_join(threads[i], NULL);
}
pthread_mutex_destroy(&lock1);
return 0;
}
Your main problem is the second for loop in main().
You first free the data structure and then call pthread_join(). Reverse these two statements and it should work reliable.
If you use Linux, I suggest to use valgrind tool, which easily helps to spot such issues. For windows I only know expensive commercial tools doing the same (like Purify).
Change this :
for (int i=0; i<numThreads; i++) {
free(connections[i]);
pthread_join(threads[i], NULL);
To :
for (int i=0; i<numThreads; i++) {
pthread_join(threads[i], NULL);
free(connections[i]);

Segmentation fault on Socket programming

I have a homework problem. Socket-Programming with Unix domain
1. Client send file name to server
2. Server checks the File exists, opens, and sends file descriptor to client
3. Client opens a file descriptor and outputs to screen.
platform = ubuntu 12.04.
I have problem with the client. Error Segmentation fault (core dumped) on line fd = *p(i have marked on client code)
this is my code
Server
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <stdbool.h>
#include <signal.h>
#include <sys/wait.h>
#define SOCKNAME "sockunix"
bool ende = false;
void sigfkt(int signr){
printf("SIGINT empfangen ...\n");
ende = true;
}
int main(){
int fd, sockd, sockd2, rc, *p, sl;
FILE *fp;
struct sockaddr_un uxadr;
struct msghdr mh;
struct cmsghdr *cmp;
char ctrl[sizeof(struct cmsghdr)+10];
struct iovec iov[1];
char eab[100];
//bat dau khai bao
mh.msg_name = NULL;
mh.msg_namelen = 0;
mh.msg_iov = iov;
mh.msg_iovlen = 1;
mh.msg_control = ctrl;
mh.msg_controllen = sizeof(ctrl);
mh.msg_flags = 0;
cmp = CMSG_FIRSTHDR(&mh);
cmp->cmsg_len = CMSG_LEN(fd);
cmp->cmsg_level = SOL_SOCKET;
cmp->cmsg_type = SCM_RIGHTS;
p = (int *)CMSG_DATA(cmp);
// khoi tao socket
uxadr.sun_family = AF_UNIX;
strcpy(uxadr.sun_path, SOCKNAME);
sockd = socket(AF_UNIX, SOCK_STREAM, 0);
if(sockd<0){
perror("socket");
exit(1);
}
unlink(uxadr.sun_path);
sl = sizeof(uxadr);
rc = bind(sockd, (struct sockaddr*)&uxadr, sl);
if(rc<0){
perror("bind");
exit(2);
}
rc = listen(sockd, 10);
if(rc<0){
perror("listen");
exit(3);
}
sigset(SIGINT, sigfkt);
printf("Warte auf Client-Anforderungen ....\n"); //cho client ket noi toi
do{
sockd2 = accept(sockd, 0, 0);
if(ende)
break;
if(sockd2<0){
perror("accept");
exit(4);
}
iov[0].iov_base = eab;
iov[0].iov_len = sizeof(eab);
rc = recvmsg(sockd2,&mh,0); //nhan File name tu client
if(rc<0){
perror("recvmsg");
exit(5);
}
printf("%s\n",eab);
if(rc>0){
fp = fopen(eab,"r");// kiem tra xem file ton tai ko?
if(fp==NULL){
printf("file not existiert\n");
eab[0]=1; // thong bao cho client file ko ton tai
}
else{
fd = fileno(fp); // lay File descriptor
eab[0]=2; // thong bao cho client file ton tai
*p = fd; //gan File descriptor vao cau truc dieu khien
}
}
printf("fd=%d\n",*p);
rc = sendmsg(sockd2,&mh,0); // guoi thong bao va File descriptor den client
if(rc<0){
perror("sendmsg");
}
close(sockd2);
}while(!ende);
close(sockd);
unlink(uxadr.sun_path);
}
Client
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <stdbool.h>
#include <signal.h>
#include <sys/wait.h>
#define SOCKNAME "sockunix"
int main(int argc, char *argv[]){
int fd = 0, sockd, rc, *p, sl;
FILE *fp;
struct sockaddr_un uxadr;
struct msghdr mh;
struct cmsghdr *cmp;
char ctrl[sizeof(struct cmsghdr)+10];
struct iovec iov[1];
char eab[100],fname[100];
//bat dau khai bao
mh.msg_name = NULL;
mh.msg_namelen = 0;
mh.msg_iov = iov;
mh.msg_iovlen = 1;
mh.msg_control = ctrl;
mh.msg_controllen = sizeof(ctrl);
mh.msg_flags = 0;
cmp = CMSG_FIRSTHDR(&mh);
cmp->cmsg_len = CMSG_LEN(fd);
cmp->cmsg_level = SOL_SOCKET;
cmp->cmsg_type = SCM_RIGHTS;
p = (int *)CMSG_DATA(cmp);
//khoi tao socket
uxadr.sun_family = AF_UNIX;
strcpy(uxadr.sun_path, SOCKNAME);
sockd = socket(AF_UNIX, SOCK_STREAM, 0);
if(sockd<0){
perror("socket");
exit(1);
}
sl = sizeof(uxadr);
rc = connect(sockd, (struct sockaddr *)&uxadr, sl);
if(rc<0){
perror("connect");
exit(2);
}
if(argc>=2){ // dua File name vao tu dong lenh
sprintf(fname,"%s",argv[1]);
}
else{// neu chua co File name thi bat dau nhap file name vao
printf("Bitte Filename eingeben\n");
fflush(stdin);
gets(fname);
}
iov[0].iov_base = fname;
iov[0].iov_len = strlen(fname)+1;
rc = sendmsg(sockd, &mh, 0); // guoi filename sang server
if(rc<0){
perror("sendmsg");
exit(3);
}
iov[0].iov_base = eab;
iov[0].iov_len = sizeof(eab);
rc = recvmsg(sockd, &mh, 0); // nhan thong bao va File descriptor tu server
cmp = CMSG_FIRSTHDR(&mh);
p = (int *)CMSG_DATA(cmp);
if(rc<0){
perror("recvmsg");
exit(4);
}
switch(eab[0]){// kiem tra thong bao
case 1:// file khong ton tai
printf("File ist nicht existiert!\n");
break;
case 2:// file ton tai
printf("File ist existiert. Filedeskriptor ist bereits zu verwandel!\n");
FAULT ================> fd = *p; //fault here with GDB debug
printf("fd=%d\n",fd);
fp = fdopen(fd,"r");
if(fp=NULL)
printf("fehler fd\n");
printf("Fileinhalt ausgeben\n");
printf("=============================================\n");
while(fread(eab,100,1,fp)>0)
printf("%s", eab);
printf("=============================================\n");
fclose(fp);
break;
}
close(sockd);
}
In theory, you can't share file descriptors between processes over TCP sockets with processes with different address spaces. In order to do that, you could use UNIX sockets.
If you want to share info between processes (not file descriptors), you can use other techniques, like mmap, pipes, message passing, and so on.
You need to check the error code returned by recvmesg before you do anything with the data it may or may not have returned.
There is no guarantee that when recvmesg returns an error that mh will be in a useable state.
A segmentation fault on *p means that p is either zero or pointing to memory that is not allocated.
It looks like p is supposed to be pointing inside mh somewhere. First check that the value of p just before the crash is between &mh and (char*)&mh + sizeof(mh).

Error "Bad address" when reading from message queue on Linux

I have assignment when I need to write simple time server and a client using Linux message queue. The server opens a message queue and the client sends a request with his PID (message with type 1) and the server reads that message and sends a message with type of PID (taken from the message read). I put all the code below because I don't know where I made the mistake. I'm not Linux programming expert. Don't even know if I written server correct.
File that is included by server and client (I need to write it in this way).
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <sys/msg.h>
#include <sys/ipc.h>
#include <sys/types.h>
#include <string.h>
#include <signal.h>
#define QUEUE 100
#define PERM_ALL 0777
typedef struct my_msgbuf {
long mtype;
int pid;
} ClientMessage;
typedef struct my_msgbuf2 {
long mtype;
struct tm time;
} TimeMessage;
Server
int m_queue;
void cleanup(int signum) {
if (msgctl(m_queue, IPC_RMID, NULL) == -1) {
printf("Something happen on clean up\n");
exit(1);
}
exit(signum);
}
int main() {
ClientMessage pid_message;
TimeMessage t;
time_t clock;
struct tm *cur_time;
if ((m_queue = msgget(QUEUE, PERM_ALL | IPC_CREAT)) == -1) {
printf("Can't create and open message queue\n");
exit(1);
}
printf("created message queue = %d\n", m_queue);
fflush(stdout);
//t = malloc(sizeof(TimeMessage));
signal(SIGINT, cleanup);
while (1) {
if (msgrcv(m_queue, &pid_message, sizeof(pid_message.pid), 1, 0) == -1) {
break;
} else {
t.mtype = pid_message.pid;
clock = time(NULL);
cur_time = localtime(&clock);
memcpy(&t.time, cur_time, sizeof(struct tm));
msgsnd(m_queue, &t, sizeof(struct tm), 0);
}
}
cleanup(0);
}
Client
int main() {
int m_queue;
TimeMessage *t;
ClientMessage client;
if ((m_queue = msgget(QUEUE, PERM_ALL)) == -1) {
perror("Error in opening queue");
exit(1);
}
client.mtype = 1;
client.pid = getpid();
while (1) {
if (msgsnd(m_queue, &client, sizeof(client.pid), 0) == -1) {
perror("Error sending to queue");
exit(1);
} else {
if (msgrcv(m_queue, t, sizeof(struct tm), client.pid, 0) == -1) {
perror("Error reading from queue");
exit(1);
}
printf("time: %d:%d:%d\n", t->time.tm_hour, t->time.tm_min, t->time.tm_sec);
}
}
return 0;
}
Both program compile without errors but client return "Error reading from queue" msgrcv is returning -1.
After adding the perror it appears that you have got the error stating "Bad Address" (EFAULT) which means that "The address pointed to by msgp (buffer) isn't accessible". From the code it appears that there has been no memory allocated to TimeMessage *t so you can either allocate memory or just change it to TimeMessage t and pass &t instead of t to msgrcv. Also size should be sizeof t (assuming the change from *t to t, or sizeof(TimeMessage) for *t) instead of sizeof(struct tm) (& obviously you would change printf statement accordingly)
Hope this helps!

Resources