00001 /*************************************************************************** 00002 *cr 00003 *cr (C) Copyright 1995-2019 The Board of Trustees of the 00004 *cr University of Illinois 00005 *cr All Rights Reserved 00006 *cr 00007 ***************************************************************************/ 00008 00009 /*************************************************************************** 00010 * RCS INFORMATION: 00011 * 00012 * $RCSfile: imd.C,v $ 00013 * $Author: johns $ $Locker: $ $State: Exp $ 00014 * $Revision: 1.20 $ $Date: 2019年01月17日 21:21:03 $ 00015 * 00016 *************************************************************************** 00017 * DESCRIPTION: 00018 * Lowest level interactive MD communication routines. 00019 * 00020 * LICENSE: 00021 * UIUC Open Source License 00022 * http://www.ks.uiuc.edu/Research/vmd/plugins/pluginlicense.html 00023 * 00024 ***************************************************************************/ 00025 #include "imd.h" 00026 #include "vmdsock.h" 00027 #include <string.h> 00028 #include <errno.h> 00029 #include <stdlib.h> 00030 00032 typedef struct { 00033 int32 type; 00034 int32 length; 00035 } IMDheader; 00036 00037 #define HEADERSIZE 8 00038 #define IMDVERSION 2 00039 00040 /* Only works with aligned 4-byte quantities, will cause a bus error */ 00041 /* on some platforms if used on unaligned data. */ 00042 void swap4_aligned(void *v, long ndata) { 00043 int *data = (int *) v; 00044 long i; 00045 int *N; 00046 for (i=0; i<ndata; i++) { 00047 N = data + i; 00048 *N=(((*N>>24)&0xff) | ((*N&0xff)<<24) | 00049 ((*N>>8)&0xff00) | ((*N&0xff00)<<8)); 00050 } 00051 } 00052 00053 static int32 imd_htonl(int32 h) { 00054 int32 n; 00055 ((char *)&n)[0] = (h >> 24) & 0x0FF; 00056 ((char *)&n)[1] = (h >> 16) & 0x0FF; 00057 ((char *)&n)[2] = (h >> 8) & 0x0FF; 00058 ((char *)&n)[3] = h & 0x0FF; 00059 return n; 00060 } 00061 00063 typedef struct { 00064 unsigned int highest : 8; 00065 unsigned int high : 8; 00066 unsigned int low : 8; 00067 unsigned int lowest : 8; 00068 } netint; 00069 00070 static int32 imd_ntohl(int32 n) { 00071 int32 h = 0; 00072 netint net; 00073 00074 memcpy((void *)&net,(void *)&n, sizeof(n)); 00075 h |= net.highest << 24 | net.high << 16 | net.low << 8 | net.lowest; 00076 return h; 00077 } 00078 00079 static void fill_header(IMDheader *header, IMDType type, int32 length) { 00080 header->type = imd_htonl((int32)type); 00081 header->length = imd_htonl(length); 00082 } 00083 00084 static void swap_header(IMDheader *header) { 00085 header->type = imd_ntohl(header->type); 00086 header->length= imd_ntohl(header->length); 00087 } 00088 00089 static int32 imd_readn(void *s, char *ptr, int32 n) { 00090 int32 nleft; 00091 int32 nread; 00092 00093 nleft = n; 00094 while (nleft > 0) { 00095 if ((nread = vmdsock_read(s, ptr, nleft)) < 0) { 00096 if (errno == EINTR) 00097 nread = 0; /* and call read() again */ 00098 else 00099 return -1; 00100 } else if (nread == 0) 00101 break; /* EOF */ 00102 nleft -= nread; 00103 ptr += nread; 00104 } 00105 return n-nleft; 00106 } 00107 00108 static int32 imd_writen(void *s, const char *ptr, int32 n) { 00109 int32 nleft; 00110 int32 nwritten; 00111 00112 nleft = n; 00113 while (nleft > 0) { 00114 if ((nwritten = vmdsock_write(s, ptr, nleft)) <= 0) { 00115 if (errno == EINTR) 00116 nwritten = 0; 00117 else 00118 return -1; 00119 } 00120 nleft -= nwritten; 00121 ptr += nwritten; 00122 } 00123 return n; 00124 } 00125 00126 00127 int imd_disconnect(void *s) { 00128 IMDheader header; 00129 fill_header(&header, IMD_DISCONNECT, 0); 00130 return (imd_writen(s, (char *)&header, HEADERSIZE) != HEADERSIZE); 00131 } 00132 00133 int imd_pause(void *s) { 00134 IMDheader header; 00135 fill_header(&header, IMD_PAUSE, 0); 00136 return (imd_writen(s, (char *)&header, HEADERSIZE) != HEADERSIZE); 00137 } 00138 00139 int imd_kill(void *s) { 00140 IMDheader header; 00141 fill_header(&header, IMD_KILL, 0); 00142 return (imd_writen(s, (char *)&header, HEADERSIZE) != HEADERSIZE); 00143 } 00144 00145 static int imd_go(void *s) { 00146 IMDheader header; 00147 fill_header(&header, IMD_GO, 0); 00148 return (imd_writen(s, (char *)&header, HEADERSIZE) != HEADERSIZE); 00149 } 00150 00151 00152 int imd_handshake(void *s) { 00153 IMDheader header; 00154 fill_header(&header, IMD_HANDSHAKE, 1); 00155 header.length = IMDVERSION; /* Not byteswapped! */ 00156 return (imd_writen(s, (char *)&header, HEADERSIZE) != HEADERSIZE); 00157 } 00158 00159 int imd_trate(void *s, int32 rate) { 00160 IMDheader header; 00161 fill_header(&header, IMD_TRATE, rate); 00162 return (imd_writen(s, (char *)&header, HEADERSIZE) != HEADERSIZE); 00163 } 00164 00165 /* Data methods */ 00166 int imd_send_mdcomm(void *s,int32 n,const int32 *indices,const float *forces) { 00167 int rc; 00168 int32 size = HEADERSIZE+16L*n; 00169 char *buf = (char *) malloc(sizeof(char) * size); 00170 fill_header((IMDheader *)buf, IMD_MDCOMM, n); 00171 memcpy(buf+HEADERSIZE, indices, 4L*n); 00172 memcpy(buf+HEADERSIZE+4*n, forces, 12L*n); 00173 rc = (imd_writen(s, buf, size) != size); 00174 free(buf); 00175 return rc; 00176 } 00177 00178 int imd_send_energies(void *s, const IMDEnergies *energies) { 00179 int rc; 00180 int32 size = HEADERSIZE+sizeof(IMDEnergies); 00181 char *buf = (char *) malloc(sizeof(char) * size); 00182 fill_header((IMDheader *)buf, IMD_ENERGIES, 1); 00183 memcpy(buf+HEADERSIZE, energies, sizeof(IMDEnergies)); 00184 rc = (imd_writen(s, buf, size) != size); 00185 free(buf); 00186 return rc; 00187 } 00188 00189 int imd_send_fcoords(void *s, int32 n, const float *coords) { 00190 int rc; 00191 int32 size = HEADERSIZE+12L*n; 00192 char *buf = (char *) malloc(sizeof(char) * size); 00193 fill_header((IMDheader *)buf, IMD_FCOORDS, n); 00194 memcpy(buf+HEADERSIZE, coords, 12L*n); 00195 rc = (imd_writen(s, buf, size) != size); 00196 free(buf); 00197 return rc; 00198 } 00199 00200 /* The IMD receive functions */ 00201 IMDType imd_recv_header_nolengthswap(void *s, int32 *length) { 00202 IMDheader header; 00203 if (imd_readn(s, (char *)&header, HEADERSIZE) != HEADERSIZE) 00204 return IMD_IOERROR; 00205 *length = header.length; 00206 swap_header(&header); 00207 return (IMDType) header.type; 00208 } 00209 00210 IMDType imd_recv_header(void *s, int32 *length) { 00211 IMDheader header; 00212 if (imd_readn(s, (char *)&header, HEADERSIZE) != HEADERSIZE) 00213 return IMD_IOERROR; 00214 swap_header(&header); 00215 *length = header.length; 00216 return (IMDType) header.type; 00217 } 00218 00219 int imd_recv_handshake(void *s) { 00220 int32 buf; 00221 IMDType type; 00222 00223 /* Wait up to 5 seconds for the handshake to come */ 00224 if (vmdsock_selread(s, 5) != 1) return -1; 00225 00226 /* Check to see that a valid handshake was received */ 00227 type = imd_recv_header_nolengthswap(s, &buf); 00228 if (type != IMD_HANDSHAKE) return -1; 00229 00230 /* Check its endianness, as well as the IMD version. */ 00231 if (buf == IMDVERSION) { 00232 if (!imd_go(s)) return 0; 00233 return -1; 00234 } 00235 00236 swap4_aligned(&buf, 1); 00237 if (buf == IMDVERSION) { 00238 if (!imd_go(s)) return 1; 00239 } 00240 00241 /* We failed to determine endianness. */ 00242 return -1; 00243 } 00244 00245 int imd_recv_mdcomm(void *s, int32 n, int32 *indices, float *forces) { 00246 if (imd_readn(s, (char *)indices, 4L*n) != 4L*n) return 1; 00247 if (imd_readn(s, (char *)forces, 12L*n) != 12L*n) return 1; 00248 return 0; 00249 } 00250 00251 int imd_recv_energies(void *s, IMDEnergies *energies) { 00252 return (imd_readn(s, (char *)energies, sizeof(IMDEnergies)) 00253 != sizeof(IMDEnergies)); 00254 } 00255 00256 int imd_recv_fcoords(void *s, int32 n, float *coords) { 00257 return (imd_readn(s, (char *)coords, 12L*n) != 12L*n); 00258 } 00259