1 2 #include <petscsys.h> 3 4 #if defined(PETSC_NEEDS_UTYPE_TYPEDEFS) 5 /* Some systems have inconsistent include files that use but do not 6 ensure that the following definitions are made */ 7 typedef unsigned char u_char; 8 typedef unsigned short u_short; 9 typedef unsigned short ushort; 10 typedef unsigned int u_int; 11 typedef unsigned long u_long; 12 #endif 13 14 #include <errno.h> 15 #include <ctype.h> 16 #if defined(PETSC_HAVE_MACHINE_ENDIAN_H) 17 #include <machine/endian.h> 18 #endif 19 #if defined(PETSC_HAVE_UNISTD_H) 20 #include <unistd.h> 21 #endif 22 #if defined(PETSC_HAVE_SYS_SOCKET_H) 23 #include <sys/socket.h> 24 #endif 25 #if defined(PETSC_HAVE_SYS_WAIT_H) 26 #include <sys/wait.h> 27 #endif 28 #if defined(PETSC_HAVE_NETINET_IN_H) 29 #include <netinet/in.h> 30 #endif 31 #if defined(PETSC_HAVE_NETDB_H) 32 #include <netdb.h> 33 #endif 34 #if defined(PETSC_HAVE_FCNTL_H) 35 #include <fcntl.h> 36 #endif 37 #if defined(PETSC_HAVE_IO_H) 38 #include <io.h> 39 #endif 40 #if defined(PETSC_HAVE_WINSOCK2_H) 41 #include <Winsock2.h> 42 #endif 43 #include <sys/stat.h> 44 #include <../src/sys/classes/viewer/impls/socket/socket.h> 45 46 #if defined(PETSC_NEED_CLOSE_PROTO) 47 PETSC_EXTERN int close(int); 48 #endif 49 #if defined(PETSC_NEED_SOCKET_PROTO) 50 PETSC_EXTERN int socket(int,int,int); 51 #endif 52 #if defined(PETSC_NEED_SLEEP_PROTO) 53 PETSC_EXTERN int sleep(unsigned); 54 #endif 55 #if defined(PETSC_NEED_CONNECT_PROTO) 56 PETSC_EXTERN int connect(int,struct sockaddr*,int); 57 #endif 58 59 /*--------------------------------------------------------------*/ 60 #undef __FUNCT__ 61 #define __FUNCT__ "PetscViewerDestroy_Socket" 62 static PetscErrorCode PetscViewerDestroy_Socket(PetscViewer viewer) 63 { 64 PetscViewer_Socket *vmatlab = (PetscViewer_Socket*)viewer->data; 65 PetscErrorCode ierr; 66 67 PetscFunctionBegin; 68 if (vmatlab->port) { 69 #if defined(PETSC_HAVE_CLOSESOCKET) 70 ierr = closesocket(vmatlab->port); 71 #else 72 ierr = close(vmatlab->port); 73 #endif 74 if (ierr) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"System error closing socket"); 75 } 76 ierr = PetscFree(vmatlab);CHKERRQ(ierr); 77 PetscFunctionReturn(0); 78 } 79 80 /*--------------------------------------------------------------*/ 81 #undef __FUNCT__ 82 #define __FUNCT__ "PetscOpenSocket" 83 /* 84 PetscSocketOpen - handles connected to an open port where someone is waiting. 85 86 .seealso: PetscSocketListen(), PetscSocketEstablish() 87 */ 88 PetscErrorCode PetscOpenSocket(const char hostname[],int portnum,int *t) 89 { 90 struct sockaddr_in sa; 91 struct hostent *hp; 92 int s = 0; 93 PetscErrorCode ierr; 94 PetscBool flg = PETSC_TRUE; 95 static int refcnt = 0; 96 97 PetscFunctionBegin; 98 if (!(hp=gethostbyname(hostname))) { 99 perror("SEND: error gethostbyname: "); 100 SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SYS,"system error open connection to %s",hostname); 101 } 102 ierr = PetscMemzero(&sa,sizeof(sa));CHKERRQ(ierr); 103 ierr = PetscMemcpy(&sa.sin_addr,hp->h_addr_list[0],hp->h_length);CHKERRQ(ierr); 104 105 sa.sin_family = hp->h_addrtype; 106 sa.sin_port = htons((u_short) portnum); 107 while (flg) { 108 if ((s=socket(hp->h_addrtype,SOCK_STREAM,0)) < 0) { 109 perror("SEND: error socket"); SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"system error"); 110 } 111 if (connect(s,(struct sockaddr*)&sa,sizeof(sa)) < 0) { 112 #if defined(PETSC_HAVE_WSAGETLASTERROR) 113 ierr = WSAGetLastError(); 114 if (ierr == WSAEADDRINUSE) (*PetscErrorPrintf)("SEND: address is in use\n"); 115 else if (ierr == WSAEALREADY) (*PetscErrorPrintf)("SEND: socket is non-blocking \n"); 116 else if (ierr == WSAEISCONN) { 117 (*PetscErrorPrintf)("SEND: socket already connected\n"); 118 Sleep((unsigned) 1); 119 } else if (ierr == WSAECONNREFUSED) { 120 /* (*PetscErrorPrintf)("SEND: forcefully rejected\n"); */ 121 Sleep((unsigned) 1); 122 } else { 123 perror(NULL); SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"system error"); 124 } 125 #else 126 if (errno == EADDRINUSE) (*PetscErrorPrintf)("SEND: address is in use\n"); 127 else if (errno == EALREADY) (*PetscErrorPrintf)("SEND: socket is non-blocking \n"); 128 else if (errno == EISCONN) { 129 (*PetscErrorPrintf)("SEND: socket already connected\n"); 130 sleep((unsigned) 1); 131 } else if (errno == ECONNREFUSED) { 132 refcnt++; 133 if (refcnt > 5) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_SYS,"Connection refused by remote host %s port %d",hostname,portnum); 134 ierr = PetscInfo(0,"Connection refused in attaching socket, trying again\n");CHKERRQ(ierr); 135 sleep((unsigned) 1); 136 } else { 137 perror(NULL); SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"system error"); 138 } 139 #endif 140 flg = PETSC_TRUE; 141 #if defined(PETSC_HAVE_CLOSESOCKET) 142 closesocket(s); 143 #else 144 close(s); 145 #endif 146 } else flg = PETSC_FALSE; 147 } 148 *t = s; 149 PetscFunctionReturn(0); 150 } 151 152 #define MAXHOSTNAME 100 153 #undef __FUNCT__ 154 #define __FUNCT__ "PetscSocketEstablish" 155 /* 156 PetscSocketEstablish - starts a listener on a socket 157 158 .seealso: PetscSocketListen() 159 */ 160 PETSC_INTERN PetscErrorCode PetscSocketEstablish(int portnum,int *ss) 161 { 162 char myname[MAXHOSTNAME+1]; 163 int s; 164 PetscErrorCode ierr; 165 struct sockaddr_in sa; 166 struct hostent *hp; 167 168 PetscFunctionBegin; 169 ierr = PetscGetHostName(myname,MAXHOSTNAME);CHKERRQ(ierr); 170 171 ierr = PetscMemzero(&sa,sizeof(struct sockaddr_in));CHKERRQ(ierr); 172 173 hp = gethostbyname(myname); 174 if (!hp) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"Unable to get hostent information from system"); 175 176 sa.sin_family = hp->h_addrtype; 177 sa.sin_port = htons((u_short)portnum); 178 179 if ((s = socket(AF_INET,SOCK_STREAM,0)) < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"Error running socket() command"); 180 #if defined(PETSC_HAVE_SO_REUSEADDR) 181 { 182 int optval = 1; /* Turn on the option */ 183 ierr = setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char*)&optval,sizeof(optval));CHKERRQ(ierr); 184 } 185 #endif 186 187 while (bind(s,(struct sockaddr*)&sa,sizeof(sa)) < 0) { 188 #if defined(PETSC_HAVE_WSAGETLASTERROR) 189 ierr = WSAGetLastError(); 190 if (ierr != WSAEADDRINUSE) { 191 #else 192 if (errno != EADDRINUSE) { 193 #endif 194 close(s); 195 SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"Error from bind()"); 196 } 197 } 198 listen(s,0); 199 *ss = s; 200 return(0); 201 } 202 203 #undef __FUNCT__ 204 #define __FUNCT__ "PetscSocketListen" 205 /* 206 PetscSocketListens - Listens at a socket created with PetscSocketEstablish() 207 208 .seealso: PetscSocketEstablish() 209 */ 210 PETSC_INTERN PetscErrorCode PetscSocketListen(int listenport,int *t) 211 { 212 struct sockaddr_in isa; 213 #if defined(PETSC_HAVE_ACCEPT_SIZE_T) 214 size_t i; 215 #else 216 int i; 217 #endif 218 219 PetscFunctionBegin; 220 /* wait for someone to try to connect */ 221 i = sizeof(struct sockaddr_in); 222 if ((*t = accept(listenport,(struct sockaddr*)&isa,(socklen_t*)&i)) < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"error from accept()\n"); 223 PetscFunctionReturn(0); 224 } 225 226 #undef __FUNCT__ 227 #define __FUNCT__ "PetscViewerSocketOpen" 228 /*@C 229 PetscViewerSocketOpen - Opens a connection to a MATLAB or other socket based server. 230 231 Collective on MPI_Comm 232 233 Input Parameters: 234 + comm - the MPI communicator 235 . machine - the machine the server is running on,, use NULL for the local machine, use "server" to passively wait for 236 a connection from elsewhere 237 - port - the port to connect to, use PETSC_DEFAULT for the default 238 239 Output Parameter: 240 . lab - a context to use when communicating with the server 241 242 Level: intermediate 243 244 Notes: 245 Most users should employ the following commands to access the 246 MATLAB PetscViewers 247 $ 248 $ PetscViewerSocketOpen(MPI_Comm comm, char *machine,int port,PetscViewer &viewer) 249 $ MatView(Mat matrix,PetscViewer viewer) 250 $ 251 $ or 252 $ 253 $ PetscViewerSocketOpen(MPI_Comm comm,char *machine,int port,PetscViewer &viewer) 254 $ VecView(Vec vector,PetscViewer viewer) 255 256 Options Database Keys: 257 For use with PETSC_VIEWER_SOCKET_WORLD, PETSC_VIEWER_SOCKET_SELF, 258 PETSC_VIEWER_SOCKET_() or if 259 NULL is passed for machine or PETSC_DEFAULT is passed for port 260 $ -viewer_socket_machine <machine> 261 $ -viewer_socket_port <port> 262 263 Environmental variables: 264 + PETSC_VIEWER_SOCKET_PORT portnumber 265 - PETSC_VIEWER_SOCKET_MACHINE machine name 266 267 Currently the only socket client available is MATLAB. See 268 src/dm/examples/tests/ex12.c and ex12.m for an example of usage. 269 270 Notes: The socket viewer is in some sense a subclass of the binary viewer, to read and write to the socket 271 use PetscViewerBinaryRead(), PetscViewerBinaryWrite(), PetscViewerBinarWriteStringArray(), PetscViewerBinaryGetDescriptor(). 272 273 Use this for communicating with an interactive MATLAB session, see PETSC_VIEWER_MATLAB_() for writing output to a 274 .mat file. Use PetscMatlabEngineCreate() or PETSC_MATLAB_ENGINE_(), PETSC_MATLAB_ENGINE_SELF, or PETSC_MATLAB_ENGINE_WORLD 275 for communicating with a MATLAB Engine 276 277 Concepts: MATLAB^sending data 278 Concepts: sockets^sending data 279 280 .seealso: MatView(), VecView(), PetscViewerDestroy(), PetscViewerCreate(), PetscViewerSetType(), 281 PetscViewerSocketSetConnection(), PETSC_VIEWER_SOCKET_, PETSC_VIEWER_SOCKET_WORLD, 282 PETSC_VIEWER_SOCKET_SELF, PetscViewerBinaryWrite(), PetscViewerBinaryRead(), PetscViewerBinaryWriteStringArray(), 283 PetscBinaryViewerGetDescriptor(), PetscMatlabEngineCreate() 284 @*/ 285 PetscErrorCode PetscViewerSocketOpen(MPI_Comm comm,const char machine[],int port,PetscViewer *lab) 286 { 287 PetscErrorCode ierr; 288 289 PetscFunctionBegin; 290 ierr = PetscViewerCreate(comm,lab);CHKERRQ(ierr); 291 ierr = PetscViewerSetType(*lab,PETSCVIEWERSOCKET);CHKERRQ(ierr); 292 ierr = PetscViewerSocketSetConnection(*lab,machine,port);CHKERRQ(ierr); 293 PetscFunctionReturn(0); 294 } 295 296 #undef __FUNCT__ 297 #define __FUNCT__ "PetscViewerSetFromOptions_Socket" 298 static PetscErrorCode PetscViewerSetFromOptions_Socket(PetscOptionItems *PetscOptionsObject,PetscViewer v) 299 { 300 PetscErrorCode ierr; 301 PetscInt def = -1; 302 char sdef[256]; 303 PetscBool tflg; 304 305 PetscFunctionBegin; 306 /* 307 These options are not processed here, they are processed in PetscViewerSocketSetConnection(), they 308 are listed here for the GUI to display 309 */ 310 ierr = PetscOptionsHead(PetscOptionsObject,"Socket PetscViewer Options");CHKERRQ(ierr); 311 ierr = PetscOptionsGetenv(PetscObjectComm((PetscObject)v),"PETSC_VIEWER_SOCKET_PORT",sdef,16,&tflg);CHKERRQ(ierr); 312 if (tflg) { 313 ierr = PetscOptionsStringToInt(sdef,&def);CHKERRQ(ierr); 314 } else def = PETSCSOCKETDEFAULTPORT; 315 ierr = PetscOptionsInt("-viewer_socket_port","Port number to use for socket","PetscViewerSocketSetConnection",def,0,0);CHKERRQ(ierr); 316 317 ierr = PetscOptionsString("-viewer_socket_machine","Machine to use for socket","PetscViewerSocketSetConnection",sdef,0,0,0);CHKERRQ(ierr); 318 ierr = PetscOptionsGetenv(PetscObjectComm((PetscObject)v),"PETSC_VIEWER_SOCKET_MACHINE",sdef,256,&tflg);CHKERRQ(ierr); 319 if (!tflg) { 320 ierr = PetscGetHostName(sdef,256);CHKERRQ(ierr); 321 } 322 ierr = PetscOptionsTail();CHKERRQ(ierr); 323 PetscFunctionReturn(0); 324 } 325 326 #undef __FUNCT__ 327 #define __FUNCT__ "PetscViewerCreate_Socket" 328 PETSC_EXTERN PetscErrorCode PetscViewerCreate_Socket(PetscViewer v) 329 { 330 PetscViewer_Socket *vmatlab; 331 PetscErrorCode ierr; 332 333 PetscFunctionBegin; 334 ierr = PetscNewLog(v,&vmatlab);CHKERRQ(ierr); 335 vmatlab->port = 0; 336 v->data = (void*)vmatlab; 337 v->ops->destroy = PetscViewerDestroy_Socket; 338 v->ops->flush = 0; 339 v->ops->setfromoptions = PetscViewerSetFromOptions_Socket; 340 341 /* lie and say this is a binary viewer; then all the XXXView_Binary() methods will work correctly on it */ 342 ierr = PetscObjectChangeTypeName((PetscObject)v,PETSCVIEWERBINARY);CHKERRQ(ierr); 343 PetscFunctionReturn(0); 344 } 345 346 #undef __FUNCT__ 347 #define __FUNCT__ "PetscViewerSocketSetConnection" 348 /*@C 349 PetscViewerSocketSetConnection - Sets the machine and port that a PETSc socket 350 viewer is to use 351 352 Logically Collective on PetscViewer 353 354 Input Parameters: 355 + v - viewer to connect 356 . machine - host to connect to, use NULL for the local machine,use "server" to passively wait for 357 a connection from elsewhere 358 - port - the port on the machine one is connecting to, use PETSC_DEFAULT for default 359 360 Level: advanced 361 362 .seealso: PetscViewerSocketOpen() 363 @*/ 364 PetscErrorCode PetscViewerSocketSetConnection(PetscViewer v,const char machine[],int port) 365 { 366 PetscErrorCode ierr; 367 PetscMPIInt rank; 368 char mach[256]; 369 PetscBool tflg; 370 PetscViewer_Socket *vmatlab = (PetscViewer_Socket*)v->data; 371 372 PetscFunctionBegin; 373 /* PetscValidLogicalCollectiveInt(v,port,3); not a PetscInt */ 374 if (port <= 0) { 375 char portn[16]; 376 ierr = PetscOptionsGetenv(PetscObjectComm((PetscObject)v),"PETSC_VIEWER_SOCKET_PORT",portn,16,&tflg);CHKERRQ(ierr); 377 if (tflg) { 378 PetscInt pport; 379 ierr = PetscOptionsStringToInt(portn,&pport);CHKERRQ(ierr); 380 port = (int)pport; 381 } else port = PETSCSOCKETDEFAULTPORT; 382 } 383 if (!machine) { 384 ierr = PetscOptionsGetenv(PetscObjectComm((PetscObject)v),"PETSC_VIEWER_SOCKET_MACHINE",mach,256,&tflg);CHKERRQ(ierr); 385 if (!tflg) { 386 ierr = PetscGetHostName(mach,256);CHKERRQ(ierr); 387 } 388 } else { 389 ierr = PetscStrncpy(mach,machine,256);CHKERRQ(ierr); 390 } 391 392 ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)v),&rank);CHKERRQ(ierr); 393 if (!rank) { 394 ierr = PetscStrcmp(mach,"server",&tflg);CHKERRQ(ierr); 395 if (tflg) { 396 int listenport; 397 ierr = PetscInfo1(v,"Waiting for connection from socket process on port %D\n",port);CHKERRQ(ierr); 398 ierr = PetscSocketEstablish(port,&listenport);CHKERRQ(ierr); 399 ierr = PetscSocketListen(listenport,&vmatlab->port);CHKERRQ(ierr); 400 close(listenport); 401 } else { 402 ierr = PetscInfo2(v,"Connecting to socket process on port %D machine %s\n",port,mach);CHKERRQ(ierr); 403 ierr = PetscOpenSocket(mach,port,&vmatlab->port);CHKERRQ(ierr); 404 } 405 } 406 PetscFunctionReturn(0); 407 } 408 409 /* ---------------------------------------------------------------------*/ 410 /* 411 The variable Petsc_Viewer_Socket_keyval is used to indicate an MPI attribute that 412 is attached to a communicator, in this case the attribute is a PetscViewer. 413 */ 414 static PetscMPIInt Petsc_Viewer_Socket_keyval = MPI_KEYVAL_INVALID; 415 416 417 #undef __FUNCT__ 418 #define __FUNCT__ "PETSC_VIEWER_SOCKET_" 419 /*@C 420 PETSC_VIEWER_SOCKET_ - Creates a socket viewer shared by all processors in a communicator. 421 422 Collective on MPI_Comm 423 424 Input Parameter: 425 . comm - the MPI communicator to share the socket PetscViewer 426 427 Level: intermediate 428 429 Options Database Keys: 430 For use with the default PETSC_VIEWER_SOCKET_WORLD or if 431 NULL is passed for machine or PETSC_DEFAULT is passed for port 432 $ -viewer_socket_machine <machine> 433 $ -viewer_socket_port <port> 434 435 Environmental variables: 436 + PETSC_VIEWER_SOCKET_PORT portnumber 437 - PETSC_VIEWER_SOCKET_MACHINE machine name 438 439 Notes: 440 Unlike almost all other PETSc routines, PetscViewer_SOCKET_ does not return 441 an error code. The socket PetscViewer is usually used in the form 442 $ XXXView(XXX object,PETSC_VIEWER_SOCKET_(comm)); 443 444 Currently the only socket client available is MATLAB. See 445 src/dm/examples/tests/ex12.c and ex12.m for an example of usage. 446 447 Connects to a waiting socket and stays connected until PetscViewerDestroy() is called. 448 449 Use this for communicating with an interactive MATLAB session, see PETSC_VIEWER_MATLAB_() for writing output to a 450 .mat file. Use PetscMatlabEngineCreate() or PETSC_MATLAB_ENGINE_(), PETSC_MATLAB_ENGINE_SELF, or PETSC_MATLAB_ENGINE_WORLD 451 for communicating with a MATLAB Engine 452 453 .seealso: PETSC_VIEWER_SOCKET_WORLD, PETSC_VIEWER_SOCKET_SELF, PetscViewerSocketOpen(), PetscViewerCreate(), 454 PetscViewerSocketSetConnection(), PetscViewerDestroy(), PETSC_VIEWER_SOCKET_(), PetscViewerBinaryWrite(), PetscViewerBinaryRead(), 455 PetscViewerBinaryWriteStringArray(), PetscViewerBinaryGetDescriptor(), PETSC_VIEWER_MATLAB_() 456 @*/ 457 PetscViewer PETSC_VIEWER_SOCKET_(MPI_Comm comm) 458 { 459 PetscErrorCode ierr; 460 PetscBool flg; 461 PetscViewer viewer; 462 MPI_Comm ncomm; 463 464 PetscFunctionBegin; 465 ierr = PetscCommDuplicate(comm,&ncomm,NULL);if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);} 466 if (Petsc_Viewer_Socket_keyval == MPI_KEYVAL_INVALID) { 467 ierr = MPI_Keyval_create(MPI_NULL_COPY_FN,MPI_NULL_DELETE_FN,&Petsc_Viewer_Socket_keyval,0); 468 if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);} 469 } 470 ierr = MPI_Attr_get(ncomm,Petsc_Viewer_Socket_keyval,(void**)&viewer,(int*)&flg); 471 if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);} 472 if (!flg) { /* PetscViewer not yet created */ 473 ierr = PetscViewerSocketOpen(ncomm,0,0,&viewer); 474 if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);} 475 ierr = PetscObjectRegisterDestroy((PetscObject)viewer); 476 if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);} 477 ierr = MPI_Attr_put(ncomm,Petsc_Viewer_Socket_keyval,(void*)viewer); 478 if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);} 479 } 480 ierr = PetscCommDestroy(&ncomm); 481 if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);} 482 PetscFunctionReturn(viewer); 483 } 484 485