/* ** Copyright (C) 2003-2007 by Carnegie Mellon University. ** ** @OPENSOURCE_HEADER_START@ ** ** Use of the SILK system and related source code is subject to the terms ** of the following licenses: ** ** GNU Public License (GPL) Rights pursuant to Version 2, June 1991 ** Government Purpose License Rights (GPLR) pursuant to DFARS 252.225-7013 ** ** NO WARRANTY ** ** ANY INFORMATION, MATERIALS, SERVICES, INTELLECTUAL PROPERTY OR OTHER ** PROPERTY OR RIGHTS GRANTED OR PROVIDED BY CARNEGIE MELLON UNIVERSITY ** PURSUANT TO THIS LICENSE (HEREINAFTER THE "DELIVERABLES") ARE ON AN ** "AS-IS" BASIS. CARNEGIE MELLON UNIVERSITY MAKES NO WARRANTIES OF ANY ** KIND, EITHER EXPRESS OR IMPLIED AS TO ANY MATTER INCLUDING, BUT NOT ** LIMITED TO, WARRANTY OF FITNESS FOR A PARTICULAR PURPOSE, ** MERCHANTABILITY, INFORMATIONAL CONTENT, NONINFRINGEMENT, OR ERROR-FREE ** OPERATION. CARNEGIE MELLON UNIVERSITY SHALL NOT BE LIABLE FOR INDIRECT, ** SPECIAL OR CONSEQUENTIAL DAMAGES, SUCH AS LOSS OF PROFITS OR INABILITY ** TO USE SAID INTELLECTUAL PROPERTY, UNDER THIS LICENSE, REGARDLESS OF ** WHETHER SUCH PARTY WAS AWARE OF THE POSSIBILITY OF SUCH DAMAGES. ** LICENSEE AGREES THAT IT WILL NOT MAKE ANY WARRANTY ON BEHALF OF ** CARNEGIE MELLON UNIVERSITY, EXPRESS OR IMPLIED, TO ANY PERSON ** CONCERNING THE APPLICATION OF OR THE RESULTS TO BE OBTAINED WITH THE ** DELIVERABLES UNDER THIS LICENSE. ** ** Licensee hereby agrees to defend, indemnify, and hold harmless Carnegie ** Mellon University, its trustees, officers, employees, and agents from ** all claims or demands made against them (and any related losses, ** expenses, or attorney's fees) arising out of, or relating to Licensee's ** and/or its sub licensees' negligent use or willful misuse of or ** negligent conduct or willful misconduct regarding the Software, ** facilities, or other rights or assistance granted by Carnegie Mellon ** University under this License, including, but not limited to, any ** claims of product liability, personal injury, death, damage to ** property, or violation of any laws or regulations. ** ** Carnegie Mellon University Software Engineering Institute authored ** documents are sponsored by the U.S. Department of Defense under ** Contract F19628-00-C-0003. Carnegie Mellon University retains ** copyrights in all material produced under this contract. The U.S. ** Government retains a non-exclusive, royalty-free license to publish or ** reproduce these documents, or allow others to do so, for U.S. ** Government purposes only pursuant to the copyright license under the ** contract clause at 252.227.7013. ** ** @OPENSOURCE_HEADER_END@ */ /* ** Implements sending low-level primitives. ** */ #include "silk.h" RCSIDENT("$SiLK: skt-send.c 7397 2007-06-06 14:45:33Z mthomas $"); #include #include #include "utils.h" #include "skt-protocol.h" #include "skt-private.h" #ifdef TEST_PRINTF_FORMATS # define IF_LOGFN(f) printf #else # define IF_LOGFN(f) if (! f) { } else f #endif sktErr_t skSendHandshake(int sock, skt_logfn_t logf, int *control) { #define LOG IF_LOGFN(logf) sk_transfer_header_prologue_t p; sktErr_t err; int saveerrno; memset(&p, 0, sizeof(p)); p.version = SK_TRANSFER_PROTOCOL_V1; p.cksum_type = SK_TRANSFER_NONE; p.type = SK_TRANSFER_HANDSHAKE; if (skwrite(sock, &p, sizeof(p), control, NULL, &err) != sizeof(p)) { switch (err) { case SK_TRANSFER_ESYSTEM: saveerrno = errno; LOG("Failed to write handshake."); errno = saveerrno; break; case SK_TRANSFER_ESHUTDOWN_EXTERNAL: LOG("Connection shut down"); break; default: LOG("Connection died"); } return err; } return 0; #undef LOG } sktErr_t skSendShutdown(int sock, skt_logfn_t logf, int *control) { #define LOG IF_LOGFN(logf) sk_transfer_header_prologue_t p; sktErr_t err; int saveerrno; memset(&p, 0, sizeof(p)); p.version = SK_TRANSFER_PROTOCOL_V1; p.cksum_type = SK_TRANSFER_NONE; p.type = SK_TRANSFER_SHUTDOWN; if (skwrite(sock, &p, sizeof(p), control, NULL, &err) != sizeof(p)) { switch (err) { case SK_TRANSFER_ESYSTEM: saveerrno = errno; LOG("Failed to send shutdown prologue."); errno = saveerrno; break; case SK_TRANSFER_ESHUTDOWN_EXTERNAL: LOG("Connection shut down"); break; default: LOG("Connection died"); } return err; } return 0; #undef LOG } #ifdef SKT_DEBUG #define SKT_DEBUG_TIMEOUT(x) \ do { \ char *dbg = getenv("SKT_DEBUG_" x); \ if (dbg) { \ if (strcmp(dbg, "hang") == 0) { \ timeout = &skt_hang; \ } else if (strcmp(dbg, "exit") == 0) { \ timeout = &skt_exit; \ } else { \ timeout = &skt_exit; \ } \ } \ } while (0) #else #define SKT_DEBUG_TIMEOUT(x) #endif sktErr_t skSendFileBase( int sock, char *path, char *name, skt_logfn_t logf, int *control, uint32_t baud, uint8_t acktimeout) { #define LOG IF_LOGFN(logf) struct stat st; int fd; void *map; sk_transfer_file_info_t info; sk_transfer_header_prologue_t p; uint8_t ack; struct timeval to; struct timeval *timeout = NULL; ssize_t rv; char *basename; sktErr_t err; int saveerrno; if (name) { basename = name; } else { basename = strrchr(path, '/'); if (basename == NULL) { basename = path; } else { basename++; } } /* Check to see if the file exists */ if (!fileExists(path)) { LOG("%s does not exist: cannot send", basename); return SK_TRANSFER_EFATAL; } if ((fd = open(path, O_RDONLY)) == -1) { LOG("cannot open %s for reading", basename); return SK_TRANSFER_EFATAL; } if (fstat(fd, &st) == -1) { LOG("failed to stat %s", basename); close(fd); return SK_TRANSFER_EFATAL; } map = mmap(0, st.st_size, PROT_READ, MAP_SHARED, fd, 0); close(fd); if (map == MAP_FAILED) { LOG("failed to mmap %s [%s]", basename, strerror(errno)); return SK_TRANSFER_EFATAL; } /* Set up prologue */ memset(&p, 0, sizeof(p)); p.version = 1; p.cksum_type = SK_TRANSFER_NONE; p.type = SK_TRANSFER_FILETRANSFER; /* Set up info */ memset(&info, 0, sizeof(info)); strncpy(info.name, basename, sizeof(info.name)); if (info.name[sizeof(info.name) - 1] != 0) { LOG("Filename %s too long for protocol.", basename); return SK_TRANSFER_EFATAL; } info.size = htonl(st.st_size); /* Send the file! */ SKT_DEBUG_TIMEOUT("WRITE_PROLOGUE"); if ((rv = skwrite(sock, &p, sizeof(p), control, timeout, &err)) != sizeof(p)) { saveerrno = errno; switch (err) { case SK_TRANSFER_ESYSTEM: LOG("Failed write in prologue"); break; case SK_TRANSFER_ESHUTDOWN_EXTERNAL: LOG("Connection shut down"); break; default: LOG("Connection died"); } munmap(map, st.st_size); errno = saveerrno; return err; } SKT_DEBUG_TIMEOUT("WRITE_FILE_INFO"); if ((rv = skwrite(sock, &info, sizeof(info), control, timeout, &err)) != sizeof(info)) { saveerrno = errno; switch (err) { case SK_TRANSFER_ESYSTEM: LOG("Failed write in file info"); break; case SK_TRANSFER_ESHUTDOWN_EXTERNAL: LOG("Connection shut down"); break; default: LOG("Connection died"); } munmap(map, st.st_size); errno = saveerrno; return err; } /* Calculate the amount of time we should spend waiting */ to.tv_sec = st.st_size / baud * 8 + 10; to.tv_usec = 0; timeout = &to; SKT_DEBUG_TIMEOUT("WRITE_FILE"); if ((rv = skwrite(sock, map, st.st_size, control, timeout, &err)) != st.st_size) { saveerrno = errno; switch (err) { case SK_TRANSFER_ESYSTEM: LOG("Failed write of file"); break; case SK_TRANSFER_ETIMEOUT: LOG("Transfer timed out."); break; case SK_TRANSFER_ESHUTDOWN_EXTERNAL: LOG("Connection shut down"); break; default: LOG("Connection died"); } munmap(map, st.st_size); errno = saveerrno; return err; } munmap(map, st.st_size); if (acktimeout) { to.tv_sec = acktimeout; to.tv_usec = 0; } timeout = acktimeout ? &to : NULL; SKT_DEBUG_TIMEOUT("READ_ACK"); if ((rv = skread(sock, &ack, 1, control, timeout, &err) != 1)) { saveerrno = errno; switch (err) { case SK_TRANSFER_ESYSTEM: LOG("Failed read of ack"); break; case SK_TRANSFER_ETIMEOUT: LOG("Timed out waiting for ACK"); break; case SK_TRANSFER_ESHUTDOWN_EXTERNAL: LOG("Connection shut down"); break; default: LOG("Connection died waiting for ACK"); } errno = saveerrno; return err; } if (ack != SK_TRANSFER_ACK) { LOG("received NAK for %s", basename); return SK_TRANSFER_EFAILED; } return SK_TRANSFER_ESUCCESS; #undef LOG } sktErr_t skSendFile( int sock, char *path, char *name, skt_logfn_t logf, int *control) { return skSendFileBase(sock, path, name, logf, control, 300, SK_TRANSFER_ACKTIMEOUT); } /* ** Local Variables: ** mode:c ** indent-tabs-mode:nil ** c-basic-offset:4 ** End: */