kinetic-c  v0.12.0
Seagate Kinetic Protocol Client Library for C
kinetic_operation.c
Go to the documentation of this file.
1 /*
2 * kinetic-c
3 * Copyright (C) 2015 Seagate Technology.
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 *
19 */
20 #include "kinetic_operation.h"
21 #include "kinetic_controller.h"
22 #include "kinetic_session.h"
23 #include "kinetic_message.h"
24 #include "kinetic_bus.h"
25 #include "kinetic_response.h"
26 #include "kinetic_device_info.h"
27 #include "kinetic_allocator.h"
28 #include "kinetic_logger.h"
29 #include "kinetic_request.h"
30 
31 #include <stdlib.h>
32 #include <errno.h>
33 #include <sys/time.h>
34 #include <stdio.h>
35 
36 #include "kinetic_acl.h"
37 
38 #ifdef TEST
39 uint8_t * msg = NULL;
40 size_t msgSize = 0;
41 #endif
42 
43 void KineticOperation_ValidateOperation(KineticOperation* op)
44 {
45  KINETIC_ASSERT(op);
46  KINETIC_ASSERT(op->session);
47  KINETIC_ASSERT(op->request);
48  KINETIC_ASSERT(op->request->command);
49  KINETIC_ASSERT(op->request->command->header);
50  KINETIC_ASSERT(op->request->command->header->has_sequence);
51 }
52 
53 static KineticStatus send_request_in_lock(KineticOperation* const op);
54 
55 KineticStatus KineticOperation_SendRequest(KineticOperation* const op)
56 {
57  KineticSession *session = op->session;
59 
60  if (!KineticRequest_LockSend(session)) {
62  }
65  return status;
66 }
67 
68 static void log_request_seq_id(int fd, int64_t seq_id, KineticMessageType mt)
69 {
70  #ifdef TEST
71  (void)fd;
72  (void)seq_id;
73  (void)mt;
74  #else
75  #if KINETIC_LOGGER_LOG_SEQUENCE_ID
76  struct timeval tv;
77  gettimeofday(&tv, NULL);
78  LOGF2("SEQ_ID request fd %d seq_id %lld %08lld.%08lld cmd %02x",
79  fd, (long long)seq_id,
80  (long long)tv.tv_sec, (long long)tv.tv_usec, (uint8_t)mt);
81  #else
82  (void)seq_id;
83  (void)mt;
84  #endif
85  #endif
86 }
87 
88 /* Send request.
89  * Note: This whole function operates with op->session->sendMutex locked. */
90 static KineticStatus send_request_in_lock(KineticOperation* const op)
91 {
92  LOGF3("\nSending PDU via fd=%d", op->session->socket);
93  KineticRequest* request = op->request;
94 
95  int64_t seq_id = KineticSession_GetNextSequenceCount(op->session);
96  KINETIC_ASSERT(request->message.header.sequence == KINETIC_SEQUENCE_NOT_YET_BOUND);
97  request->message.header.sequence = seq_id;
98 
99  size_t expectedLen = KineticRequest_PackCommand(request);
100  if (expectedLen == KINETIC_REQUEST_PACK_FAILURE) {
102  }
103  uint8_t * commandData = request->message.message.commandbytes.data;
104 
105  log_request_seq_id(op->session->socket, seq_id, request->message.header.messagetype);
106 
107  KineticSession *session = op->session;
108  KineticStatus status = KineticRequest_PopulateAuthentication(&session->config,
109  op->request, op->pin);
110  if (status != KINETIC_STATUS_SUCCESS) {
111  if (commandData) { free(commandData); }
112  return status;
113  }
114 
115  #ifndef TEST
116  uint8_t * msg = NULL;
117  size_t msgSize = 0;
118  #endif
119  status = KineticRequest_PackMessage(op, &msg, &msgSize);
120  if (status != KINETIC_STATUS_SUCCESS) {
121  if (commandData) { free(commandData); }
122  return status;
123  }
124 
125  if (commandData) { free(commandData); }
126  KineticCountingSemaphore * const sem = op->session->outstandingOperations;
127  KineticCountingSemaphore_Take(sem); // limit total concurrent requests
128 
129  if (!KineticRequest_SendRequest(op, msg, msgSize)) {
130  LOGF0("Failed queuing request %p for transmit on fd=%d w/seq=%lld",
131  (void*)request, op->session->socket, (long long)seq_id);
132  /* A false result from bus_send_request means that the request was
133  * rejected outright, so the usual asynchronous, callback-based
134  * error handling for errors during the request or response will
135  * not be used. */
138  } else {
139  status = KINETIC_STATUS_SUCCESS;
140  }
141 
142  if (msg != NULL) { free(msg); }
143  return status;
144 }
145 
146 KineticStatus KineticOperation_GetStatus(const KineticOperation* const op)
147 {
149  if (op != NULL) {
150  status = KineticResponse_GetStatus(op->response);
151  }
152  return status;
153 }
154 
155 void KineticOperation_Complete(KineticOperation* op, KineticStatus status)
156 {
157  KINETIC_ASSERT(op);
158  KINETIC_ASSERT(op->session);
159 
160  // ExecuteOperation should ensure a callback exists (either a user supplied one, or the a default)
161  KineticCompletionData completionData = {.status = status};
162 
163  // Release this request so that others can be unblocked if at max (request PDUs throttled)
164  KineticCountingSemaphore_Give(op->session->outstandingOperations);
165 
166  if(op->closure.callback != NULL) {
167  op->closure.callback(&completionData, op->closure.clientData);
168  }
169 
171 }
KineticStatus KineticRequest_PackMessage(KineticOperation *operation, uint8_t **out_msg, size_t *msgSize)
KineticStatus KineticRequest_PopulateAuthentication(KineticSessionConfig *config, KineticRequest *request, ByteArray *pin)
Operation successful.
No request was attempted.
void KineticAllocator_FreeOperation(KineticOperation *operation)
static void log_request_seq_id(int fd, int64_t seq_id, KineticMessageType mt)
static KineticStatus send_request_in_lock(KineticOperation *const op)
#define KINETIC_SEQUENCE_NOT_YET_BOUND
KineticStatus KineticResponse_GetStatus(KineticResponse *response)
size_t KineticRequest_PackCommand(KineticRequest *request)
Failed allocating/deallocating memory.
void KineticCountingSemaphore_Take(KineticCountingSemaphore *const sem)
void KineticCountingSemaphore_Give(KineticCountingSemaphore *const sem)
void KineticOperation_ValidateOperation(KineticOperation *op)
bool KineticRequest_LockSend(KineticSession *session)
KineticStatus KineticOperation_GetStatus(const KineticOperation *const op)
void KineticOperation_Complete(KineticOperation *op, KineticStatus status)
#define KINETIC_ASSERT(cond)
No connection/disconnected.
Completion data which will be provided to KineticCompletionClosure for asynchronous operations...
#define LOGF3(message,...)
int64_t KineticSession_GetNextSequenceCount(KineticSession *const session)
#define LOGF0(message,...)
KineticStatus status
Resultant status of the operation.
Status not available (no reponse/status available)
KineticStatus
Kinetic status codes.
KineticMessageType
Log info message types.
#define KINETIC_REQUEST_PACK_FAILURE
KineticStatus KineticOperation_SendRequest(KineticOperation *const op)
bool KineticRequest_SendRequest(KineticOperation *operation, uint8_t *msg, size_t msgSize)
bool KineticRequest_UnlockSend(KineticSession *session)
#define LOGF2(message,...)