I know, Windows doesn't use UNIX sockets while Mac OS does. Until this point my software was cross-platform without any code changes. But now I want it to do some network communication. I know about POSIX sockets, but I know nothing about Windows' ones. The goal is to implement a simple cross-platform socket server.
Could you please explain to me the differences between POSIX and Winsock sockets and how I may go about writing cross platform networking code?
WinSock versus POSIX Sockets
WinSock and POSIX sockets work in a similar manner - mainly because Windows sockets were originally based on code from BSD:
Although these proprietary BSD derivatives were largely superseded by the UNIX System V Release 4 and OSF/1 systems in the 1990s (both of which incorporated BSD code and are the basis of other modern Unix systems), later BSD releases provided a basis for several open source development projects, e.g. FreeBSD, OpenBSD, NetBSD, Darwin or PC-BSD, that are ongoing. These, in turn, have been incorporated in whole or in part in modern proprietary operating systems, e.g. the TCP/IP (IPv4 only) networking code in Microsoft Windows and most of the foundation of Apple's OS X and iOS.
However, there are a few things you'll need to handle differently if you want to write "socket-library-agnostic" code.
Note: The following examples have been tested using Code::Blocks and GCC on Windows XP (x86) and Debian Testing (AMD64).
The header and lib files are different
You'll need to include different header files depending on whether you're using Windows or not:
#ifdef _WIN32
/* See http://stackoverflow.com/questions/12765743/getaddrinfo-on-win32 */
#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x0501 /* Windows XP. */
#endif
#include <winsock2.h>
#include <Ws2tcpip.h>
#else
/* Assume that any non-Windows platform uses POSIX-style sockets instead. */
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netdb.h> /* Needed for getaddrinfo() and freeaddrinfo() */
#include <unistd.h> /* Needed for close() */
#endif
You'll also need to link with Ws2_32 lib file on Windows.
WinSock requires initialisation and cleanup.
The functions below illustrate how you can initialise WinSock v1.1 and clean up afterwards:
int sockInit(void)
{
#ifdef _WIN32
WSADATA wsa_data;
return WSAStartup(MAKEWORD(1,1), &wsa_data);
#else
return 0;
#endif
}
int sockQuit(void)
{
#ifdef _WIN32
return WSACleanup();
#else
return 0;
#endif
}
Socket handles are UNSIGNED on Winsock
For POSIX-style sockets, you can simply use int to store a socket handle. Invalid sockets are indicated by a negative value.
However, WinSock sockets are UNSIGNED integers, with a special constant (INVALID_SOCKET) used instead of negative numbers.
You can abstract the differences by typedefing SOCKET as int on POSIX and hiding the "valid socket" check behind a macro or function.
Sockets are closed differently
The function below illustrates the differences:
/* Note: For POSIX, typedef SOCKET as an int. */
int sockClose(SOCKET sock)
{
int status = 0;
#ifdef _WIN32
status = shutdown(sock, SD_BOTH);
if (status == 0) { status = closesocket(sock); }
#else
status = shutdown(sock, SHUT_RDWR);
if (status == 0) { status = close(sock); }
#endif
return status;
}
In general though, they're pretty similar.
If you stick to "common" functions (such as send() or recv()) and avoid platform-specific stuff (such as WSAWaitForMultipleEvents()) then you should be fine.
I can also suggest the plibsys library: works on both Windows and UNIX systems (see the full list on the project page) with various compilers. Supports IPv4 and IPv6. It has the tests where you can see the usage examples. The library itself is lightweight and portable.
There are many libraries and toolkits that support cross platform sockets, depending on what you are doing, you can use (to name a few):
openssl
apache portable runtime
libtcl
If you don't want to have a dependency on an external library, all of the above packages have fairly permissive licenses, so you can use their code as a reference.
The regular sockets (those in AF_INET address family) which you need to build a socket server are equally supported on all platforms.
Do not confuse them with Unix sockets (those in AF_UNIX address family) - such sockets are highly specific for a Unix world, and are used for a highly specific goals. You wouldn't ever need them for a simple socket server application.
Related
The Linux kernel added a user space API to its crypto functions at 2.6 via a new new socket family AF_ALG. Also see crypto: af_alg - User-space interface for Crypto API on LWN.
I'm working with Gentoo, and it requires one to configure and build the kernel. It appears the default settings omit AF_ALG, so I'm [currently] working with a kernel that lacks the support. OpenSSL 1.1.0 has an Engine interface into the crypto API. Its failing its self tests due to lack of support for AF_ALG.
I'd like to know how to detect availability of AF_ALG at both compile time and runtime. I have not found a way to detect availability at compile time. I think we can use alg_get_type to detect runtime availability, but I'm not certain.
How can I determine availability of AF_ALG at compile time and at runtime?
The socket(2) man pages has this to say: "Some socket types may not be implemented by all protocol families." But it does not discuss how to detect availability.
The kernel docs cover the API in Chapter 4. User Space Interface, but it does not appear to discuss how to detect availability.
For completeness, it looks like the following kernel configuration parameters need to be set for Gentoo (from Marek Vašut's Utilizing the crypto accelerators):
CONFIG_CRYPTO_USER_API=m
CONFIG_CRYPTO_USER_API_HASH=m
CONFIG_CRYPTO_USER_API_SKCIPHER=m
I'd say the only way to detect at compile time is to write a separate program that will do a runtime check for AF_ALG sockets and create a header file with a define such as #define AF_ALG_AVAILABLE.
Expanding on your answer to the second question, you may want to make sure errno holds EAFNOSUPPORT. Otherwise, another error, such as being out of file descriptors, will make your program falsely believe that AF_ALG is not supported, which could be bad if you are checking for AF_ALG at compile time using my method.
Checking at compile time:
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <linux/if_alg.h>
int main(){
//Alternatively you can set the path to argv[1]
FILE *f = fopen("/path/to/output/file", "w");
if(f == NULL){
//Handle error
}
int sockfd = socket(AF_ALG, SOCK_SEQPACKET, 0);
if(sockfd == -1){
if(errno == EAFNOSUPPORT){
//Unavailable, put whatever you want here
fprintf(f, "#define AF_ALG_UNAVAILABLE\n");
} else {
//Unable to detect for some other error
}
} else { //AF_ALG is available
fprintf(f, "#define AF_ALG_AVAILABLE\n");
}
close(sockfd);
fclose(f);
return 0;
}
Then just compile and run that in your makefile, and you will find your header file where you put it. Then you can simply select what code to use using #ifdef AF_ALG_AVAILABLE.
I think I can answer some of the second question, runtime availability, with the following:
int ret = socket(AF_ALG, SOCK_SEQPACKET, 0);
if (ret != -1)
close(ret);
int supported = ret != -1;
I want to create a Pseudo Terminal using the BSD API. My understanding is that the Unix 98 API will automatically find a free port with posix_openpt() but with BSD API I need to check/find a free port to connect to. Is this correct?
So I need to do something like this...?
int fd, index = 0;
char serial_port[11]; // = "/dev/ptyp0"
while (true) {
sprintf(serial_port, "/dev/ptyp%d", index);
fd = open(serial_port, O_RDWR | O_NOCTTY | O_NONBLOCK);
if (fd > 0)
break;
index++;
}
Do you know of a Pseudo Terminal tutorial that uses BSD? There are many using Unix 98 API but not many if any BSD API ones.
Using the actual device path is problematic because the pathnames can differ from system to system. Most portable applications which use pseudo terminals long ago were changed to use one of the library functions written to abstract away from the device path.
There is more than one flavor of BSD to consider, e.g., FreeBSD, NetBSD, OpenBSD (and others of course, including OSX). xterm's configure script identifies features from each. All have openpty in the "util" library, providing its prototype in util.h
POSIX provides posix_openpt which combines the functionality of openpty with others to provide a simpler interface. However (though a documented interface), it is known to not work properly with OSX (see for example OSX 10.7.5 UTF-8 encoding over ssh as well as xterm's changelog).
Here are manpage links:
FreeBSD
NetBSD
OpenBSD
OSX
When building the Apple's implementation of mDNS, aka. Bonjour, aka. mDNSResponder for a posix system (http://www.opensource.apple.com/tarballs/mDNSResponder/) [*]
On a clean Ubuntu 14.04 build box (with only build-essentials, g++), the compiled examples fail to work, and report "bind: Address already in use".
On a clean Debian 7 build box (with only build-essentials, g++), the compiled examples work, and do not report "bind: Address already in use".
What is going on here?
[*] which... is just riddled with bugs. For sanity, I suggest using versions 333.10, or 541, and applying patches from the umondo project: https://github.com/tklab-tud/umundo/tree/master/contrib/archives
The problem is due to the following difference in /usr/include/asm-generic/socket.h
The socket.h in question is part of the linux-libc-dev package.
In Debian, socket.h is from version 3.2.65 of linux-libc-dev, and contains contains the commented line
/* To add :#define SO_REUSEPORT 15 */
On Ubuntu, linux-libc-dev is version 3.13.0. socket.h. Here, that line is no longer commented out:
#define SO_REUSEPORT 15
Of course, the problem is not with linux-libc-dev, but the use of this macro, in mDNSPosix.c, in particular, the lines:
#if defined(SO_REUSEPORT)
err = setsockopt(*sktPtr, SOL_SOCKET, SO_REUSEPORT, &kOn, sizeof(kOn));
#elif defined(SO_REUSEADDR)
err = setsockopt(*sktPtr, SOL_SOCKET, SO_REUSEADDR, &kOn, sizeof(kOn));
#else
#error This platform has no way to avoid address busy errors on multicast.
#endif
By just swapping the order, to prioritize SO_REUSEADDR, there is no longer a socket binding issue. I.e.:
#if defined(SO_REUSEADDR)
err = setsockopt(*sktPtr, SOL_SOCKET, SO_REUSEADDR, &kOn, sizeof(kOn));
#elif defined(SO_REUSEPORT)
err = setsockopt(*sktPtr, SOL_SOCKET, SO_REUSEPORT, &kOn, sizeof(kOn));
#else
#error This platform has no way to avoid address busy errors on multicast.
#endif
Note: This change has not been tested in BSD, which, if I understand correctly, should perhaps keep the priority in the order it was.
You're running into the differences between SO_REUSEADDR AND SO_REUSEPORT.
SO_REUSEPORT was introduced in later Linux kernels and it appears the Ubuntu system image has support for it. Take a look at this question for all you could ever want to know about REUSADDR/REUSEPORT.
The behavioral differences between REUSEADDR and REUSEPORT are that REUSEPORT places more restrictions on the sockets trying to reuse the same port: they all have to have the option set and exist within the same process. That's not the case with REUSEADDR.
Is it possible your Ubuntu image is also running another mDNS daemon like avahi? You can run netstat to diagnose the other bound sockets in the system to identify the port collisions
I'm working on a serial port library, and I am thinking on using the major/minor mode
of the character device to check whether the given file is a platform serial port, a
pty or a usb serial port, in complement of using other frameworks that exist under
Linux or OSX.
Actually, for finding out whether a file is an USB serial port, or a platform serial
port, there are ways using the available frameworks, like libudev on linux or IOKit
on OSX. But I think that for checking a PTY file, the only way is using good old
stat():
#if defined(OS_LINUX)
#define PTY_MAJOR_NODE 136
#elif defined(OS_MAC)
#define PTY_MAJOR_NODE 16
#elif defined(OS_SOLARIS)
#define PTY_MAJOR_NODE 24
#endif
bool is_pty(const char* file) {
struct stat filestat;
if (0 == stat(file, &filestat)
&& S_ISCHR(filestat.st_mode)
&& major(filestat.st_rdev) == PTY_MAJOR_NODE) {
return true;
}
return false;
}
So far I found out on my debian linux that the PTS chardev all have a major mode of
136, and on my OSX, all PTS have a mode of 16. Crawling on ddg, I found out
Solaris may use a major mode of 24.
I could find many resources online talking about what are PTY/PTS and their history.
The manpage of openpty, pty or pts - though that one give major and
minor of /dev/ptmx - do not talk about major/minor mode of PTS devices. And no
resource listing the Major modes accross unices.
So here are my questions:
are the major mode of PTS (and by extension other serial chardev) stable for a given Unix flavor? (I'm looking for something stable at ±2 years)
where are those defined? I guess it's a kernel driver that handles that, isn't it?
is it a good idea to rely on major mode of the chardev to detect what kind of device this is?
N.B.: I have hesitated to post on unix.SE, but as I'm in the context of using that
in code, I considered this is more a question to ask here, on SO.
Edit: I posted a related question on unix.SE asking for help finding other major modes and look how stable they are accross systems. My guess is that if nobody has an answer, at least we can query the systems and look at the sources.
Major and minor device numbers are defined at compile or link/load time depending on the hardware involved. Adding an additional SBUS card to a Solaris machine might (must?) have an arbitrary major device number. I know mine did.
In short, I don't think major/minor device numbers are going to do what you want.
Consider Debian Linux Ports https://www.debian.org/ports
I can't imagine that the SPARC, s390, MIPS, PowerPC, and ARM architectures all use the same major/minor numbers; the bus architectures are too different.
I'm trying to figure out how to use pseudo-terminal's in linux, essentially I want to create a telnetd clone, something I mentioned in an earlier question.
I understand the concept of master and slave terminal, and I have a basic grasp on how to use syscalls in C.
My question concerns the next step after opening a slave / master file descriptor. How to I launch getty in the slave? Are there any good resources on the net for using the forkpty(), openpty(),or another API?
Some examples in C would help. This was a very similar question, but no one really provided any examples.
Advanced Programming in the Unix Environment, 2nd Edition has a superb chapter on the pseudo-terminal layer available in Linux. The best part is the source code which contains a pty driver and very clearly demonstrates how to use the pty interfaces. (The pty program it builds is useful in its own right if you want to drive a terminal-only program programmatically but don't wish to use expect(1).)
include
#include <sys/stat.h>
#include <fcntl.h>
#define _XOPEN_SOURCE
#include <stdlib.h>
int main(int argc, char **argv)
{
char *slavename;
int masterfd;
masterfd = open("/dev/ptmx", O_RDWR);
grantpt(masterfd);
unlockpt(masterfd);
slavename = ptsname(masterfd);
...
}
I posted simple example of demonstrating pseudo terminal master slave concept. please go through this link to get clear understanding of terminals in Linux
http://www.linusakesson.net/programming/tty/
You don't lauch a getty for ptys. The getty is only the "listener" part of the process. For hardwired terminals, each individual terminal-device is "listening" constantly. For telnet, the daemon does the listening part(on a socket), and handles connection request by creating a pty pair, and fork()ing / exec()ing.
And indeed: APUE handles ptys very well.