How to use the C socket API in C++ on z/OS

Viewed 15620

I'm having issues getting the C sockets API to work properly in C++ on z/OS.

Although I am including sys/socket.h, I still get compile time errors telling me that AF_INET is not defined.

Am I missing something obvious, or is this related to the fact that being on z/OS makes my problems much more complicated?

I discovered that there is an #ifdef that I'm hitting. Apparently z/OS isn't happy unless I define which "type" of sockets I'm using with:

#define _OE_SOCKETS

Now, I personally have no idea what this _OE_SOCKETS is actually for, so if any z/OS sockets programmers are out there (all 3 of you), perhaps you could give me a rundown of how this all works?

Test App

#include <sys/socket.h>

int main()
{
    return AF_INET;
}

Compile/Link Output:

cxx -Wc,xplink -Wl,xplink -o inet_test inet.C

"./inet.C", line 5.16: CCN5274 (S) The name lookup for "AF_INET" did not find a declaration.
CCN0797(I) Compilation failed for file ./inet.C. Object file not created.

A check of sys/sockets.h does include the definition I need, and as far as I can tell, it is not being blocked by any #ifdef statements.

I have however noticed it contains the following:

#ifdef __cplusplus
  extern "C" {
#endif

which encapsulates basically the whole file? Not sure if it matters.

9 Answers

I've had no trouble using the BSD sockets API in C++, in GNU/Linux. Here's the sample program I used:

#include <sys/socket.h>

int
main()
{
    return AF_INET;
}

So my take on this is that z/OS is probably the complicating factor here, however, because I've never used z/OS before, much less programmed in it, I can't say this definitively. :-P

See the Using z/OS UNIX System Services sockets section in the z/OS XL C/C++ Programming Guide. Make sure you're including the necessary header files and using the appropriate #defines.

The link to the doc has changed over the years, but you should be able to get to it easily enough by finding the current location of the Support & Downloads section on ibm.com and searching the documentation by title.

So try

#define _OE_SOCKETS

before you include sys/socket.h

The _OE_SOCKETS appears to be simply to enable/disable the definition of socket-related symbols. It is not uncommon in some libraries to have a bunch of macros to do that, to assure that you're not compiling/linking parts not needed. The macro is not standard in other sockets implementations, it appears to be something specific to z/OS.

Take a look at this page:
Compiling and Linking a z/VM C Sockets Program

@Jax: The extern "C" thing matters, very very much. If a header file doesn't have one, then (unless it's a C++-only header file), you would have to enclose your #include with it:

extern "C" {
#include <sys/socket.h>
// include other similarly non-compliant header files
}

Basically, anytime where a C++ program wants to link to C-based facilities, the extern "C" is vital. In practical terms, it means that the names used in external references will not be mangled, like normal C++ names would. Reference.

You may want to take a look to cpp-sockets, a C++ wrapper for the sockets system calls. It works with many operating systems (Win32, POSIX, Linux, *BSD). I don't think it will work with z/OS but you can take a look at the include files it uses and you'll have many examples of tested code that works well on other OSs.

DISCLAIMER: I am not a C++ programmer, however I know C really well. I adapated these calls from some C code I have.

Also markdown put these strange _ as my underscores.

You should just be able to write an abstraction class around the C sockets with something like this:

class my_sock {
    private int sock;
    private int socket_type;
    private socklen_t sock_len;
    private struct sockaddr_in server_addr;
    public char *server_ip;
    public unsigned short server_port;
};

Then have methods for opening, closing, and sending packets down the socket.

For example, the open call might look something like this:

int my_socket_connect()
{
    int return_code = 0;

    if ( this->socket_type != CLIENT_SOCK ) {
        cout << "This is a not a client socket!\n";
        return -1;
    }

    return_code = connect( this->local_sock, (struct sockaddr *) &this->server_addr, sizeof(this->server_addr));

    if( return_code < 0 ) {
        cout << "Connect() failure! %s\n", strerror(errno);
        return return_code;
    }

    return return_code;
}
Related