The idea of my program is to use pthreads, semaphores, posix shared memory, and sockets to create an environment where N processes (that we will refer to as the children) can connect to a single process (that we will refer to as the parent) in order to send it data.
Common Code
The parent and child processes are only allowed, and must have, 2 globally defined (#define) variables. It is these values that provide for a common means for these processes to establish a connection. These values will define the main semaphore and the shared memory segment.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <arpa/inet.h>
#include <string.h>
#include <pthread.h>
#include <sys/types.h>
#include <stdbool.h>
#include <sys/ipc.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/sem.h>
#include <fcntl.h>
#define SEM_KEY ftok("commoncode.c", 'a')
#define SHARED_MEM "/vector_table"
struct v_table
{
pid_t PID;
int Sem;
int Port;
};
Parent Code
#include "commoncode.c"
#define MAX_LENGTH 512
#define MAX_CHILD 5
pthread_barrier_t barrier;
struct v_table Vector[MAX_CHILD];
char *ok = "<ok>\n";
key_t key;
static int semcnt = 0;
union semun {
int val; /* used for SETVAL only */
};
void *client_serv(void * argum) {
int msg_len, client_socket = *(int *)argum, semid0, semid1;
char text[20];
union semun arg;
while (1) {
semid0 = semget(key + semcnt, 0, IPC_CREAT | 0666);
if ((volatile int)semctl(semid0, 0, GETVAL, 0) != 1) {
arg.val = 1;
semctl(semid0, 0, SETVAL, arg);
msg_len = recv(client_socket, text, 20, 0);
printf("%s\n", text);
if(msg_len <= 0) {
printf("Incorrect name from client");
return (void *)1;
}
semcnt++;
if (semcnt == MAX_CHILD)
semcnt = 0;
semid1 = semget(key + semcnt, 0, IPC_CREAT | 0666);
arg.val = 0;
semctl(semid1, 0, SETVAL, arg);
if (!strcmp(text, "terminate"))
break;
memset(text, 0, 20);
if (send(client_socket, ok, strlen(ok), 0) != strlen(ok)) {
printf("Error : send() sent a different number of bytes\n");
return (void *)1;
}
}
}
pthread_barrier_wait (&barrier);
if (send(client_socket, ok, strlen(ok), 0) != strlen(ok)) {
printf("Error : send() sent a different number of bytes\n");
return (void *)1;
}
return (void *)0;
}
int main(int argc, char *argv[])
{
int i, fd;
int servSock, clntSock[MAX_CHILD], i1=1;
struct sockaddr_in echoServAddr;
pthread_t threads[MAX_CHILD];
uint8_t * mapped_ptr;
union semun arg;
for (i = 0; i < MAX_CHILD; i++) {
Vector[i].PID = 0;
Vector[i].Sem = 0;
Vector[i].Port = i + 49153;
}
fd = shm_open(SHARED_MEM, O_CREAT | O_RDWR | O_APPEND, S_IRUSR | S_IWUSR);
if(fd == -1) {
perror("shm_open");
shm_unlink (SHARED_MEM);
return 1;
}
ftruncate(fd, MAX_CHILD * sizeof(struct v_table));
mapped_ptr = mmap(NULL, MAX_CHILD * sizeof(struct v_table), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if(mapped_ptr < 0) {
perror("mmap");
shm_unlink (SHARED_MEM);
return 1;
}
key = SEM_KEY;
for (i = 0; i < MAX_CHILD; i++) {
Vector[i].Sem = semget(key + i, 1, IPC_CREAT | 0666);
arg.val = 0;
semctl(Vector[i].Sem, 0, SETVAL, arg);
}
memcpy(mapped_ptr, Vector, MAX_CHILD * sizeof(struct v_table));
msync(mapped_ptr, MAX_CHILD * sizeof(struct v_table), MS_SYNC);
printf("Vector table (from Parent)\n");
printf("-----------------------------\n");
printf("PID Semaphore Port\n");
for (i = 0; i < MAX_CHILD; i++)
printf("%04d %06d %05d\n", (int)(Vector[i].PID), Vector[i].Sem, Vector[i].Port);
if ((servSock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
printf("Error : Socket failed\n");
return 1;
}
setsockopt(servSock, SOL_SOCKET, SO_REUSEADDR, &i1, sizeof(i1));
memset(&echoServAddr, 0, sizeof(echoServAddr));
echoServAddr.sin_family = AF_INET;
echoServAddr.sin_addr.s_addr = htonl(INADDR_ANY);
echoServAddr.sin_port = htons(Vector[0].Port);
if (bind(servSock, (struct sockaddr *) &echoServAddr, sizeof(echoServAddr)) < 0) {
printf("bind() failed\n");
return 1;
}
/* Mark the socket so it will listen for incoming connections */
if (listen(servSock, MAX_CHILD) < 0) {
printf("Listen() failed\n");
return 1;
}
for (i = 0; i < MAX_CHILD; i++) {
if ((clntSock[i]=accept(servSock,(struct sockaddr*)NULL,(socklen_t *)NULL)) < 0) {
printf("accept() failed\n");
return 1;
}
}
pthread_barrier_init (&barrier, NULL, MAX_CHILD);
for (i = 0; i < MAX_CHILD; i++) {
pthread_create(&threads[i], NULL, client_serv,(void *)(&clntSock[i]));
}
while (i)
pthread_join(threads[--i], NULL);
for (i = 0; i < MAX_CHILD; i++) {
close(clntSock[i]);
semctl(Vector[i].Sem, 0, IPC_RMID);
}
getchar();
shm_unlink (SHARED_MEM);
return 0;
}
Child Code
#include "commoncode.c"
#define MAX_LENGTH 512
#define MAX_CHILD 5
struct v_table Vector[MAX_CHILD];
uint8_t * mapped_ptr;
char *ok = "<ok>\n";
int main(int argc, char *argv[])
{
int server_socket, echoServPort, i, n, attmpt = 0, fd;
char *ipaddrstr, *text[3];
struct sockaddr_in echoServAddr;
if (1 == argc) {
printf("Error - You must include a data size: ./child N.\n");
return 1;
} else if (2 != argc) {
printf("Error : Too many arguments\n");
return 1;
}
for(i=0 ; i<3 ; i++) {
text[i] = malloc(MAX_LENGTH);
memset(text[i], 0, MAX_LENGTH);
}
fd = shm_open(SHARED_MEM, O_RDWR | O_APPEND, S_IRUSR | S_IWUSR);
if(fd == -1) {
perror("shm_open");
shm_unlink (SHARED_MEM);
return 1;
}
ftruncate(fd, MAX_CHILD * sizeof(struct v_table));
mapped_ptr = mmap(NULL, MAX_CHILD * sizeof(struct v_table), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if(mapped_ptr < 0) {
perror("mmap");
shm_unlink (SHARED_MEM);
}
memcpy((void *)Vector, (void *)mapped_ptr, MAX_CHILD * sizeof(struct v_table));
ipaddrstr = malloc(16);
memcpy(ipaddrstr, "127.0.0.1", strlen("127.0.0.1"));
if ((server_socket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
printf("socket() failed\n");
return 1;
}
echoServAddr.sin_family = AF_INET; /* Internet address family */
echoServAddr.sin_addr.s_addr = inet_addr(ipaddrstr); /* Server IP address */
for (i = 0; i < MAX_CHILD; i++) {
if (Vector[i].PID == 0) {
Vector[i].PID = getpid();
break;
}
attmpt++;
}
printf("Vector table (from %04d)\n", getpid());
printf("-----------------------------\n");
printf("PID Semaphore Port\n");
for (i = 0; i < MAX_CHILD; i++)
printf("%04d %04d %05d\n", (int)(Vector[i].PID), Vector[i].Sem, Vector[i].Port);
if (attmpt == MAX_CHILD) {
printf("Error - No space left in vector table\n");
getchar();
return 1;
}
for (i = 0; i < MAX_CHILD; i++) {
echoServPort = 49153 + i;
echoServAddr.sin_port = htons(echoServPort); /* Server port */
if (connect(server_socket, (struct sockaddr*) &echoServAddr,sizeof(echoServAddr)) < 0) {
printf("Error Connecting\n");
getchar();
return 1;
} else {
break;
}
}
mapped_ptr = memcpy((void *)mapped_ptr, (void *)Vector, MAX_CHILD * sizeof(struct v_table));
msync(mapped_ptr, MAX_CHILD * sizeof(struct v_table), MS_SYNC);
sscanf(argv[1], "%d", &n);
for (i = 0; i < n; i++) {
sprintf(text[1], "Child %04d %d", getpid(), i);
if (send(server_socket, text[1], strlen(text[1]), 0) != strlen(text[1])) {
printf("Error : send() sent a different number of bytes\n");
return 1;
}
recv(server_socket, text[2], MAX_LENGTH, 0);
if(strcmp (text[2], ok)) {
printf("Error : Wrong Secret\n");
shutdown(server_socket, 2);
return 1;
}
memset(text[1], 0, MAX_LENGTH);
memset(text[2], 0, MAX_LENGTH);
}
sprintf(text[1], "terminate");
if (send(server_socket, text[1], strlen(text[1]), 0) != strlen(text[1])) {
printf("Error : send() sent a different number of bytes\n");
return 1;
}
recv(server_socket, text[2], MAX_LENGTH, 0);
if(strcmp (text[2], ok)) {
printf("Error : Wrong Secret\n");
shutdown(server_socket, 2);
return 1;
}
free(ipaddrstr);
getchar();
shm_unlink (SHARED_MEM);
return 0;
}