src/vsl_rcpd.c

Go to the documentation of this file.
00001 /*
00002  * Copyright 2005, 2006, Internet2
00003  * Legal conditions are in file LICENSE
00004  * (MD5 = c434f2e53b8089d8b4d0172c7ce07360).
00005  */
00006 
00007 /**
00008  * @file   vsl_rcpd.c
00009  * @author Nikolaus Rath
00010  * @brief  VSL file transfer server
00011  */
00012 
00013 #include "vsl_rcp.h"
00014 #include "vsl_api.h"
00015 #include <sys/types.h>
00016 #include <sys/stat.h>
00017 #include <unistd.h>
00018 #include "vsl.h"
00019 #include <pwd.h>
00020 #include <strings.h>
00021 #include <string.h>
00022 #include <stdlib.h>
00023 #include <stdio.h>
00024 #include <fcntl.h>
00025 #include <signal.h>
00026 #include "vfer.h"
00027 
00028 /**
00029  * @brief info structure used for parsing the command line arguments and options of test_rcpd
00030  */
00031 typedef struct vsl_rcpd_info {
00032     char        user            [MAX_USER];
00033     char        home_dir        [MAX_PATH];
00034 } vsl_rcpd_info;
00035 
00036 
00037 /**
00038  * This function is a catcher of SIGINT signal, installed in main()
00039  */
00040 void sig_handler(int sig) {
00041     exit(1);
00042 } /* sig_handler() */
00043 
00044 
00045 
00046 /**
00047  * main
00048  */
00049 int main (int argc, char** argv) {
00050     int ret;
00051 
00052     /* Parse commandline */
00053     if ( argc < 2 ||
00054          strncmp(argv[1], MAGIC_PARM, sizeof(MAGIC_PARM)) != 0 ) {
00055         fprintf(stderr, "to be called by vsl_rcp only!\n");
00056         exit(1);
00057     }
00058     else if ( argc > 2 ) {
00059         FILE* fp;
00060         if ( (fp = fopen(argv[2], "w")) == NULL) {
00061             fprintf(stderr, "cannot open %s for writing: %s!\n",
00062                     argv[2], strerror(errno));
00063             exit(VSL_PERM);
00064         }
00065         if ( argc == 3 )
00066             vsl_debug(fp, NULL);
00067         else if ( argc == 4 )
00068             vsl_debug(fp, argv[3]);
00069     }
00070 
00071     /* find out and cache the username running this server */
00072     vsl_rcpd_info info;
00073     struct passwd *pwentry;
00074     int uid=getuid();
00075     if ((pwentry = getpwuid(uid)) == NULL) {
00076         fprintf(stderr, "failed getting password entry for uid(%d)\n", uid);
00077         exit(VSL_PERM);
00078     }
00079     if (strlen(pwentry->pw_dir) > MAX_PATH) {
00080         fprintf(stderr, "length of home dir must be less than %d\n", MAX_PATH);
00081         exit(VSL_PERM);
00082     }
00083     strncpy(info.home_dir, pwentry->pw_dir, MAX_PATH);
00084     strncpy(info.user, pwentry->pw_name, MAX_USER);
00085 
00086     /* Init sockets */
00087     vsl_sock ssock;
00088     vfer_fd vfd;
00089     if ( (ret = vsl_init()) != 0) {
00090         fprintf(stderr, "cannot init vsl: %s!\n", vsl_errortext(ret));
00091         exit(VSL_TEMP);
00092     }
00093     if ( (vfd = vfer_socket(SOCK_DGRAM)) < 0) {
00094         fprintf(stderr, "vfer_socket failed: %s!\n", vfer_errortext(vfd));
00095         exit(VSL_TEMP);
00096     }
00097     if ( (ret = vsl_socket(&ssock, vfd)) != 0) {
00098         fprintf(stderr, "vsl_socket failed: %s!\n", vsl_errortext(ret));
00099         exit(VSL_TEMP);
00100     }
00101 
00102     /* Connect */
00103     if ( (ret = vsl_accept_ssh(&ssock)) != 0) {
00104         fprintf(stderr, "vsl_accept_ssh failed: %s!\n", vsl_errortext(ret));
00105         exit(VSL_TEMP);
00106     }
00107     // Close listening socket
00108     vfer_close(vfd);
00109     vfd = vsl_vferfd(&ssock);
00110 
00111     /* install a handler for SIGINT that will exit gracefully */
00112     struct sigaction sa;
00113     sa.sa_handler = &(sig_handler);
00114     if (sigaction(SIGINT, &sa, NULL) == -1)
00115         LOG("couldn't install a signal handler for SIGINT");
00116 
00117     /* receive client msg */
00118     vsl_client_msg_t client_msg;
00119     vsl_server_msg_t server_msg;
00120     if ((ret = vsl_recv(&ssock, &client_msg, sizeof(vsl_client_msg_t))) < 0) {
00121         LOG( "failed to read client message: %s!", vsl_errortext(ret));
00122         goto CLEAN_UP;
00123     }
00124     client_msg.file_size = ntohl(client_msg.file_size);
00125 
00126     LOG("received: rpath[%s] from_remote[%d] file_size[%u]",
00127         client_msg.remote_path, client_msg.from_remote, client_msg.file_size);
00128 
00129     server_msg.file_size = 0;
00130     server_msg.file_size = htonl(server_msg.file_size);
00131 
00132     /* expand out the home directory truncation */
00133     char path[MAX_PATH * 2];
00134     if (client_msg.remote_path[0] == '~') {
00135         strncpy(path, info.home_dir, MAX_PATH);
00136         strncpy(path + strlen(path), client_msg.remote_path+1, MAX_PATH);
00137     } else {
00138         strncpy(path, client_msg.remote_path, MAX_PATH);
00139     }
00140 
00141     LOG( "path expanded to: %s", path);
00142     int fd;
00143     struct stat stat_buf;
00144     if (client_msg.from_remote == 0) {
00145         /* send local file to client */
00146         if ((fd = open(path, O_RDONLY, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP)) == -1) {
00147             LOG( "open for reading failed");
00148             /* send server msg to client */
00149             server_msg.status   = RCP_EOPEN;
00150             server_msg.status   = htonl(server_msg.status);
00151             if ((ret = vsl_send(&ssock, &server_msg, sizeof(vsl_server_msg_t))) < 0) {
00152                 LOG("failed to send server msg to client [%s]", vsl_errortext(ret));
00153                 goto CLEAN_UP;
00154             }
00155         } else {
00156             /* send server msg to client */
00157             server_msg.status   = RCP_READY;
00158             server_msg.file_size        = lseek(fd, 0, SEEK_END);
00159             server_msg.file_size        = htonl(server_msg.file_size);
00160                 server_msg.status       = htonl(server_msg.status);
00161                 if ((ret = vsl_send(&ssock, &server_msg, sizeof(vsl_server_msg_t))) < 0) {
00162                     LOG("failed to send server msg to client [%s]", vsl_errortext(ret));
00163                     goto CLEAN_UP;
00164                 }
00165                 server_msg.file_size    = ntohl(server_msg.file_size);
00166                 if ((ret = vsl_sendfile(&ssock, fd, 0, server_msg.file_size)) < 0) {
00167                     LOG("vfer_sendfile failed [%s]", vsl_errortext(ret));
00168                     goto CLEAN_UP;
00169                 }
00170         }
00171     } else { /* client_msg.from_remote == 1 */
00172         /* receive file from client */
00173 
00174         /* check if path ends if '/' */
00175         if (path[strlen(path) - 1] == '/') {
00176             /* append local_name to path and continue */
00177             strncpy(path + strlen(path), client_msg.local_name, 2*MAX_PATH - strlen(path));
00178         } else {
00179             /* check if the path is an existing directory */
00180             if (stat(path, &stat_buf) == -1) {
00181                 server_msg.status = RCP_EOTHER;
00182                 switch (errno) {
00183                 case ENOENT:
00184                     /* file that does not exist, great, continue */
00185                     LOG( "writing to a new file");
00186                     break;
00187                 case ENOTDIR: /* bad path (one of directories doesn't exist, bail */
00188                     LOG("bad path from client");
00189                     server_msg.status = RCP_ENOENT;
00190                 default: /* something is wrong, bail */
00191                     LOG("stat failed");
00192                     /* send server msg to client */
00193                     server_msg.status = htonl(server_msg.status);
00194                     if ((ret = vsl_send(&ssock, &server_msg, sizeof(vsl_server_msg_t))) < 0) {
00195                         LOG("failed to send server msg to client [%s]", vsl_errortext(ret));
00196                         goto CLEAN_UP;
00197                     }
00198                 }
00199             } else {
00200                 /* check if path is an existing directory */
00201                 if (stat_buf.st_mode & S_IFDIR) {
00202                     /* yes- append local_name to path and continue */
00203                     path[strlen(path)] = '/';
00204                     path[strlen(path)+1] = 0;
00205                     strncpy(path + strlen(path), client_msg.local_name, 256 - strlen(path));
00206                 }
00207             }
00208         }
00209 
00210         if ((fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP)) == -1) {
00211             LOG("open for writing failed");
00212             /* send server msg to client */
00213             server_msg.status = RCP_EOPEN;
00214             server_msg.status = htonl(server_msg.status);
00215             if ((ret = vsl_send(&ssock, &server_msg, sizeof(vsl_server_msg_t))) < 0) {
00216                 LOG("failed to send server msg to client [%s]", vsl_errortext(ret));
00217                 goto CLEAN_UP;
00218             }
00219         } else {
00220             /* send server msg to client */
00221             server_msg.status = RCP_READY;
00222             server_msg.status = htonl(server_msg.status);
00223             if ((ret = vsl_send(&ssock, &server_msg, sizeof(vsl_server_msg_t))) < 0) {
00224                 LOG("failed to send server msg to client [%s]", vsl_errortext(ret));
00225                 goto CLEAN_UP;
00226             }
00227             if ((ret = vsl_recvfile(&ssock, fd, 0, client_msg.file_size)) < 0){
00228                 LOG("vfer_recvfile failed [%s]", vsl_errortext(ret));
00229                 goto CLEAN_UP;
00230             }
00231         }
00232     }
00233 CLEAN_UP:
00234     LOG("Closing the accepted socket");
00235     vsl_close(&ssock);
00236     vfer_close(vfd);
00237     if ( (ret = vsl_uninit()) != 0 )
00238         LOG("uninit failed: %s!", vsl_errortext(ret));
00239     close(fd);
00240 
00241     return 0;
00242 } /* main() */
00243 
00244 /*
00245  * Local Variables:
00246  * compile-command: "cd ..; make file_xfer"
00247  * compilation-search-path: ("..")
00248  * End:
00249  */

Generated on Tue Aug 8 16:07:20 2006 for VFER by  doxygen 1.4.7