static void _sput( T _this_, OEK_Context *context ) { Oek_Impl_ *client = (Oek_Impl_*) OEK_get_client(_this_); OeStore store = client->store; Arena_T arena = context->arena; OekMsg msg = context->cmd_msg; oe_id corid = OekMsg_get_cid(msg); oe_id txnid = OekMsg_get_tid(msg); PutCmd cmd = OekMsg_get_put_cmd(msg); //build the db entry DataObject values = PutCmd_get_data(cmd); assert(values); OeStoreHolder holder = OeStoreHolder_new_with_data(arena, values); OeStoreHolder_set_txn_id (holder, txnid); oe_time exptime; oe_time dur = PutCmd_get_dur(cmd); if (dur == OEC_FOREVER) { exptime = OEC_FOREVER; } else { exptime = oec_get_time_milliseconds() + dur; } OeStoreHolder_set_lease_expire_time(holder, exptime); OeStoreHolder_set_lock (holder, txnid == 0 ? OESTORE_UNLOCKED : OESTORE_WRITE_LOCK ); OeStoreHolder_set_tuple (holder, PutCmd_is_tuple(cmd)); int ret; for ( int i = 0 ; i < OEK_MAX_DB_DEADLOCKS ; i++ ) { ret = OeStore_put(store, holder, arena); if ( ret != OE_STORE_PLEASE_RETRY ) break; OE_DLOG(NULL,OEK_STR_PUT_DL_RETRY, i + 1); } if ( ret ) { OE_ERR( NULL, "%s: %s", OEK_STR_PUT_FAILED, OeStore_strerror(store, ret) ); _send_error(context, 104, OEK_STR_CAN_NOT_STORE); } else { OekMsg res_msg = OekMsg_new(PUT_RES, arena); PutRes res = OekMsg_get_put_res(res_msg); OekMsg_set_cid(res_msg, corid); OekMsg_set_tid(res_msg, txnid); //PutRes_set_expiretime(res, OeStoreHolder_get_lease_expire_time( holder ) ); PutRes_set_lease_id(res, OeStoreHolder_get_lease_id(holder) ); context->res_msgs = Oec_AList_list(arena, res_msg, NULL); _default_write_to_client(context); } }
static bool _handle_request(const char *path, const char *mode, const uint16_t opcode, const struct addrinfo *local_address, const struct sockaddr *client_address, const socklen_t address_size) { /* the socket */ int s = (-1); /* the source address */ struct sockaddr source = {0}; /* the return value */ bool result = false; /* the transaction ID */ short tid = 0; assert(NULL != path); assert((PACKET_TYPE_RRQ == opcode) || (PACKET_TYPE_WRQ == opcode)); assert(0 < address_size); assert(NULL != local_address); assert(NULL != client_address); assert(0 < address_size); /* get the transaction ID */ switch (client_address->sa_family) { case AF_INET: tid = ((struct sockaddr_in *) client_address)->sin_port; break; case AF_INET6: tid = ((struct sockaddr_in6 *) client_address)->sin6_port; break; default: goto end; } /* create a socket */ s = socket(local_address->ai_family, local_address->ai_socktype, local_address->ai_protocol); if (-1 == s) { goto end; } /* set the socket timeout */ if (false == _set_timeout(s)) { goto end; } /* pick a unique source port and bind the socket on it */ (void) memcpy(&source, local_address->ai_addr, local_address->ai_addrlen); if (false == _pick_tid(s, &source, local_address->ai_addrlen)) { goto close_socket; } /* make sure the transfer mode is "octet" */ if (0 != strcmp("octet", mode)) { _send_error(s, ERROR_ILLEGAL_OPERATION, client_address, address_size); goto close_socket; } /* make sure the file doesn't contain a sub-director */ if (NULL != strchr(path, '/')) { _send_error(s, ERROR_ACCESS_VIOLATION, client_address, address_size); goto close_socket; } /* handle the request */ switch (opcode) { case PACKET_TYPE_RRQ: _log_request("GET", path, client_address, address_size); result = _handle_rrq(s, path, client_address, address_size, tid); break; case PACKET_TYPE_WRQ: _log_request("PUT", path, client_address, address_size); result = _handle_wrq(s, path, client_address, address_size, tid); break; default: _send_error(s, ERROR_ILLEGAL_OPERATION, client_address, address_size); goto close_socket; } close_socket: /* close the socket */ (void) close(s); end: return result; }
static bool _handle_rrq(const int s, const char *path, const struct sockaddr *address, const socklen_t address_size, const short tid) { /* a data chunk */ data_t chunk = {{0}}; /* the address the acknowledgement was received from */ struct sockaddr ack_source = {0}; /* the chunk size */ ssize_t size = 0; /* the source address size */ socklen_t source_address_size = 0; /* the input file */ int file = (-1); /* an acknowledment message */ ack_t ack = {0}; /* chunk ID */ uint16_t id = 0; /* the acknowledgement transaction ID */ short ack_tid = 0; /* the return value */ bool result = false; assert(STDERR_FILENO < s); assert(NULL != path); assert(NULL != address); assert(0 < address_size); assert(0 != tid); /* create the file */ file = open(path, O_RDONLY); if (-1 == file) { switch (errno) { case ENOENT: _send_error(s, ERROR_FILE_NOT_FOUND, address, address_size); break; case EPERM: case EACCES: case EROFS: _send_error(s, ERROR_ACCESS_VIOLATION, address, address_size); } goto end; } chunk.header.opcode = htons(PACKET_TYPE_DATA); do { /* read a data chunk */ size = read(file, (void *) &chunk.data, sizeof(chunk.data)); if (-1 == size) { goto close_file; } /* send the chunk */ ++id; chunk.header.id = htons(id); size += sizeof(chunk.header); if (size != sendto(s, (const void *) &chunk, size, 0, address, address_size)) { goto end; } /* wait for an acknowledgment message */ source_address_size = sizeof(ack_source); if (sizeof(ack) != recvfrom(s, (void *) &ack, sizeof(ack), 0, &ack_source, &source_address_size)) { goto close_file; } /* make sure the acknowledgment is an acknowledgment packet */ if (htons(PACKET_TYPE_ACK) != ack.opcode) { goto close_file; } /* make sure the acknowledgment message has the right chunk number */ if (chunk.header.id != ack.id) { goto close_file; } /* make sure the acknowledgment message has the right transaction ID */ switch (ack_source.sa_family) { case AF_INET: ack_tid = ((struct sockaddr_in *) &ack_source)->sin_port; break; case AF_INET6: ack_tid = ((struct sockaddr_in6 *) &ack_source)->sin6_port; break; } if (tid != ack_tid) { _send_error(s, ERROR_UNKNOWN_TID, address, address_size); goto close_file; } /* stop once a small or empty chunk is sent */ } while (sizeof(chunk) == size); /* report success */ result = true; close_file: /* close the file */ (void) close(file); end: return result; }
static bool _handle_wrq(const int s, const char *path, const struct sockaddr *address, const socklen_t address_size, const short tid) { /* a data chunk */ data_t chunk = {{0}}; /* the address the chunk was received from */ struct sockaddr chunk_source = {0}; /* the chunk size */ ssize_t size = 0; /* the source address size */ socklen_t source_address_size = 0; /* the output file */ int file = (-1); /* an acknowledgment packet */ ack_t ack = {0}; /* the chunk transaction ID */ short chunk_tid = 0; /* the return value */ bool result = false; assert(STDERR_FILENO < s); assert(NULL != path); assert(NULL != address); assert(0 < address_size); assert(0 != tid); /* create the file */ file = open(path, O_WRONLY | O_CREAT | O_EXCL, 0666); if (-1 == file) { switch (errno) { case EEXIST: _send_error(s, ERROR_FILE_EXISTS, address, address_size); break; case EPERM: case EACCES: _send_error(s, ERROR_ACCESS_VIOLATION, address, address_size); } goto end; } /* send an acknowledgment message, to indicate the request is valid */ ack.opcode = htons(PACKET_TYPE_ACK); if (sizeof(ack) != sendto(s, (const void *) &ack, sizeof(ack), 0, address, address_size)) { goto end; } do { /* receive a data chunk */ source_address_size = sizeof(chunk_source); size = recvfrom(s, (void *) &chunk, sizeof(chunk), 0, &chunk_source, &source_address_size); if (-1 == size) { goto close_file; } /* make sure the chunk is a data packet */ if (htons(PACKET_TYPE_DATA) != chunk.header.opcode) { goto close_file; } /* make sure the chunk was sent with the right transaction ID */ switch (chunk_source.sa_family) { case AF_INET: chunk_tid = ((struct sockaddr_in *) &chunk_source)->sin_port; break; case AF_INET6: chunk_tid = ((struct sockaddr_in6 *) &chunk_source)->sin6_port; break; } if (tid != chunk_tid) { _send_error(s, ERROR_UNKNOWN_TID, address, address_size); goto close_file; } /* write the chunk to the file */ size -= sizeof(chunk.header); if (size != write(file, (const void *) &chunk.data, (size_t) size)) { if (ENOSPC == errno) { _send_error(s, ERROR_DISK_FULL, address, address_size); } goto close_file; } /* send an acknowledgment message, to indicate the chunk was received */ ack.id = chunk.header.id; if (sizeof(ack) != sendto(s, (const void *) &ack, sizeof(ack), 0, address, address_size)) { goto close_file; } /* stop once a small or empty chunk is received */ } while (sizeof(chunk.data) == size); /* report success */ result = true; close_file: /* close the file */ (void) close(file); /* upon failure, also delete it */ if (false == result) { (void) unlink(path); } end: return result; }