/////////////////////////////////////////////////////////////////////////////// /* A minimal wrapper for socket communication. Copyright (C) 2013, Joshua More and Michele Ceriotti Copyright (C) 2016, B lint Aradi (adapted to F2003 C-bindings) Functions: error: Prints an error message and then exits. open_socket_: Opens a socket with the required host server, socket type and port number. write_buffer_: Writes a string to the socket. read_buffer_: Reads data from the socket. - 02.02.2017: Sergey Kostrov's ( SK ) notes: - https://software.intel.com/en-us/forums/intel-c-compiler/topic/710141 - For compilation with Intel C++ compiler for Windows without linking use icl.exe -c */ /////////////////////////////////////////////////////////////////////////////// #include #include #include #include #include /////////////////////////////////////////////////////////////////////////////// // SK #ifdef _WIN32 #include #include #else #include #include #include #include #endif /////////////////////////////////////////////////////////////////////////////// // SK void connect_inet_socket( int *psockfd, const char* host, int port ); #ifdef _WIN32 void connect_windows_socket( int *psockfd, const char* pathname ); #else void connect_unix_socket( int *psockfd, const char* pathname ); #endif void writebuffer_socket( int sockfd, const void *data, int len ); void readbuffer_socket( int sockfd, void *data, int len ); void shutdown_socket( int sockfd ); /////////////////////////////////////////////////////////////////////////////// // SK /* Access to sockets needs to be done with a wrapper function 'connect_socket' and it is substituted by 'connect_windows_socket' or by 'connect_unix_socket' ( depends on a state of the macro _WIN32 ) during preprocessing phase of the compilation. For portability 'connect_windows_socket' and 'connect_unix_socket' shouldn't be used directly and the wrapper function 'connect_socket' must be used instead. */ #ifdef _WIN32 #define connect_socket connect_windows_socket #else #define connect_socket connect_unix_socket #endif /////////////////////////////////////////////////////////////////////////////// /* Opens an internet socket. Note that fortran passes an extra argument for the string length, but this is ignored here for C compatibility. Args: psockfd: The id of the socket that will be created. port: The port number for the socket to be created. Low numbers are often reserved for important channels, so use of numbers of 4 or more digits is recommended. host: The name of the host server. */ void connect_inet_socket( int *psockfd, const char* host, int port ) { int sockfd, ai_err; // creates an internet socket // fetches information on the host struct addrinfo hints, *res; char service[256]; memset(&hints, 0, sizeof(hints)); hints.ai_socktype = SOCK_STREAM; hints.ai_family = AF_UNSPEC; hints.ai_flags = AI_PASSIVE; sprintf(service, "%d", port); // convert the port number to a string ai_err = getaddrinfo(host, service, &hints, &res); if (ai_err!=0) { printf("Error code: %i\n",ai_err); perror("Error fetching host data. Wrong host name?"); exit(-1); } // creates socket sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol); if (sockfd < 0) { perror("Error opening socket"); exit(-1); } // makes connection if (connect(sockfd, res->ai_addr, res->ai_addrlen) < 0) { perror("Error opening INET socket: wrong port or server unreachable"); exit(-1); } freeaddrinfo(res); *psockfd = sockfd; } /////////////////////////////////////////////////////////////////////////////// // SK /* Opens a socket. Note that fortran passes an extra argument for the string length, but this is ignored here for C compatibility. Args: psockfd: The id of the socket that will be created. pathname: The name of the file to use for sun_path. */ #ifdef _WIN32 void connect_windows_socket( int *psockfd, const char* pathname ) { // Required functionality for Windows // ... } #else void connect_unix_socket( int *psockfd, const char* pathname ) { // Required functionality for Unix int sockfd, ai_err; struct sockaddr_in serv_addr; printf("Connecting to :%s:\n",pathname); // fills up details of the socket addres memset(&serv_addr, 0, sizeof(serv_addr)); serv_addr.sun_family = AF_UNIX; /* Beware of buffer over runs UNIX Network Programming by Richard Stevens mentions that the use of sizeof() is ok, but see http://mail-index.netbsd.org/tech-net/2006/10/11/0008.html */ if ((int)strlen(pathname)> sizeof(serv_addr.sun_path)) { perror("Error opening UNIX socket: pathname too long\n"); exit(-1); } else { strcpy(serv_addr.sun_path, pathname); } // creates a unix socket // creates the socket sockfd = socket(AF_UNIX, SOCK_STREAM, 0); // connects if (connect(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) { perror("Error opening UNIX socket: path unavailable, or already existing"); exit(-1); } *psockfd = sockfd; } #endif /////////////////////////////////////////////////////////////////////////////// /* Writes to a socket. Args: sockfd: The id of the socket that will be written to. data: The data to be written to the socket. len: The length of the data in bytes. */ void writebuffer_socket( int sockfd, const void *data, int len ) { int n; n = write(sockfd, (char *) data, len); if (n < 0) { perror("Error writing to socket: server has quit or connection broke"); exit(-1); } } /////////////////////////////////////////////////////////////////////////////// /* Reads from a socket. Args: sockfd: The id of the socket that will be read from. data: The storage array for data read from the socket. len: The length of the data in bytes. */ void readbuffer_socket( int sockfd, void *data, int len ) { int n, nr; char *pdata; pdata = (char *) data; n = nr = read(sockfd, pdata, len); while (nr > 0 && n < len) { nr = read(sockfd, &(pdata[n]), len - n); n += nr; } if (n == 0) { perror("Error reading from socket: server has quit or connection broke"); exit(-1); } } /////////////////////////////////////////////////////////////////////////////// /* Shuts down the socket. */ void shutdown_socket( int sockfd ) { shutdown( sockfd, 2 ); close( sockfd ); }