/* Daniel Reeves http://ai.eecs.umich.edu/people/dreeves/misc/math-sockets/ $Id: Sockets.c,v 1.2 2000/02/16 10:43:25 dreeves Exp dreeves $ This is a mathlink program to allow Mathematica code to read and write to arbitrary sockets. TODO: Read should be called ReadLine and there should be a more general Read which doesn't care about newlines! */ #include /* diagnostics */ #include /* NULL */ #include /* read, write */ #include /* memset */ #include /* saddr */ #include /* gethostbyname */ #include "mathlink.h" #include /* #include */ /* #include */ /* #include */ /************************ prototypes ****************************/ int Read(int fd, int maxlen); int Write(int fd, const char *ptr, int nbytes); int SetupConnection(const char *servname, int port); int MLMain(int argc, char ** argv); /* prototype */ /*************************** functions **************************/ int main(int argc, char ** argv) { return MLMain(argc, argv); } /******************************************************************** Read a line from a file/socket descriptor. Read the line one byte at a time, looking for the newline or null terminator. We store the newline or null in the buffer, then follow it with a null. Return the number of characters read. Based on code from "UNIX Network Programming" W. Richard Stevens 1990, p. 280. ********************************************************************/ int Read(const int fd, const int maxlen) { int n, rc = -1; int total = 0; char c; char * p; char * buf; if (fd < 0) { return -1; } /* bad argument */ if (maxlen <= 0) { return 0; } buf = (char*)malloc(maxlen * sizeof(char)); if (buf == NULL) { fprintf(stderr, "Memory allocation failed!\n"); exit(1); } p = buf; for (n = 1; n < maxlen; n++) { if ( (rc = read(fd, &c, 1)) == 1) { total += rc; *p++ = c; if ( (c == '\n') || (c == '\0') || (c == 0) ) { break; } } else if (rc == 0) { if (n == 1) { return -2; } /* Hit on client disconnect */ else { break; } } else { return -3; } /* read error */ } *p = '\0'; MLPutString(stdlink, buf); free(buf); return total; } /******************************************************************** Write a string to a descriptor. We return the number of characters written up to, but not including, the null. Based on code from "UNIX Network Programming" W. Richard Stevens 1990, pp. 279-280. ********************************************************************/ int Write(int fd, const char * ptr, int nBytes) { int nleft, nwritten; if (fd < 0) { return 0; } if (ptr == NULL) { return 0; } if (nBytes <= 0) { return 0; } nleft = nBytes + 1; while (nleft > 0) { nwritten = write(fd, ptr, nleft); if (nwritten <= 0) { return(nwritten); } /* error */ nleft -= nwritten; ptr += nwritten; } return(nBytes - nleft); } /******************************************************************** Setup a connection to the server. Returns socket descriptor if connected, < 0 if not. ********************************************************************/ int SetupConnection(const char * machine, int port) { int err, enable; struct sockaddr_in saddr; struct hostent * ptrh; int sd; if (machine == NULL) { return -2; } if (port < 0) { return -2; } /* create a TCP socket */ sd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); if (sd < 0) { return -2; } /* initialize socket address */ (void)memset((char *) &saddr, 0, sizeof(struct sockaddr_in)); saddr.sin_family = AF_INET; saddr.sin_port = htons((u_short) port); /* set socket to KEEPALIVE */ enable = 1; err = setsockopt(sd, SOL_SOCKET, SO_KEEPALIVE, (char*)&enable, sizeof(int)); if (err) { return -2; } /* convert "machine" to IP address */ ptrh = gethostbyname(machine); if (ptrh == NULL) { return -2; } (void)memcpy(&saddr.sin_addr, ptrh->h_addr, ptrh->h_length); /* connect to the specific server */ err = connect(sd, (struct sockaddr *) &saddr, sizeof(saddr)); if (err < 0) { close(sd); return -2; } return sd; } /********************************************************************* Close the socket, given socket descriptor. Returns 0 (TODO: possible error codes?) ********************************************************************/ int CloseConnection(int sd) { close(sd); return 0; }