📄 sysdep.c
字号:
/* $Header: /home/jcb/newmj/RCS/sysdep.c,v 11.16 2003/10/08 19:35:42 jcb Rel $ * sysdep.c * By intention, this file contains all functions that might need * fiddling with to cope with different variants of Unix. * In particular, all the networking code is in here. * Some parts of the other code assume POSIXish functions for file * descriptors and the like; this file is responsible for providing them * if they're not native. All such cases that occurred to me as I was * writing them can be found by searching for sysdep.c in the other * files. *//****************** COPYRIGHT STATEMENT ********************** * This file is Copyright (c) 2000 by J. C. Bradfield. * * Distribution and use is governed by the LICENCE file that * * accompanies this file. * * The moral rights of the author are asserted. * * * ***************** DISCLAIMER OF WARRANTY ******************** * This code is not warranted fit for any purpose. See the * * LICENCE file for further information. * * * *************************************************************/static const char rcs_id[] = "$Header: /home/jcb/newmj/RCS/sysdep.c,v 11.16 2003/10/08 19:35:42 jcb Rel $";#include "sysdep.h"#include <string.h>#include <fcntl.h>#ifndef WIN32#include <sys/socket.h>#include <netinet/in.h>/* needed for HP-UX 11 with _XOPEN_SOURCE_EXTENDED */#include <arpa/inet.h>#include <sys/un.h>/* this is modern, I think. */#include <netdb.h>#include <pwd.h>#endif /* not WIN32 */#include <stdlib.h>#include <stdarg.h>#include <time.h>#include <signal.h>#ifdef WIN32#include <io.h>#include <fcntl.h>#endif/* warn: = fprintf(stderr,...), with automatic new line *//* log_msg is a generalized version with a syslog like warning level. Currently only two levels are defined by the LogLevel enum, LogWarning and LogInfo. */int (*log_msg_hook)(LogLevel l,char *);static char *log_prefixes[] = { "" , "-I- ", "+W+ " };/* internal function */static int vlog_msg(LogLevel l, char *format,va_list args) { char buf[1024]; int ret; int n; strcpy(buf,log_prefixes[l]); n = strlen(log_prefixes[l]); /* My Windows/Mingw installation doesn't have vsnprintf! Oh well, we'll just hope it doesn't overflow. */#ifdef WIN32 ret = vsprintf(buf+n,format,args);#else /* reserve 1 char for extra '\n' */ ret = vsnprintf(buf+n,sizeof(buf)-n-1,format,args);#endif buf[1023] = 0; n = strlen(buf); /* do quick check for terminators */#ifdef WIN32 if ( buf[n-2] == '\r' ) { /* OK */ ; } else if ( buf[n-1] == '\n' ) { /* already have unix terminator */ buf[n-1] = '\r' ; buf[n] = '\n' ; buf[n+1] = 0 ; } else { /* no terminator */ strcat(buf,"\r\n"); }#else if ( buf[n-1] != '\n' ) strcat(buf,"\n");#endif /* call the hook */ if ( log_msg_hook == NULL || log_msg_hook(l,buf) == 0 ) { fprintf(stderr,"%s",buf); } return ret;}int log_msg(LogLevel l,char *format,...) { va_list args; va_start(args,format); return vlog_msg(l,format,args);}int warn(char *format,...) { va_list args; va_start(args,format); return vlog_msg(LogWarning,format,args);}int info(char *format,...) { va_list args; va_start(args,format); return vlog_msg(LogInfo,format,args);}/* ignore the SIGPIPE signal. Return 0 on success, -1 on error */int ignore_sigpipe(void) {#ifdef WIN32 return 0;#else /* this is just posix at present */ struct sigaction act; act.sa_handler = SIG_IGN; sigemptyset(&act.sa_mask); act.sa_flags = 0; return sigaction(SIGPIPE,&act,NULL);#endif /* WIN32 */}/* functions to be applied by the socket routines */static void *(*skt_open_transform)(SOCKET) = NULL;static int (*skt_closer)(void *) = NULL;static int (*skt_reader)(void *, void *, size_t) = NULL;static int (*skt_writer)(void *, const void *,size_t) = NULL;static int sockets_initialized = 0;#ifdef WIN32static void shutdown_sockets(void) { WSACleanup(); /* I don't care what it returns */}#endif /* WIN32 *//* initialize sockets */int initialize_sockets(void *(*open_transform)(SOCKET), int (*closer)(void *), int (*reader)(void *, void *, size_t), int (*writer)(void *, const void *,size_t)) { skt_open_transform = open_transform; skt_closer = closer; skt_reader = reader; skt_writer = writer;#ifdef WIN32 if ( ! sockets_initialized ) { WORD version; WSADATA data; int err; version = MAKEWORD( 2, 2 ); err = WSAStartup( version, &data ); if (err != 0) { return 0; } if ((LOBYTE( data.wVersion ) != 2) || (HIBYTE( data.wVersion ) != 2)) { WSACleanup(); return 0; } if ( atexit(shutdown_sockets) != 0 ) { warn("couldn't register socket shutdown routine"); } }#endif /* WIN32 */ sockets_initialized = 1; return 1;}/* this function takes a string and parses it as an address. It returns 0 for an Internet address, 1 for a Unix address. For Internet addresses, the host name and port are placed in the given variables (the string had better be long enough); for Unix, the file name is copied to the given variable.*/static int parse_address(const char *address, char *ret_host, unsigned short *ret_port, char *ret_file) { if ( strchr(address,':') ) { /* grrr */ if ( address[0] == ':' ) { strcpy(ret_host,"localhost"); sscanf(address,":%hu",ret_port); } else { sscanf(address,"%[^:]:%hu",ret_host,ret_port); } return 0; } else { if ( ret_file) strcpy(ret_file,address); return 1; }}/* set_up_listening_socket: Set up a socket listening on the given address. Return its fd.*/SOCKET set_up_listening_socket(const char *address) { SOCKET sfd; struct protoent *prstruc = NULL; struct sockaddr_in inaddr;#ifndef WIN32 struct sockaddr_un unaddr;#endif int unixsockets; unsigned short port; char name[256]; int sockopt; if ( ! sockets_initialized ) initialize_sockets(NULL,NULL,NULL,NULL); unixsockets = #ifdef WIN32 parse_address(address,name,&port,NULL);#else parse_address(address,name,&port,unaddr.sun_path);#endif /* WIN32 */#ifdef WIN32 if ( unixsockets ) { warn("unix sockets not available on Windows"); return INVALID_SOCKET; }#endif /* WINDOWS */ if ( !unixsockets ) { prstruc = getprotobyname("tcp"); if ( prstruc == NULL ) { perror("getprotobyname failed"); return INVALID_SOCKET; } } sfd = socket(unixsockets ? AF_UNIX : AF_INET, SOCK_STREAM, unixsockets ? 0 : prstruc->p_proto); if ( sfd == INVALID_SOCKET ) { perror("socket failed"); return INVALID_SOCKET; } sockopt=1; setsockopt(sfd,SOL_SOCKET,SO_REUSEADDR,(void *)&sockopt,sizeof(int));#ifndef WIN32 if ( unixsockets ) { unaddr.sun_family = AF_UNIX; unlink(unaddr.sun_path); /* need to check success FIXME */ if ( bind(sfd,(struct sockaddr *)&unaddr,sizeof(struct sockaddr_un)) < 0 ) { perror("bind failed"); return INVALID_SOCKET; } } else {#else if ( 1 ) {#endif /* WIN32 */ inaddr.sin_family = AF_INET; inaddr.sin_port = htons(port); inaddr.sin_addr.s_addr = INADDR_ANY; if ( bind(sfd,(struct sockaddr *)&inaddr,sizeof(struct sockaddr_in)) < 0 ) { perror("bind failed"); return INVALID_SOCKET; } } if ( listen(sfd,5) < 0 ) { perror("listen failed"); return INVALID_SOCKET; } if ( skt_open_transform ) { return (SOCKET) skt_open_transform(sfd); } else { return sfd; }} /* accept_new_connection: A connection has arrived on the socket fd. Accept the connection, and return the new fd, or INVALID_SOCKET on error.*/SOCKET accept_new_connection(SOCKET fd) { SOCKET newfd; struct sockaddr saddr; struct linger l = { 1, 1000 } ; /* linger on close for 10 seconds */ socklen_t saddrlen = sizeof(saddr); if ( ! sockets_initialized ) initialize_sockets(NULL,NULL,NULL,NULL); newfd = accept(fd,&saddr,&saddrlen); if ( newfd == INVALID_SOCKET ) { perror("accept failed"); } /* we should make sure that data is sent when this socket is closed */ if ( setsockopt(newfd,SOL_SOCKET,SO_LINGER,(void *)&l,sizeof(l)) < 0 ) { warn("setsockopt failed"); } if ( skt_open_transform ) { return (SOCKET) skt_open_transform(newfd); } else { return newfd; }}/* connect_to_host: Establish a connection to the given address. Return the file descriptor or INVALID_SOCKET on error. If unixsockets, only the port number is used in making the name The returned socket is marked close-on-exec .*/SOCKET connect_to_host(const char *address) { SOCKET fd; struct sockaddr_in inaddr;#ifndef WIN32 struct sockaddr_un unaddr;#endif char name[512]; int unixsockets; unsigned short port; struct hostent *hent = NULL; struct protoent *prstruc = NULL; if ( ! sockets_initialized ) initialize_sockets(NULL,NULL,NULL,NULL);#ifdef WIN32 unixsockets = parse_address(address,name,&port,NULL); if ( unixsockets ) { warn("Unix sockets not supported on Windows"); return INVALID_SOCKET; }#else unixsockets = parse_address(address,name,&port,unaddr.sun_path);#endif /* WIN32 */ if ( !unixsockets ) { hent = gethostbyname(name); if ( ! hent ) { perror("connect_to_host: gethostbyname failed"); return INVALID_SOCKET; } prstruc = getprotobyname("tcp"); if ( prstruc == NULL ) { perror("connect_to_host: getprotobyname failed"); return INVALID_SOCKET; } } fd = socket(unixsockets ? AF_UNIX : AF_INET, SOCK_STREAM, unixsockets ? 0 : prstruc->p_proto); if ( fd == INVALID_SOCKET ) { perror("connect_to_host: socket failed"); return INVALID_SOCKET; }#ifndef WIN32 if ( unixsockets ) { unaddr.sun_family = AF_UNIX; if ( connect(fd,(struct sockaddr *)&unaddr,sizeof(struct sockaddr_un)) < 0 ) { perror("connect_to_host: connect failed"); return INVALID_SOCKET; } } else {#else if ( 1 ) {#endif /* WIN32 */ inaddr.sin_family = AF_INET; inaddr.sin_port = htons(port); inaddr.sin_addr = *((struct in_addr *)hent->h_addr); if ( connect(fd,(struct sockaddr *)&inaddr,sizeof(struct sockaddr_in)) < 0 ) { perror("connect_to_host: connect failed"); return INVALID_SOCKET; } } #ifndef WIN32 /* mark close on exec */ fcntl(fd,F_SETFD,1);#endif /* WIN32 */ if ( skt_open_transform ) { return (SOCKET) skt_open_transform(fd); } else { return fd; }}/* close a network connection */int close_socket(SOCKET s) { if ( skt_closer ) { return skt_closer((void *)s);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -