# include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # define DATA_BUF_MAX 1000 # define DEBUG 0 int main ( int argc, char *argv[] ); void byte2int ( unsigned char *bvec, unsigned int *ival ); void int2byte ( unsigned int ival, unsigned char *bvec ); int socket_local ( int *local_socket ); int socket_recv ( int local_socket, char *data_buf, int data_buf_max, struct sockaddr_in remote_addr, unsigned int *sequence, int *num_data_recv ); int socket_remote ( char *remote_host_name, struct sockaddr_in *remote_addr ); void socket_terminate ( int local_socket ); /******************************************************************************/ int main ( int argc, char *argv[] ) /******************************************************************************/ /* Purpose: MAIN is the main program for IRIS_TO_PC. Discussion: This program runs on an SGI. The program: * opens a socket on port 53001 that uses the UDP protocol; * sets up address information for a remote socket on host "garlic.psc.edu" and port 53000; * receives messages from the remote socket; * closes the local socket. Licensing: This code is distributed under the GNU LGPL license. Modified: 12 November 1998 Author: John Burkardt Usage: iris_to_pc */ { char data_buf[DATA_BUF_MAX]; int error_flag; int i; char local_host_name[81]; int local_host_name_len; int local_socket; int num_data_recv; struct sockaddr_in remote_addr; char remote_host_name[81]; int result; unsigned int sequence; error_flag = 0; /* Report the local host name. */ local_host_name_len = 81; result = gethostname ( local_host_name, local_host_name_len ); printf ( "\n" ); printf ( "IRIS_TO_PC:\n" ); printf ( " Local host is %s.\n", local_host_name ); /* Set up the local socket. */ result = socket_local ( &local_socket ); if ( result != 0 ) { printf ( "\n" ); printf ( "IRIS_TO_PC: ERROR!\n" ); printf ( " Could not open the local socket.\n" ); return 1; } /* Set up the remote socket. */ strcpy ( remote_host_name, "garlic.psc.edu" ); result = socket_remote ( remote_host_name, &remote_addr ); if ( result != 0 ) { printf ( "\n" ); printf ( "IRIS_TO_PC: ERROR!\n" ); printf ( " Could not set up the remote socket.\n" ); return 1; } /* Communication loop. */ while ( 1 ) { result = socket_recv ( local_socket, data_buf, DATA_BUF_MAX, remote_addr, &sequence, &num_data_recv ); if ( result == -2 ) { printf ( "\n" ); printf ( "IRIS_TO_PC: WARNING:\n" ); printf ( " Message received out of sequence.\n" ); } if ( result == -1 ) { printf ( "\n" ); printf ( "IRIS_TO_PC:\n" ); printf ( " Sequence = %d.\n", sequence ); printf ( " Shutdown signal received.\n" ); break; } if ( result == 5 ) { printf ( "\n" ); printf ( "IRIS_TO_PC: FATAL ERROR:\n" ); printf ( " socket_recv error code = %d.\n", result ); printf ( " Transmitted data would overflow internal buffer.\n" ); error_flag = 1; break; } if ( result > 0 ) { printf ( "\n" ); printf ( "IRIS_TO_PC: ERROR:\n" ); printf ( " socket_recv error code = %d.\n", result ); continue; } printf ( "\n" ); printf ( "IRIS_TO_PC:\n" ); printf ( " Sequence = %d.\n", sequence ); printf ( " Number of bytes received = %d.\n", num_data_recv ); printf ( " Message data:\n" ); printf ( "\n" ); printf ( " " ); for ( i = 0; i < num_data_recv; i++ ) { printf ( "%c", data_buf[i] ); } printf ( "\n" ); } /* Close the socket. */ socket_terminate ( local_socket ); return error_flag; } /******************************************************************************/ void byte2int ( unsigned char *bvec, unsigned int *ival ) /******************************************************************************/ /* Purpose: BYTE2INT converts 4 bytes into an unsigned integer. Licensing: This code is distributed under the GNU LGPL license. Modified: 09 November 1998 Author: John Burkardt Parameters: Input, unsigned char *BVEC, is a pointer to a character string. The contents of BVEC through BVEC+3 are the bytes of IVAL, from high order to low. Output, unsigned int IVAL, the integer represented by the bytes. */ { int i; *ival = 0; for ( i = 0; i < 4; i++ ) { *ival = *ival << 8; *ival = *ival + *bvec; bvec = bvec + 1; } return; } /******************************************************************************/ void int2byte ( unsigned int ival, unsigned char *bvec ) /******************************************************************************/ /* Purpose: INT2BYTE converts an unsigned integer into 4 bytes. Licensing: This code is distributed under the GNU LGPL license. Modified: 09 November 1998 Author: John Burkardt Parameters: Input, unsigned int IVAL, is the integer to be converted. Output, unsigned char *BVEC, is a pointer to a character string. The contents of BVEC through BVEC+3 will be the bytes of IVAL, from low order to high. */ { int i; for ( i = 0; i < 4; i++ ) { *bvec = ( ival >> (3-i)*8 ); bvec = bvec + 1; } return; } /******************************************************************************/ int socket_local ( int *local_socket ) /******************************************************************************/ /* Purpose: SOCKET_LOCAL creates a local socket. Licensing: This code is distributed under the GNU LGPL license. Modified: 12 November 1998 Author: John Burkardt Parameters: Output, int *local_socket, the descriptor of the local socket. */ { int domain; struct sockaddr_in local_addr; int local_addr_len; unsigned short int local_port; int protocol; int result; int type; /* Create a socket. DOMAIN is AF_INET, we will be using Internet addresses with this socket; TYPE is SOCK_DGRAM, the type of socket we will use; PROTOCOL is IPPROTO_UDP, the protocol to use with the socket. SD is the socket descriptor. */ domain = AF_INET; type = SOCK_DGRAM; protocol = IPPROTO_UDP; *local_socket = socket ( domain, type, protocol ); if ( *local_socket == 0 ) { printf ( "\n" ); perror ( "SOCKET_LOCAL: call to socket" ); return 1; } printf ( "\n" ); printf ( "SOCKET_LOCAL:\n" ); printf ( " Socket creation successful.\n" ); /* Bind the socket to a specific port number. */ local_port = 53001; local_addr_len = sizeof ( local_addr ); memset ( &local_addr, 0, local_addr_len ); local_addr.sin_family = AF_INET; local_addr.sin_port = htons ( local_port ); local_addr.sin_addr.s_addr = htonl ( INADDR_ANY ); result = bind ( *local_socket, &local_addr, local_addr_len ); if ( result != 0 ) { printf ( "\n" ); perror ( "SOCKET_LOCAL: call to bind" ); return 1; } printf ( "\n" ); printf ( "SOCKET_LOCAL:\n" ); printf ( " Local socket bound to port number %d.\n", local_port ); return 0; } /******************************************************************************/ int socket_recv ( int local_socket, char *data_buf, int data_buf_max, struct sockaddr_in remote_addr, unsigned int *sequence, int *num_data_recv ) /******************************************************************************/ /* Purpose: SOCKET_RECV returns the data received from the socket. Licensing: This code is distributed under the GNU LGPL license. Modified: 12 November 1998 Author: John Burkardt Parameters: Input, int local_socket, the descriptor of the local socket. Output, char *data_buf, an array of bytes received from the remote socket. Input, int data_buf_max, the maximum number of bytes that can be stored in data_buf. Input, struct sockaddr_in remote_addr, the pointer to a socket address structure. Output, int *sequence, the sequence number of the message received. The first message should have sequence number 1, and the sequence numbers should rise by 1 each time a new message is received. Otherwise, a message has been lost, or messages have been received out of order. Output, int *num_data_recv, the number of bytes received. Output, int socket_recv: -2, message received out of order (sequence number discrepancy), but otherwise OK; -1, the remote socket is signaling shutdown; 0, no error, header and data received; 1, receive error while receiving header information; 2, only partial header received; 3, receive error while receiving data; 4, only partial data received; 5, amount of data sent overflows data_buf_max; no data was read. */ { unsigned char header_buf[8]; int header_buf_max; int i; unsigned int num_data_sent; int num_header_recv; int recv_flags; int remote_addr_len; int sequence_flag; static int sequence_previous = 0; header_buf_max = 8; recv_flags = 0; remote_addr_len = sizeof ( remote_addr ); *num_data_recv = 0; /* Receive the header. */ num_header_recv = recvfrom ( local_socket, header_buf, header_buf_max, recv_flags, &remote_addr, &remote_addr_len ); if ( num_header_recv < 0 ) { printf ( "\n" ); printf ( "SOCKET_RECV: ERROR:\n" ); printf ( " num_header_recv < 0.\n" ); printf ( " num_header_recv = %d.\n", num_header_recv ); return 1; } if ( num_header_recv != 8 ) { printf ( "\n" ); printf ( "SOCKET_RECV: ERROR:\n" ); printf ( " num_header_recv != 8.\n" ); printf ( " num_header_recv = %d.\n", num_header_recv ); return 2; } if ( DEBUG ) { for ( i = 0; i < 8; i++ ) { printf ( "%d %d\n", i, header_buf[i] ); } } byte2int ( header_buf, sequence ); byte2int ( header_buf+4, &num_data_sent ); if ( *sequence == sequence_previous + 1 ) { sequence_flag = 0; } else { printf ( "\n" ); printf ( "SOCKET_RECV: WARNING:\n" ); printf ( " Messages out of sequence.\n" ); printf ( " Previous message sequence = %d.\n", sequence_previous ); printf ( " Current message sequence = %d.\n", *sequence ); sequence_flag = -2; } sequence_previous = *sequence; if ( num_data_sent == 0 ) { return (-1); } if ( num_data_sent > data_buf_max ) { printf ( "\n" ); printf ( "SOCKET_RECV: ERROR:\n" ); printf ( " Too much data.\n" ); printf ( " data_buf_max = %d.\n", data_buf_max ); printf ( " num_data_sent = %d.\n", num_data_sent ); return 5; } /* Receive the data. */ *num_data_recv = recvfrom ( local_socket, data_buf, data_buf_max, recv_flags, &remote_addr, &remote_addr_len ); if ( *num_data_recv < 0 ) { printf ( "\n" ); printf ( "SOCKET_RECV: ERROR:\n" ); printf ( " num_data_recv < 0.\n" ); printf ( " num_data_recv = %d.\n", *num_data_recv ); return 3; } if ( *num_data_recv != num_data_sent ) { printf ( "\n" ); printf ( "SOCKET_RECV: ERROR:\n" ); printf ( " num_data_recv != num_data_sent.\n" ); printf ( " num_data_recv = %d.\n", *num_data_recv ); printf ( " num_data_sent = %d.\n", num_data_sent ); return 4; } return sequence_flag; } /******************************************************************************/ int socket_remote ( char *remote_host_name, struct sockaddr_in *remote_addr ) /******************************************************************************/ /* Purpose: SOCKET_REMOTE returns the address of a remote host from its name. Licensing: This code is distributed under the GNU LGPL license. Modified: 12 November 1998 Author: John Burkardt Parameters: Input, char *remote_host_name, the name of the remote host with which we wish to communicate. Output, struct sockaddr_in *remote_addr, the pointer to a socket address structure. */ { int remote_addr_len; char *remote_addr_string; struct hostent *remote_host; unsigned short int remote_port; remote_host = gethostbyname ( remote_host_name ); if ( !remote_host ) { printf ( "\n" ); printf ( "SOCKET_REMOTE: ERROR!\n" ); printf ( " Could not get host information.\n" ); return 1; } printf ( "\n" ); printf ( "SOCKET_REMOTE:\n" ); printf ( " Got host information.\n" ); /* Set up the address information for the remote machine. The REMOTE_PORT value here is arbitrary, but has to match the value defined in the receiving program. */ remote_port = 53000; remote_addr_len = sizeof ( *remote_addr ); memset ( remote_addr, 0, remote_addr_len ); remote_addr->sin_family = AF_INET; remote_addr->sin_port = htons ( remote_port ); remote_addr->sin_addr = * ( struct in_addr * ) ( remote_host->h_addr_list[0] ); remote_addr_string = inet_ntoa ( remote_addr->sin_addr ); printf ( "\n" ); printf ( "SOCKET_REMOTE:\n" ); printf ( " Remote Internet address is %s.\n", remote_addr_string ); return 0; } /******************************************************************************/ void socket_terminate ( int local_socket ) /******************************************************************************/ /* Purpose: SOCKET_TERMINATE closes the local socket. Licensing: This code is distributed under the GNU LGPL license. Modified: 12 November 1998 Author: John Burkardt Parameters: Input, int local_socket, the descriptor of the local socket that is to be closed. */ { close ( local_socket ); printf ( "\n" ); printf ( "SOCKET_TERMINATE:\n" ); printf ( " Closing the local socket.\n" ); return; }