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 230 based server. 231 232 Collective on MPI_Comm 233 234 Input Parameters: 235 + comm - the MPI communicator 236 . machine - the machine the server is running on,, use NULL for the local machine, use "server" to passively wait for 237 a connection from elsewhere 238 - port - the port to connect to, use PETSC_DEFAULT for the default 239 240 Output Parameter: 241 . lab - a context to use when communicating with the server 242 243 Level: intermediate 244 245 Notes: 246 Most users should employ the following commands to access the 247 MATLAB PetscViewers 248 $ 249 $ PetscViewerSocketOpen(MPI_Comm comm, char *machine,int port,PetscViewer &viewer) 250 $ MatView(Mat matrix,PetscViewer viewer) 251 $ 252 $ or 253 $ 254 $ PetscViewerSocketOpen(MPI_Comm comm,char *machine,int port,PetscViewer &viewer) 255 $ VecView(Vec vector,PetscViewer viewer) 256 257 Options Database Keys: 258 For use with PETSC_VIEWER_SOCKET_WORLD, PETSC_VIEWER_SOCKET_SELF, 259 PETSC_VIEWER_SOCKET_() or if 260 NULL is passed for machine or PETSC_DEFAULT is passed for port 261 $ -viewer_socket_machine <machine> 262 $ -viewer_socket_port <port> 263 264 Environmental variables: 265 + PETSC_VIEWER_SOCKET_PORT portnumber 266 - PETSC_VIEWER_SOCKET_MACHINE machine name 267 268 Currently the only socket client available is MATLAB. See 269 src/dm/da/examples/tests/ex12.c and ex12.m for an example of usage. 270 271 Notes: The socket viewer is in some sense a subclass of the binary viewer, to read and write to the socket 272 use PetscViewerBinaryRead/Write/GetDescriptor(). 273 274 Concepts: MATLAB^sending data 275 Concepts: sockets^sending data 276 277 .seealso: MatView(), VecView(), PetscViewerDestroy(), PetscViewerCreate(), PetscViewerSetType(), 278 PetscViewerSocketSetConnection(), PETSC_VIEWER_SOCKET_, PETSC_VIEWER_SOCKET_WORLD, 279 PETSC_VIEWER_SOCKET_SELF, PetscViewerBinaryWrite(), PetscViewerBinaryRead(), PetscViewerBinaryWriteStringArray(), 280 PetscBinaryViewerGetDescriptor() 281 @*/ 282 PetscErrorCode PetscViewerSocketOpen(MPI_Comm comm,const char machine[],int port,PetscViewer *lab) 283 { 284 PetscErrorCode ierr; 285 286 PetscFunctionBegin; 287 ierr = PetscViewerCreate(comm,lab);CHKERRQ(ierr); 288 ierr = PetscViewerSetType(*lab,PETSCVIEWERSOCKET);CHKERRQ(ierr); 289 ierr = PetscViewerSocketSetConnection(*lab,machine,port);CHKERRQ(ierr); 290 PetscFunctionReturn(0); 291 } 292 293 #undef __FUNCT__ 294 #define __FUNCT__ "PetscViewerSetFromOptions_Socket" 295 static PetscErrorCode PetscViewerSetFromOptions_Socket(PetscOptionItems *PetscOptionsObject,PetscViewer v) 296 { 297 PetscErrorCode ierr; 298 PetscInt def = -1; 299 char sdef[256]; 300 PetscBool tflg; 301 302 PetscFunctionBegin; 303 /* 304 These options are not processed here, they are processed in PetscViewerSocketSetConnection(), they 305 are listed here for the GUI to display 306 */ 307 ierr = PetscOptionsHead(PetscOptionsObject,"Socket PetscViewer Options");CHKERRQ(ierr); 308 ierr = PetscOptionsGetenv(PetscObjectComm((PetscObject)v),"PETSC_VIEWER_SOCKET_PORT",sdef,16,&tflg);CHKERRQ(ierr); 309 if (tflg) { 310 ierr = PetscOptionsStringToInt(sdef,&def);CHKERRQ(ierr); 311 } else def = PETSCSOCKETDEFAULTPORT; 312 ierr = PetscOptionsInt("-viewer_socket_port","Port number to use for socket","PetscViewerSocketSetConnection",def,0,0);CHKERRQ(ierr); 313 314 ierr = PetscOptionsString("-viewer_socket_machine","Machine to use for socket","PetscViewerSocketSetConnection",sdef,0,0,0);CHKERRQ(ierr); 315 ierr = PetscOptionsGetenv(PetscObjectComm((PetscObject)v),"PETSC_VIEWER_SOCKET_MACHINE",sdef,256,&tflg);CHKERRQ(ierr); 316 if (!tflg) { 317 ierr = PetscGetHostName(sdef,256);CHKERRQ(ierr); 318 } 319 ierr = PetscOptionsTail();CHKERRQ(ierr); 320 PetscFunctionReturn(0); 321 } 322 323 /*MC 324 PETSCVIEWERSOCKET - A viewer that writes to a Unix socket 325 326 327 .seealso: PetscViewerSocketOpen(), PetscViewerDrawOpen(), PETSC_VIEWER_DRAW_(),PETSC_VIEWER_DRAW_SELF, PETSC_VIEWER_DRAW_WORLD, 328 PetscViewerCreate(), PetscViewerASCIIOpen(), PetscViewerBinaryOpen(), PETSCVIEWERBINARY, PETSCVIEWERDRAW, 329 PetscViewerMatlabOpen(), VecView(), DMView(), PetscViewerMatlabPutArray(), PETSCVIEWERASCII, PETSCVIEWERMATLAB, 330 PetscViewerFileSetName(), PetscViewerFileSetMode(), PetscViewerFormat, PetscViewerType, PetscViewerSetType() 331 332 M*/ 333 334 #undef __FUNCT__ 335 #define __FUNCT__ "PetscViewerCreate_Socket" 336 PETSC_EXTERN PetscErrorCode PetscViewerCreate_Socket(PetscViewer v) 337 { 338 PetscViewer_Socket *vmatlab; 339 PetscErrorCode ierr; 340 341 PetscFunctionBegin; 342 ierr = PetscNewLog(v,&vmatlab);CHKERRQ(ierr); 343 vmatlab->port = 0; 344 v->data = (void*)vmatlab; 345 v->ops->destroy = PetscViewerDestroy_Socket; 346 v->ops->flush = 0; 347 v->ops->setfromoptions = PetscViewerSetFromOptions_Socket; 348 349 /* lie and say this is a binary viewer; then all the XXXView_Binary() methods will work correctly on it */ 350 ierr = PetscObjectChangeTypeName((PetscObject)v,PETSCVIEWERBINARY);CHKERRQ(ierr); 351 PetscFunctionReturn(0); 352 } 353 354 #undef __FUNCT__ 355 #define __FUNCT__ "PetscViewerSocketSetConnection" 356 /*@C 357 PetscViewerSocketSetConnection - Sets the machine and port that a PETSc socket 358 viewer is to use 359 360 Logically Collective on PetscViewer 361 362 Input Parameters: 363 + v - viewer to connect 364 . machine - host to connect to, use NULL for the local machine,use "server" to passively wait for 365 a connection from elsewhere 366 - port - the port on the machine one is connecting to, use PETSC_DEFAULT for default 367 368 Level: advanced 369 370 .seealso: PetscViewerSocketOpen() 371 @*/ 372 PetscErrorCode PetscViewerSocketSetConnection(PetscViewer v,const char machine[],int port) 373 { 374 PetscErrorCode ierr; 375 PetscMPIInt rank; 376 char mach[256]; 377 PetscBool tflg; 378 PetscViewer_Socket *vmatlab = (PetscViewer_Socket*)v->data; 379 380 PetscFunctionBegin; 381 /* PetscValidLogicalCollectiveInt(v,port,3); not a PetscInt */ 382 if (port <= 0) { 383 char portn[16]; 384 ierr = PetscOptionsGetenv(PetscObjectComm((PetscObject)v),"PETSC_VIEWER_SOCKET_PORT",portn,16,&tflg);CHKERRQ(ierr); 385 if (tflg) { 386 PetscInt pport; 387 ierr = PetscOptionsStringToInt(portn,&pport);CHKERRQ(ierr); 388 port = (int)pport; 389 } else port = PETSCSOCKETDEFAULTPORT; 390 } 391 if (!machine) { 392 ierr = PetscOptionsGetenv(PetscObjectComm((PetscObject)v),"PETSC_VIEWER_SOCKET_MACHINE",mach,256,&tflg);CHKERRQ(ierr); 393 if (!tflg) { 394 ierr = PetscGetHostName(mach,256);CHKERRQ(ierr); 395 } 396 } else { 397 ierr = PetscStrncpy(mach,machine,256);CHKERRQ(ierr); 398 } 399 400 ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)v),&rank);CHKERRQ(ierr); 401 if (!rank) { 402 ierr = PetscStrcmp(mach,"server",&tflg);CHKERRQ(ierr); 403 if (tflg) { 404 int listenport; 405 ierr = PetscInfo1(v,"Waiting for connection from socket process on port %D\n",port);CHKERRQ(ierr); 406 ierr = PetscSocketEstablish(port,&listenport);CHKERRQ(ierr); 407 ierr = PetscSocketListen(listenport,&vmatlab->port);CHKERRQ(ierr); 408 close(listenport); 409 } else { 410 ierr = PetscInfo2(v,"Connecting to socket process on port %D machine %s\n",port,mach);CHKERRQ(ierr); 411 ierr = PetscOpenSocket(mach,port,&vmatlab->port);CHKERRQ(ierr); 412 } 413 } 414 PetscFunctionReturn(0); 415 } 416 417 /* ---------------------------------------------------------------------*/ 418 /* 419 The variable Petsc_Viewer_Socket_keyval is used to indicate an MPI attribute that 420 is attached to a communicator, in this case the attribute is a PetscViewer. 421 */ 422 static PetscMPIInt Petsc_Viewer_Socket_keyval = MPI_KEYVAL_INVALID; 423 424 425 #undef __FUNCT__ 426 #define __FUNCT__ "PETSC_VIEWER_SOCKET_" 427 /*@C 428 PETSC_VIEWER_SOCKET_ - Creates a socket viewer shared by all processors in a communicator. 429 430 Collective on MPI_Comm 431 432 Input Parameter: 433 . comm - the MPI communicator to share the socket PetscViewer 434 435 Level: intermediate 436 437 Options Database Keys: 438 For use with the default PETSC_VIEWER_SOCKET_WORLD or if 439 NULL is passed for machine or PETSC_DEFAULT is passed for port 440 $ -viewer_socket_machine <machine> 441 $ -viewer_socket_port <port> 442 443 Environmental variables: 444 + PETSC_VIEWER_SOCKET_PORT portnumber 445 - PETSC_VIEWER_SOCKET_MACHINE machine name 446 447 Notes: 448 Unlike almost all other PETSc routines, PetscViewer_SOCKET_ does not return 449 an error code. The socket PetscViewer is usually used in the form 450 $ XXXView(XXX object,PETSC_VIEWER_SOCKET_(comm)); 451 452 Currently the only socket client available is MATLAB. See 453 src/dm/da/examples/tests/ex12.c and ex12.m for an example of usage. 454 455 Connects to a waiting socket and stays connected until PetscViewerDestroy() is called. 456 457 Use this for communicating with an interactive MATLAB session, see PETSC_VIEWER_MATLAB_() for communicating with the MATLAB engine. 458 459 .seealso: PETSC_VIEWER_SOCKET_WORLD, PETSC_VIEWER_SOCKET_SELF, PetscViewerSocketOpen(), PetscViewerCreate(), 460 PetscViewerSocketSetConnection(), PetscViewerDestroy(), PETSC_VIEWER_SOCKET_(), PetscViewerBinaryWrite(), PetscViewerBinaryRead(), 461 PetscViewerBinaryWriteStringArray(), PetscBinaryViewerGetDescriptor(), PETSC_VIEWER_MATLAB_() 462 @*/ 463 PetscViewer PETSC_VIEWER_SOCKET_(MPI_Comm comm) 464 { 465 PetscErrorCode ierr; 466 PetscBool flg; 467 PetscViewer viewer; 468 MPI_Comm ncomm; 469 470 PetscFunctionBegin; 471 ierr = PetscCommDuplicate(comm,&ncomm,NULL);if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);} 472 if (Petsc_Viewer_Socket_keyval == MPI_KEYVAL_INVALID) { 473 ierr = MPI_Keyval_create(MPI_NULL_COPY_FN,MPI_NULL_DELETE_FN,&Petsc_Viewer_Socket_keyval,0); 474 if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);} 475 } 476 ierr = MPI_Attr_get(ncomm,Petsc_Viewer_Socket_keyval,(void**)&viewer,(int*)&flg); 477 if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);} 478 if (!flg) { /* PetscViewer not yet created */ 479 ierr = PetscViewerSocketOpen(ncomm,0,0,&viewer); 480 if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);} 481 ierr = PetscObjectRegisterDestroy((PetscObject)viewer); 482 if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);} 483 ierr = MPI_Attr_put(ncomm,Petsc_Viewer_Socket_keyval,(void*)viewer); 484 if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);} 485 } 486 ierr = PetscCommDestroy(&ncomm); 487 if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);} 488 PetscFunctionReturn(viewer); 489 } 490 491