C: Reading from OpenSSL Socket - c

I'm using the OpenSSL library to secure network messages, but for some reason it doesn't always seems to work. Actually most of the time it doesn't work. When I run the compiled code and connect to the socket, most of the time it just runs the code of the main process in the child as well, but sometimes it runs the child instructions. Obiously, this isn't the way it should work, the child should exit instead, after it handled the client (handle_client(newfd)) all the time. One interesting part is, if I remove the handle_client(newfd) line from the child instructions and put something small there, like printf("test"), then the child works every time as it should, it prints test and exits right after that. Is this some kind of limitation in fork(), or I just shouldn't run this much code in a child? Or something else? Any help would be really appriciated!
main.c:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <netdb.h>
#include <sys/wait.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <string.h>
#include <fcntl.h>
#include "json.h"
#include "create_socket.h"
#include "get_addr.h"
#include "handle_income.h"
#include "handle_client.h"
int main(void) {
int newfd;
struct sockaddr_storage their_addr;
char s[INET6_ADDRSTRLEN];
pid_t pid;
unsigned int cpc = 0;
int listenfd = create_socket("8069");
if (listenfd < 0)
exit(1);
while(1) {
socklen_t sin_size = sizeof their_addr;
if ((newfd = accept(listenfd, (struct sockaddr *)&their_addr, &sin_size)) == -1)
continue;
inet_ntop(their_addr.ss_family,
get_addr((struct sockaddr *)&their_addr), s, sizeof s);
printf("conn %s siz %d\n", s, (int) sin_size); //REMOVE
if ((pid = fork()) < 0) {
exit(1);
} else if (pid == 0) {
close(listenfd);
handle_client(newfd);
exit(0);
}
printf("child %d\n", (int) pid); //REMOVE
cpc++;
while(cpc) {
pid = waitpid((pid_t) -1, NULL, WNOHANG);
if (pid < 0)
exit(1);
else if (pid == 0)
break;
else
cpc--;
}
}
EVP_cleanup();
exit(0);
}
handle_client.h:
#define READ_SIZE 32
void handle_client(int newfd) {
char *buffer = NULL;
char *tmp_buffer = malloc(READ_SIZE);
unsigned long buffer_size = 0;
unsigned long received = 0;
int status = 0;
SSL_load_error_strings();
OpenSSL_add_all_algorithms();
SSL_CTX *sslctx = SSL_CTX_new(SSLv23_server_method());
if (sslctx) {
SSL_CTX_set_ecdh_auto(sslctx, 1);
if ((SSL_CTX_use_certificate_file(sslctx, "/ssl-cert.pem", SSL_FILETYPE_PEM)) > 0) {
if ((SSL_CTX_use_PrivateKey_file(sslctx, "/ssl-key.pem", SSL_FILETYPE_PEM)) > 0) {
SSL *ssl = SSL_new(sslctx);
SSL_set_fd(ssl, newfd);
if (SSL_accept(ssl) > 0) {
fcntl(newfd, F_SETFL, fcntl(newfd, F_GETFL, 0) | O_NONBLOCK);
do {
if (received >= buffer_size) {
char *tmp;
buffer_size += READ_SIZE;
if ((tmp = realloc(buffer, buffer_size)) == NULL) {
break;
} else {
buffer = tmp;
}
}
status = SSL_read(ssl, tmp_buffer, READ_SIZE);
if (status > 0) {
received += status;
strncat(buffer, tmp_buffer, status);
} else {
ERR_print_errors_fp(stderr);
}
} while (status > 0);
free(tmp_buffer);
buffer[received] = 0;
if (received < buffer_size) {
buffer = realloc(buffer, received);
}
printf("%s\n", buffer); //REMOVE
char *response = handle_income(buffer);
SSL_write(ssl, response, strlen(response));
printf("%s\n", response); //REMOVE
}
SSL_free(ssl);
}
}
}
SSL_CTX_free(sslctx);
close(newfd);
}

There might be other problems too, but you should fix the following buffer overflow error, and check if it fix visible problem too:
SSL_read may return less than READ_SIZE. So the next piece of code is broken.
Problem occurs for example, when the 1st SSL_read() returns for example 16, and the next call return 32 (=READ_SIZE). Allocated buffer size during 2nd strncat call is 32, so buffer overflow may occurs during strncat().
if (received >= buffer_size) {
char *tmp;
buffer_size += READ_SIZE;
if ((tmp = realloc(buffer, buffer_size)) == NULL) {
break;
} else {
buffer = tmp;
}
}
status = SSL_read(ssl, tmp_buffer, READ_SIZE);
if (status > 0) {
received += status;
strncat(buffer, tmp_buffer, status);
}
...
There might be other problem with strncat call. It needs one extra byte for null terminator of string. From man page:
the size of dest must be at least strlen(dest)+n+1

Related

Read from named piped

I have to write a program which monitors two named pipes and prints the information sent through either.
When the write end of one of the pipes is closed, the program will detect this and close and open the pipe again.
This is what I have written so far:
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#define BUF_SIZE 200
int
main(void)
{
fd_set rfds;
struct timeval tv;
int retval;
ssize_t n_read;
char buf[BUF_SIZE];
/* Open pipes */
int tuberia1_fd = open("tuberia1",O_RDONLY);
int tuberia2_fd = open("tuberia2",O_RDONLY);
while(1){
/* Watch stdin (fd 0) to see when it has input. */
FD_ZERO(&rfds);
FD_SET(0, &rfds);
/* Wait for an indefinite amount of time. */
tv.tv_sec = 0;
tv.tv_usec = 0;
retval = select(2, &rfds, NULL, NULL, &tv);
/* Don't rely on the value of tv now! */
if (retval == -1)
perror("select()");
exit(EXIT_FAILURE);
if(FD_ISSET(tuberia1_fd, &rfds)){
n_read = read(tuberia1_fd, &buf, BUF_SIZE);
if (n_read == 0){
close(tuberia1_fd);
tuberia1_fd = open("tuberia1", O_RDONLY);
}else{
buf[n_read] = '\0';
printf("tuberia1: %s", buf);
}
} else if (FD_ISSET(tuberia2_fd, &rfds)){
n_read = read(tuberia2_fd, &buf, BUF_SIZE);
if (n_read == 0){
close(tuberia2_fd);
tuberia2_fd = open("tuberia2", O_RDONLY);
}else{
buf[n_read] = '\0';
printf("tuberia2: %s", buf);
}
}
}
}
When I run it, the program locks, which is the expected behavior. But when I echo hello_world > tuberia1 there is no response from the program.
What is going on?
EDIT: As observed by GM below, I was incorrectly passing arguments to select. After fixing that my program looks like this:
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#define BUF_SIZE 200
int
main(void)
{
fd_set rfds;
struct timeval tv;
int retval;
ssize_t n_read;
char buf[BUF_SIZE];
/* Open pipes */
printf("Opening tuberia1");
int tuberia1_fd = open("tuberia1",O_RDONLY);
printf("Opening tuberia2");
int tuberia2_fd = open("tuberia2",O_RDONLY);
while(1){
printf("Enter the loop");
/* Watch stdin (fd 0) to see when it has input. */
FD_ZERO(&rfds);
FD_SET(tuberia1_fd, &rfds);
FD_SET(tuberia2_fd, &rfds);
/* Wait for an indefinite amount of time. */
tv.tv_sec = 5;
tv.tv_usec = 0;
int fd_max = (tuberia1_fd > tuberia2_fd) ? tuberia1_fd : tuberia2_fd;
retval = select(fd_max, &rfds, NULL, NULL, &tv);
/* Don't rely on the value of tv now! */
if (retval == -1)
perror("select()");
exit(EXIT_FAILURE);
if(FD_ISSET(tuberia1_fd, &rfds)){
n_read = read(tuberia1_fd, &buf, BUF_SIZE);
if (n_read == 0){
close(tuberia1_fd);
tuberia1_fd = open("tuberia1", O_RDONLY);
}else{
buf[n_read] = '\0';
printf("tuberia1: %s", buf);
}
} else if (FD_ISSET(tuberia2_fd, &rfds)){
n_read = read(tuberia2_fd, &buf, BUF_SIZE);
if (n_read == 0){
close(tuberia2_fd);
tuberia2_fd = open("tuberia2", O_RDONLY);
}else{
buf[n_read] = '\0';
printf("tuberia2: %s", buf);
}
}
}
}
It still does not work. Running it under GDB shows that the program never progresses past the first open.
You need to use FD_SET on the file descriptors you're actually interested in -- namely tuberia1_fd and tuberia2_fd.
So something like...
while (1) {
FD_ZERO(&rfds);
FD_SET(tuberia1_fd, &rfds);
FD_SET(tuberia2_fd, &rfds);
int max;
if (tuberia1_fd > tuberia2_fd) {
max = tuberia1_fd;
} else {
max = tuberia2_fd;
}
tv.tv_sec = 0;
tv.tv_usec = 0;
retval = select(max + 1, &rfds, NULL, NULL, &tv);

Sending messages using pipe - C

I want to make NO_PROC processes, such that every process reads messages from its parent, and then writes those messages and one more message to its child, except in the case of the last process which writes its messages to stdout. So the i'th process will receive i-1 messages and will send to child i messages. I must use pipe to communication between processes. I wrote code but something is wrong and I can't find any bug :/. When NO_PROC = 5 I want the output to look like 4 lines with "my message", but in output I have one line: "my message" and 3 empty lines, like 3 messages are empty string :/. Note, err.h is my library which gives me function syserr() when something went wrong.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include "err.h"
#define NO_PROC 5
#define BUF_SIZE 20
char message[] = "my message";
int parent;
char buf[BUF_SIZE];
int main()
{
for (int i = 0; i < NO_PROC; ++i) {
int pipe_dsc[2], buf_len;
if (pipe(pipe_dsc) == -1)
syserr("Error in pipe\n");
pid_t pid = fork();
if (pid == -1)
syserr("Error in fork\n");
else if (pid == 0)
parent = pipe_dsc[0];
else {
for (int j = 0; j < i; ++j) {
if ((buf_len = read(parent, buf, BUF_SIZE - 1)) == -1)
syserr("Error in read\n");
buf[buf_len < BUF_SIZE - 1 ? buf_len : BUF_SIZE - 1] = '\0';
if (i == NO_PROC - 1)
printf("%s\n", buf);
else if (write(pipe_dsc[1], buf, sizeof(buf)) != sizeof(buf))
syserr("Error in write\n");
}
if (i < NO_PROC - 1 && write(pipe_dsc[1], message, sizeof(message)) != sizeof(message))
syserr("Error in write\n");
if (wait(0) == -1)
syserr("Error in wait\n");
return 0;
}
}
}
I think your over complicating it and/or using the wrong approach. You don't have to send i messages to the ith process. Since the ith process is a copy (fork) of the i-1th process it has already received i-1 messages, and just needs one more. It's a rather symmetrical (and academic) problem.
Here is an example (robust error checking omitted). Note this relies on atomic pipe writes, which is fine as long as you not writing message greater that PIPE_BUF (see man pipe):
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
void syserr(char * msg) { printf("%s\n", msg); exit(1); }
#define NO_PROC 5
#define BUF_SIZE 100
char message[] = "my message ";
int main() {
int message_len = 0;
char buf[BUF_SIZE];
for (int i = 0; i < NO_PROC; ++i) {
int pipe_dsc[2], buf_len;
if (pipe(pipe_dsc) == -1) {
syserr("Error in pipe\n");
}
pid_t pid = fork();
if (pid == -1) {
syserr("Error in fork\n");
}
else if (pid == 0) {
close(pipe_dsc[1]);
int n = read(pipe_dsc[0], buf+message_len, sizeof(buf));
message_len = strlen(buf); // Assume message is null terminated string.
if(i == NO_PROC -1) {
printf("Process %i: received '%s'\n", i+1, buf);
}
}
else {
close(pipe_dsc[0]);
write(pipe_dsc[1], message, sizeof(message));
wait(0);
return 0;
}
}
}

IPC Message queue not works with forked process

I'm trying to use IPC message queue with a forked process, passing a pointer to a dynamically allocated string, but it doesn't work.
This is a simple test that I made. It doesn't print the string received from the queue. But if I try to remove the fork() it works perfectly.
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MSGSZ 128
typedef struct msgbuf {
long mtype;
char *mtext;
} message_buf;
int
main ()
{
int msqid;
char *p;
key_t key = 129;
message_buf sbuf, rbuf;
p = (char *) malloc(sizeof(char) * MSGSZ);
if ((msqid = msgget(key, IPC_CREAT|0666)) < 0) {
perror("msgget");
exit(1);
}
if (fork() == 0) {
strcpy(p, "Did you get this?");
sbuf.mtype = 1;
sbuf.mtext = p;
if (msgsnd(msqid, &sbuf, MSGSZ, IPC_NOWAIT) < 0) {
perror("msgsnd");
exit(1);
}
}
else {
sleep(1);
if (msgrcv(msqid, &rbuf, MSGSZ, 0, 0) < 0) {
perror("msgrcv");
exit(1);
}
printf("Forked version: %s\n", rbuf.mtext);
msgctl(msqid, IPC_RMID, NULL);
}
}
The problem is that you are sending a pointer across process boundaries. Pointers are only valid within the same process and are meaningless when sent/used in another process. In fact, you are sending the pointer value followed by a whole bunch of garbage bytes as themsgbuf.mtext is in fact not MSGSZ bytes in size (so technically invoking Undefined Behaviour).
What you need to do is to declare the buffer inline in the message. That is, change the message_buf definition to be:
typedef struct msgbuf {
long mtype;
char mtext[MSGSZ];
} message_buf;
And then strcpy straight into mtext:
strcpy(sbuf.mtext, "Did you get this?");
For clarity, below is the full program with the changes described:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MSGSZ 128
typedef struct msgbuf {
long mtype;
char mtext[MSGSZ];
} message_buf;
int
main (void)
{
int msqid;
key_t key = 129;
message_buf sbuf, rbuf;
if ((msqid = msgget(key, IPC_CREAT|0666)) < 0) {
perror("msgget");
exit(1);
}
if (fork() == 0) {
strcpy(sbuf.mtext, "Did you get this?");
sbuf.mtype = 1;
if (msgsnd(msqid, &sbuf, MSGSZ, IPC_NOWAIT) < 0) {
perror("msgsnd");
exit(1);
}
}
else {
sleep(1);
if (msgrcv(msqid, &rbuf, MSGSZ, 0, 0) < 0) {
perror("msgrcv");
exit(1);
}
printf("Forked version: %s\n", rbuf.mtext);
msgctl(msqid, IPC_RMID, NULL);
}
}

how the system call read and write behave and why the threads cannot work?

fifo.3 source code:
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <limits.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <pthread.h>
#include <time.h>
#define FIFO_NAME "/tmp/my_fifo"
#define BUFFER_SIZE PIPE_BUF //4096
#define TEN_MEG (1024 * 1024 * 1)
void* thread_tick(void* arg)
{
int count =0;
while(count < 4){
printf("hello, world!\n");
sleep(1);
count++;
}
}
void* thread_write(void* arg)
{
int pipe_fd;
int res;
int bytes_sent = 0;
char buffer[BUFFER_SIZE ];
int count=0;
if (access(FIFO_NAME, F_OK) == -1) {
res = mkfifo(FIFO_NAME, 0777);
if (res != 0) {
fprintf(stderr, "Could not create fifo %s\n", FIFO_NAME);
exit(EXIT_FAILURE);
}
}
while(count < 10){
printf("write: Process %d opening FIFO O_WRONLY\n", getpid());
pipe_fd = open(FIFO_NAME, O_WRONLY);
printf("write: Process %d result %d \n", getpid(), pipe_fd);
if (pipe_fd != -1) {
while(bytes_sent < TEN_MEG) {
res = write(pipe_fd, buffer, BUFFER_SIZE);
if (res == -1) {
fprintf(stderr, "Write error on pipe\n");
exit(EXIT_FAILURE);
}
bytes_sent += res;
}
(void)close(pipe_fd);
}
else {
exit(EXIT_FAILURE);
}
printf("write: Process %d finished , count =%d\n", getpid(),count);
count++;
}
}
void CreateThread(void* (*start_routine)(void*), void* arg,int stacksize, int priority)
{
pthread_t app_thread;
pthread_attr_t thread_attr;
int res;
int max_priority;
int min_priority;
struct sched_param scheduling_value;
res = pthread_attr_init(&thread_attr);
if (res != 0) {
perror("Attribute creation failed\n");
exit(EXIT_FAILURE);
}
res = pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED);
if (res != 0) {
perror("Setting detached attribute failed");
exit(EXIT_FAILURE);
}
res = pthread_attr_setstacksize(&thread_attr, stacksize);
if (res != 0) {
perror("Set stack size failed\n");
exit(EXIT_FAILURE);
}
res = pthread_attr_setschedpolicy(&thread_attr, SCHED_RR);
if (res != 0) {
perror("Setting schedpolicy failed");
exit(EXIT_FAILURE);
}
max_priority = sched_get_priority_max(SCHED_RR);
min_priority = sched_get_priority_min(SCHED_RR);
scheduling_value.sched_priority = priority;
res = pthread_attr_setschedparam(&thread_attr, &scheduling_value);
if (res != 0) {
perror("Setting schedpolicy failed");
exit(EXIT_FAILURE);
}
res = pthread_create(&app_thread, &thread_attr, (*start_routine), arg);
if(res != 0){
perror("Thread creation failed\n");
exit(EXIT_FAILURE);
}
pthread_attr_destroy(&thread_attr);
//res = pthread_join(app_thread ,0 );
//return app_thread;
}
int main()
{
CreateThread(thread_write, 0, 50000, 99);
CreateThread(thread_tick, 0, 50000, 98);
// pthread_join(w,0 );
// pthread_join(t ,0 );
return 0;
}
fifo.4 source code :
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <limits.h>
#include <sys/types.h>
#include <sys/stat.h>
#define FIFO_NAME "/tmp/my_fifo"
#define BUFFER_SIZE PIPE_BUF //4096
int main()
{
int pipe_fd;
int res;
char buffer[BUFFER_SIZE ];
int bytes_read = 0;
int count = 0;
memset(buffer, '\0', sizeof(buffer));
while(count < 10){
printf("read: Process %d opening FIFO O_RDONLY\n", getpid());
pipe_fd = open(FIFO_NAME, O_RDONLY);
printf("read: Process %d result %d\n", getpid(), pipe_fd);
if (pipe_fd != -1) {
do {
res = read(pipe_fd, buffer, BUFFER_SIZE);
bytes_read += res;
} while (res > 0);
(void)close(pipe_fd);
}
else {
exit(EXIT_FAILURE);
}
printf("read: Process %d finished, %d bytes read , count =%d\n", getpid(), bytes_read,count);
count++;
}
return 0;
}
this is the first time I post code on Stack overflow, so it is in a mess.
Above are two C source code. fifo3.c has two thread and thread_write is to write data to named fifo.
fifo4.c is to read data from named fifo.
my question:
1) how does the read(pipe_fd, buffer, BUFFER_SIZE) behave when write() is writing data to fifo? If read() can not read data, SHOULD not read() return 0 and then exit, why read() would wait write() to finish write data??? of course, how does write() behave when read() is reading?
2) in fifo3.c , I create two threads, when I create them detached , the program can not run !!!
but joinable, they could run correctly !!I do not know why!
In theory, they both could function right.
Answer for Question-1:
If read cannot read data it will 'block' till data arrives, this is called blocking mode read. Incase of a blocking mode read, the read call blocks till a data arrives. If you wish to change it to non-blocking mode, you can use fcntl functionality, if the same is supported.
For other queries, it is best that you read about it through man pages as a concise answer will be difficult.
Answer for Question-2:
When you create a thread detached, it means the created threads are not bound to the parent thread which creates it. So, the parent thread will just exit, if it completes it's work. If the parent happens to be the main thread, then when it exits the process also will exit, which will cause program not to run.

Followup to previous question about client/server echo program

Earlier I got some great advice about Client/server sockets in c. I have modified the code slightly and it works fine when I have the server running in one terminal and the clients running in other windows. Now I would like to make a TUI for the program, but I am running into a problem. Since the server is constantly listening for a client it is in an infinite loop; once the server is established nothing else can go on in the terminal. What I thought I should do is use fork() so that the server can be running in the background, leaving the TUI free to create clients. Here is my code so far (again, I cannot take much credit for the client/server code):
Server code
#include <stdio.h>
#include <errno.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
struct sockaddr myname;
char buf[80];
ssize_t readLine(int sockd, char *vptr, size_t maxlen) {
ssize_t n, rc;
char c, *buffer;
buffer = vptr;
for(n = 1; n < maxlen; n++) {
if((rc = read(sockd, &c, 1)) == 1) {
*buffer++ = c;
if(c== '\n')
break;
}
else if(rc == 0){
if(n == 1)
return 0;
else
break;
}
else {
if(errno == EINTR)
continue;
return -1;
}
}
*buffer = 0;
return n;
}
ssize_t modifyBuf(int sockd, char *vptr, size_t n) {
int i, j;
char temp;
for(i = 0, j = n-1; i < j; i++, j--) {
temp = vptr[i];
vptr[i] = vptr[j];
vptr[j] = temp;
}
for(i = 0; i < n; i++)
vptr[i] = toupper(vptr[i]);
return writeLine(sockd,vptr,n);
}
ssize_t writeLine(int sockd, const void *vptr, size_t n) {
size_t nleft;
size_t nwritten;
const char *buffer;
buffer = vptr;
nleft = n;
while(nleft > 0) {
if((nwritten = write(sockd,buffer,nleft)) <= 0){
if(errno == EINTR)
nwritten = 0;
else
return -1;
}
nleft -= nwritten;
buffer += nwritten;
}
return n;
}
makeServer() {
int sock, new_sd, adrlen, cnt;
sock = socket(AF_UNIX, SOCK_STREAM, 0);
if(sock < 0) {
printf("server socket failure %d\n", errno);
perror("server: ");
exit(1);
}
myname.sa_family = AF_UNIX;
strcpy(myname.sa_data, "/tmp/billb");
adrlen = strlen(myname.sa_data) + sizeof(myname.sa_family);
unlink("/tmp/billb"); /*defensive programming */
if(bind(sock, &myname, adrlen) < 0) {
printf("server bind failure%d\n", errno);
perror("server: ");
exit(1);
}
if(listen(sock, 5) < 0) {
printf("server listen failure %d\n", errno);
perror("server: ");
exit(1);
}
while(1) {
if((new_sd = accept(sock, &myname, &adrlen)) < 0) {
printf("server accept failure %d\n", errno);
perror("server: ");
exit(1);
}
printf("Socket address in server %d\n", getpid());
if(fork() == 0) {
close(sock);
readLine(new_sd,buf,999);
modifyBuf(new_sd,buf,strlen(buf));
exit(0);
}
close(new_sd);
}
}
Client code
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
char buf[80];
struct sockaddr myname;
void replyBack(FILE *fp, int sockfd) {
char sendline[1000], recvline[1000];
printf("Enter your echo: \n");
while(fgets(sendline,1000,stdin) != NULL) {
write(sockfd,sendline,sizeof(sendline));
if(read(sockfd,recvline,1000) == 0) {
printf("str_cli: server terminated prematurely");
exit(-1);
}
fputs(recvline, stdout);
}
}
makeClient() {
int sock, adrlen, cnt;
sock = socket(AF_UNIX, SOCK_STREAM, 0);
if(sock < 0) {
printf("client socket failure%d\n", errno);
printf("client: ");
exit(1);
}
myname.sa_family = AF_UNIX;
strcpy(myname.sa_data, "/tmp/billb");
adrlen = strlen(myname.sa_data) + sizeof(myname.sa_family);
if((connect(sock, &myname, adrlen)) < 0) {
printf("client connect failure %d\n", errno);
perror("client: ");
exit(1);
}
replyBack(stdin,sock);
exit(0);
}
TUI
#include <stdio.h>
#include </server.c>
#include </client.c>
void displayWelcomeMessage(){
....
}
void showChoices(){
printf("\nTo make a new client, enter 1.\n");
printf("To close server, enter 2.\n");
printf(">>> ");
int choice;
scanf("%d",&choice);
if(choice == 1){
makeClient();
showChoices();
} else if(choice == 2){
printf("Goodbye.");
exit(0);
} else
printf("Invalid choice.\n");
showChoices();
}
void main() {
displayWelcomeMessage();
printf("Server is now listening for clients.\n");
if(fork() == 0)
makeServer();
if(fork() > 0)
showChoices();
}
The TUI should create the server when it is executed and then show a short menu. The user can chose to create a new client or exit the program. If the user creates a client then the user should be prompted for a message to send to the server; once the message is sent back the menu should be shown again. If the user elects to exit the program then the program will terminate and the socket should close. If the user makes an invalid choice, then the menu should display again.
What is happening is the server is created and I can see the menu, but if I select to create a new client the program terminates or terminates after I input any text + enter (so the message is not getting sent to the server). Like I said, the client/server works without the TUI so I believe the problem is in my usage of fork(), but I'm not sure what other way there is to solve this problem.
Phew, that was long. Thank you for your time!
You seem to be calling fork() twice - surely you only want to call it once? I think your code should be:
if(fork() == 0)
makeServer();
else
showChoices();
Also, you may want to investigate the use of wait(), which will allow you to wait for a child process to complete.

Resources