home *** CD-ROM | disk | FTP | other *** search
/ Amiga Developer CD v1.2 / amidev_cd_12.iso / devcon / milan_1991 / devcon91.2 / network / socket / examples / transfer.c < prev   
C/C++ Source or Header  |  1992-09-01  |  7KB  |  281 lines

  1. /*
  2. **  Transfer.c
  3. **
  4. **  Written by Dale Larson, Software Engineer, Commodore-Amiga, Inc.
  5. **  Copyright 1991, Commodore-Amiga, Inc.
  6. **  Permission to use granted provided this notice remains intact.
  7. **
  8. **  The functions in this file open, close, read to and write from my_files.
  9. **  my_files are either sockets or AmigaDOS files, depending on whether the
  10. **  file being accessed is remote or local.  The structure includes a flag
  11. **  indicating whether it is a file or socket (see client.h).  Filenames for
  12. **  local files are specified exactly like they always have been.  Filenames
  13. **  for remote files have a host name followed by a '!' followed by a local
  14. **  (to the host) filename (i.e.  host!ram:test).
  15. */
  16.  
  17.  
  18. #include "ncopy.h"
  19. #include "client.h"
  20.  
  21.  
  22. /*
  23. **  my_open()
  24. **
  25. **  Accepts a filename (see parse()) and an AmigaDOS file Open() mode
  26. **  (use MODE_OLDFILE to read, MODE_NEWFILE to write).  Returns a pointer
  27. **  to a my_file or prints an error message and returns NULL.
  28. **
  29. **  Allocates memory for a my_file, then calls function to parse filename.
  30. **  If file is local, attempts to open file and returns a pointer to and
  31. **  AmigaDOS type my_file or prints an error message and returns NULL.  If
  32. **  file is non-local, my_open() does the following:
  33. **
  34. **  Get an machine-readable hostname from the human-readable one.
  35. **  Get a new socket.
  36. **  Connect the socket to a specific port number at the remote host.
  37. **  Send the mode for transfer and the filename to send or recieve.
  38. **  Get back an error string (zero length if no error).
  39. **  Return the pointer to a socket type my_file or print an error message
  40. **    and return NULL.
  41. **
  42. **  NOTE:  The calling function is responsible for my_close()ing the returned
  43. **  my_file pointer.
  44. */
  45. my_file *my_open(char *filename, int mode)
  46. {
  47. my_file *f;
  48. char *host,             /*  host name parsed out of filename  */
  49.      *file,            /*  file parsed out of filename  */
  50.      buffer[LENGTH];        /*  for sprintf() and for errmsg from server  */
  51. struct sockaddr_in server;      /*  socket address (internet) for server  */
  52. struct hostent *hp;
  53. size_t len = sizeof(server);
  54.  
  55.     if( !(f = (my_file *)AllocMem((LONG)sizeof(my_file), 0L)) )
  56.     {
  57.         puts("Unable to open file because of low memory.");
  58.         return(NULL);
  59.     }
  60.  
  61.     /*
  62.     **  parse() allocates memory for the host string (if any) and
  63.     **  we must free it later (file will point into filename).
  64.     */
  65.     if(parse(filename, &host, &file))
  66.     {
  67.         puts("Not enough memory to parse filename.");
  68.         return(NULL);
  69.     }
  70.  
  71.     /*
  72.     **  If it is a local file, open it:
  73.     */
  74.     if(!host)
  75.     {
  76.         f->tag = dos_myfile;
  77.         if(f->data.file = Open(filename, mode))
  78.             return(f);
  79.         sprintf(buffer, "Unable to open local file '%s'", filename);
  80.         PrintFault(IoErr(), buffer);
  81.         return(NULL);
  82.     }
  83.  
  84.     /*
  85.     **  It's not a local file, connect a socket and initialize the server.
  86.     */
  87.     f->tag = socket_myfile;
  88.  
  89.     /*
  90.     **  Since server came off the stack, we initialize it to zero before
  91.     **  using.
  92.     */
  93.     bzero(&server, (int)len);
  94.  
  95.     /*
  96.     **  Find remote machine -- assume host name is dotted-decimal (you
  97.     **  can use inet_addr() under this assumption, call gethostbyname()
  98.     **  if that assumtion fails:
  99.     */
  100.     if( (server.sin_addr.s_addr = inet_addr(host)) == INADDR_NONE)
  101.     {
  102.         if( (hp=gethostbyname(host)) == NULL)
  103.         {
  104.             printf("Can't find host %s\n", host);
  105.             return(NULL);
  106.         }
  107.         /*
  108.         **  Found it by name, copy hp into server.
  109.         */
  110.         bcopy(hp->h_addr, (char *) &server.sin_addr, hp->h_length);
  111.     }
  112.  
  113.     /*
  114.     **  Finish filling out the server socket address by adding the
  115.     **  protocol family to use and the port number to connect to.
  116.     */
  117.     server.sin_family = AF_INET;
  118.     server.sin_port = htons(6666);
  119.  
  120.     /*
  121.     **  Free the host string now that we're done with it.
  122.     */
  123.     FreeMem(host, strlen(host)+1);
  124.  
  125.     /*
  126.     **  Initialize a socket.
  127.     */
  128.     if( (f->data.socket = socket(AF_INET, SOCK_STREAM, 0)) < 0)
  129.     {
  130.         perror("Can't talk to server [socket]");
  131.         return(NULL);
  132.     }
  133.  
  134.     /*
  135.     **  Connect to remote socket specified in 'server'
  136.     **  (which we filled out above).
  137.     */
  138.     if(connect(f->data.socket, (struct sockaddr *)&server, (int)len) < 0)
  139.     {
  140.         perror("Can't talk to server [connect]");
  141.         close(f->data.socket);
  142.         return(NULL);
  143.     }
  144.  
  145.     /*
  146.     ** Send mode of request (are we sending from or to?).
  147.     **    NOTE:  Since the mode is an int, both client and server must
  148.     **           be compiled with the same int-size.
  149.     */
  150.     send(f->data.socket, (char *)&mode, (int)sizeof(int), 0);
  151.  
  152.     /*
  153.     **  Send remote filename (length is strlen()+1 to include '\0').
  154.     */
  155.     send(f->data.socket, file, strlen(file)+1, 0);
  156.  
  157.     /*
  158.     **  Check for errors from the other end.
  159.     **  (could hang here if the server has serious problems)
  160.     */
  161.         recv(f->data.socket, buffer, LENGTH, 0);
  162.  
  163.     if(strlen(buffer)>0)
  164.     {
  165.         printf("Server can't open '%s\n", buffer);
  166.         close(f->data.socket);
  167.         return(NULL);
  168.     }
  169.     return(f);
  170. }
  171.  
  172.  
  173. /*
  174. **  parse()
  175. **
  176. **  Parses the filename 'string' into a hostname and real filename.
  177. **  Modifies *host to the hostname part of a filename (or NULL if there is
  178. **  none).  Modifies *file to point to after 'hostname!'.
  179. **  If everything goes well, returns a RETURN_OK, else a RETURN_ERROR.
  180. **
  181. **  A well-formed filename must, if it contains a hostname, be a hostname
  182. **  followed by a '!', followed a filename the remote system understands.  The
  183. **  hostname must not contain a '/', ':', or '!'
  184. **
  185. **  The case "ncopy ram:x work:" is not supported (because it would require
  186. **  the second invocation of my_open() to know about the first).
  187. **
  188. **  The case "ncopy ram:x sprite!test" is supported.  It copies x to the
  189. **  file test in the directory in which the server on sprite was started.
  190. */
  191.  
  192. int parse(char *string, char **host, char **file)
  193. {
  194. int len;    /*  length of the host string (includes nul)  */
  195.  
  196.     *host = NULL;
  197.     *file = string;
  198.  
  199.     /*
  200.     **  Go through the string searching for important punctuation.
  201.     */
  202.     while(**file != '\0')
  203.     {
  204.         if(**file == '/' || **file == ':')
  205.         {
  206.             *file = string;
  207.             return RETURN_OK;
  208.         }
  209.         if(**file == '!')
  210.             break;
  211.         (*file)++;
  212.     }
  213.  
  214.     /*
  215.     **  Check to see if we reached the end of a puctuationless name.
  216.     */
  217.     if(**file == '\0')
  218.     {
  219.         *file = string;
  220.         return RETURN_OK;
  221.     }
  222.  
  223.     /*
  224.     **  '!' isn't part of the filename, so move past it.
  225.     */
  226.     (*file)++;
  227.  
  228.     len = *file-string;
  229.  
  230.     if( !(*host = (char *)AllocMem(len, 0L)) )
  231.         return RETURN_ERROR;
  232.     CopyMem(string, *host, len-1);
  233.     (*host)[len-1] = '\0';  /*  make it a null terminated string  */
  234.     return RETURN_OK;
  235. }
  236.  
  237.  
  238. /*
  239. **  my_close()
  240. **
  241. **  Closes the my_file file.  NULL is ok.
  242. */
  243. void my_close(my_file *file)
  244. {
  245.     if(!file)
  246.         return;
  247.     if(file->tag == socket_myfile)
  248.         s_close(file->data.socket);
  249.     else
  250.         Close(file->data.file);
  251.     FreeMem(file, (LONG)sizeof(my_file));
  252. }
  253.  
  254.  
  255. /*
  256. **  my_read()
  257. **
  258. **  Fill 'buffer' of 'length' characters from 'file.'
  259. **  Returns number of characters actually read (-1 == error, 0 == EOF).
  260. */
  261. int my_read(my_file *file, char *buffer, int length)
  262. {
  263.     if(file->tag == dos_myfile)
  264.         return( Read(file->data.file, (void *)buffer, length) );
  265.     return( recv(file->data.socket, buffer, length, 0) );
  266. }
  267.  
  268.  
  269. /*
  270. **  my_write()
  271. **
  272. **  Send 'file' 'length' characters from 'buffer'.
  273. **  Returns number of characters actually written (-1 == error).
  274. */
  275. int my_write(my_file *file, char *buffer, int length)
  276. {
  277.     if(file->tag == dos_myfile)
  278.         return( Write(file->data.file, (void *)buffer, length) );
  279.     return( send(file->data.socket, buffer, length, 0) );
  280. }
  281.