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