views:

74

answers:

2

Hi experts,

I'm trying to reproduce an example from Network Security with OpenSSL (by Chandra et al). The program consists of client.c server.c common.h and common.c. client.c simply creates a connection to the server on port 6012 and reads data from stdin and then send those data to the server. The server.c reads data from socket and writes it back out to stdout.

The problem is that server.c always get stuck in if(BIO_do_accept(acc) <= 0) at line 62 and never gets data sent from client.c, which runs perfectly fine. I later found the problem is that pthread_create(...) at line 66 ( which is defined as THREAD_CREATE(...) in common.h) failed and it returned 4294967295. Because THREAD_CREATE(...) failed, the program never get a chance to run do_server_loop in server_thread(...), which explains why the server never got the data from client.

How should I interpret the return values from pthread_create and how should I fix it? PS. I later used strerror to convert 4294967295 and it returned "Unknown error".

Any help will be much appreciated!

//////////////////////////////////////////////////

Here is server.c:

#include "common.h" 
void do_server_loop(BIO *conn)
{
    int err, nread;
    char buf[80];

    do
    {
        fprintf(stderr, "server_loop executed.\n");
        for(nread = 0; nread < sizeof(buf); nread += err)
        {
            err = BIO_read(conn, buf + nread, sizeof(buf) - nread);
            if(err <= 0){
                break;
            }
        }
        fwrite(buf, 1, nread, stdout);
    }
    while (err > 0);
}

void THREAD_CC server_thread(void *arg)
{
    fprintf(stderr, "server_thread(void *arg) executed.\n");
    BIO *client = (BIO *)arg;
#ifndef WIN32
    pthread_detach(pthread_self());
#endif
    fprintf(stderr, "Connection opened.\n");
    do_server_loop(client);
    fprintf(stderr, "Connection closed.\n");

    BIO_free(client);
    ERR_remove_state(0);
#ifdef WIN32
    _endthread();
#else
    return 0;
#endif
}


int main(int argc, char *argv[])
{
    BIO     *acc, *client;
    int thread_create_result;
    THREAD_TYPE tid;

    init_OpenSSL();

    acc = BIO_new_accept(PORT);
    if(!acc){
        int_error("Error creating server socket");
    }

    if(BIO_do_accept(acc) <= 0){
        int_error("Error binding server socket");   
    }
    for(;;)
    {
        if(BIO_do_accept(acc) <= 0){
            int_error("Error accepting connection");
        }
        client = BIO_pop(acc);
        thread_create_result = THREAD_CREATE(tid, server_thread, client);
        if(thread_create_result != 0){
            fprintf(stderr, "THREAD_CREATE failed! returns: %s.\n", \
                                            strerror(thread_create_result));
            fprintf(stderr, "thread_create_result has the value: %u.\n", \
                                            thread_create_result);
            exit(-1);
        }
    }

    BIO_free(acc);
    return 0;
}

Here is common.h

#include <errno.h>
#include <fcntl.h>
#include <netdb.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <openssl/bio.h>
#include <openssl/err.h>
#include <openssl/hmac.h>
#include <openssl/objects.h>
#include <openssl/rand.h>
#include <openssl/ssl.h>
#include <openssl/x509.h>
#include <openssl/x509v3.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>


#ifndef WIN32
#include <pthread.h>
#define THREAD_CC *
#define THREAD_TYPE         pthread_t
#define THREAD_CREATE(tid, entry, arg)  pthread_create(&(tid), NULL, \
                                   (entry), (arg))
#else
#include <windows.h>
#include <process.h>
#define THREAD_CC              __cdecl
#define THREAD_TYPE            DWORD
#define THREAD_CREATE(tid, entry, arg) do { _beginthread((entry), 0, (arg));\
                        (tid) = GetCurrentThreadId();\
                       } while (0)
#endif

#define PORT    "6012"      //port
#define SERVER  "10.1.251.24"   //server address
#define CLIENT  "10.1.21.46"    //client address

#define int_error(msg) handle_error(__FILE__, __LINE__, msg)
void handle_error(const char *file, int lineno, const char *msg);

void init_OpenSSL(void);

Makefile:

CC = gcc
OPENSSLDIR = /usr/local/ssl
#CFLAGS = -g -Wall -W -I${OPENSSLDIR}/include -O2 -D_REENTRANT -D__EXTENSIONS__  
CFLAGS = -g -Wall -W -I${OPENSSLDIR}/include -O2

RPATH = -R${OPENSSLDIR}/lib
#LD = ${RPATH} -L${OPENSSLDIR}/lib -lssl -lcrypto -lsocket -lnsl -lpthread
LD = -L${OPENSSLDIR}/lib -lssl -lcrypto -lsocket -lnsl -pthread

OBJS = common.o

PROGS = server

all: ${PROGS}

server: server.o ${OBJS}
        ${CC} server.o ${OBJS} -o server ${LD}


clean:;
        ${RM} ${PROGS} *.ln *.BAK *.bak *.o
+2  A: 

Change

if(thread_create_result = !0){

to

if(thread_create_result != 0){

Besides, you can use strerror function to convert error code to human-readable form.

adf88
@adf88: thanks! I updated my code and added "fprintf(stderr, "THREAD_CREATE failed! returns: %s.\n", strerror(thread_create_result));" at line 68. Here is what the program returned: THREAD_CREATE failed! returns: Unknown error.thread_create_result has the value: 4294967295.
Z.Zen
@adf88: I checked the listed error codes from pthread_create but couldn't find the one I got. Thanks!
Z.Zen
4294967295 is just the unsigned version of -1.
Amardeep
@Amardeep: so what does it mean? I just used strerr(-1) and it still returned "Unknown error."
Z.Zen
@Amardeep: I also used strerror(errno) and it returned "Error 0". I got really confused :(
Z.Zen
@Z.Zen - strerror() is for C library error codes, not POSIX error codes. The return value of pthread_create() is one of several values defined in pthread.h: EAGAIN, EINVAL, and EPERM. Check the man page of your target system to see the comprehensive list.
Amardeep
@Amardeep: I managed to fix the problem by adding -D_REENTRANT on compile command line and -lthread on the link command line. The reason why my program did nothing when it hit pthread_create is because I didn't tell C libraries that the program is using multi-thread mode. Now it's working perfectly!
Z.Zen
@Z.Zen - Assuming you are using gcc, the only parameter you should provide is `-pthread`, which generates all flags necessary for multi-threaded operation. The problem may have been that you were only using `-lpthread` (note the letter l) which only links in the library but doesn't set the flags. You managed to do it manually, but that may not set **all** flags needed by a platform.
Amardeep
You get -1 because you assigned `!0` to `thread_create_result` which is -1
adf88
@adf88: I updated the server.c right after you posted your answer. It stopped returning 1 but it started returning 4294967295, which "is just the unsigned version of -1", according to Amardeep. But I figured out how to do it and it now works fine. Thanks!
Z.Zen
@Amardeep: I tried '-pthread' but my gcc compiler returned 'gcc: unrecognized option `-pthread''. I'm using gcc 3.4.6. I just posted my Makefile above. The commented lines are those I used before. Thanks!
Z.Zen
Are you using gcc under cygwin? That doesn't support -pthread.
Amardeep
@Amardeep: no. I'm just using gcc under Solaris 9 terminal.
Z.Zen
A: 

add -D_REENTRANT on compile command lines and -lpthread on the link command line. -D_REENTRANT will tell C/C++ libraries that your program is in multithread mode and -lpthread just load the shared library libpthread.so at runtime. I found this at William Garrison's POSIX threads tutorial and this link.

Here is the Makefile:

CC = gcc
OPENSSLDIR = /usr/local/ssl
CFLAGS = -g -Wall -W -I${OPENSSLDIR}/include -O2 -D_REENTRANT -D__EXTENSIONS__  

RPATH = -R${OPENSSLDIR}/lib
LD = ${RPATH} -L${OPENSSLDIR}/lib -lssl -lcrypto -lsocket -lnsl -lpthread

OBJS = common.o

PROGS = server

all: ${PROGS}

server: server.o ${OBJS}
        ${CC} server.o ${OBJS} -o server ${LD}


clean:;
        ${RM} ${PROGS} *.ln *.BAK *.bak *.o
Z.Zen