diff --git a/Makefile.am b/Makefile.am index 9c07405..5ef88d1 100644 --- a/Makefile.am +++ b/Makefile.am @@ -25,7 +25,7 @@ dist_noinst_DATA = lib/libiscsi.syms lib_LTLIBRARIES = lib/libiscsi.la lib_libiscsi_la_SOURCES = \ lib/connect.c lib/crc32c.c lib/discovery.c lib/init.c \ - lib/login.c lib/md5.c lib/nop.c lib/pdu.c lib/scsi-command.c \ + lib/login.c lib/md5.c lib/nop.c lib/pdu.c lib/iscsi-command.c \ lib/scsi-lowlevel.c lib/socket.c lib/sync.c lib/task_mgmt.c \ lib/logging.c diff --git a/include/iscsi-private.h b/include/iscsi-private.h index b34a184..48b757a 100644 --- a/include/iscsi-private.h +++ b/include/iscsi-private.h @@ -18,6 +18,7 @@ #define __iscsi_private_h__ #include +#include #if defined(WIN32) #include @@ -48,8 +49,8 @@ struct iscsi_in_pdu { long long data_pos; unsigned char *data; }; -void iscsi_free_iscsi_in_pdu(struct iscsi_in_pdu *in); -void iscsi_free_iscsi_inqueue(struct iscsi_in_pdu *inqueue); +void iscsi_free_iscsi_in_pdu(struct iscsi_context *iscsi, struct iscsi_in_pdu *in); +void iscsi_free_iscsi_inqueue(struct iscsi_context *iscsi, struct iscsi_in_pdu *inqueue); enum iscsi_initial_r2t { ISCSI_INITIAL_R2T_NO = 0, @@ -68,6 +69,7 @@ struct iscsi_context { char connected_portal[MAX_STRING_SIZE+1]; char portal[MAX_STRING_SIZE+1]; char alias[MAX_STRING_SIZE+1]; + char bind_interfaces[MAX_STRING_SIZE+1]; char user[MAX_STRING_SIZE+1]; char passwd[MAX_STRING_SIZE+1]; @@ -102,6 +104,7 @@ struct iscsi_context { int login_attempts; int is_loggedin; int is_reconnecting; + int bind_interfaces_cnt; int chap_a; int chap_i; @@ -127,9 +130,15 @@ struct iscsi_context { int lun; int no_auto_reconnect; int reconnect_deferred; - + int log_level; iscsi_log_fn log_fn; + + int mallocs; + int reallocs; + int frees; + + time_t last_reconnect; }; #define ISCSI_PDU_IMMEDIATE 0x40 @@ -210,16 +219,26 @@ struct iscsi_pdu { struct iscsi_scsi_cbdata *scsi_cbdata; }; -void iscsi_free_scsi_cbdata(struct iscsi_scsi_cbdata *scsi_cbdata); +void iscsi_free_scsi_cbdata(struct iscsi_context *iscsi, struct iscsi_scsi_cbdata *scsi_cbdata); struct iscsi_pdu *iscsi_allocate_pdu(struct iscsi_context *iscsi, enum iscsi_opcode opcode, enum iscsi_opcode response_opcode); +struct iscsi_pdu *iscsi_allocate_pdu_size(struct iscsi_context *iscsi, + enum iscsi_opcode opcode, + enum iscsi_opcode response_opcode, + size_t payload_size); struct iscsi_pdu *iscsi_allocate_pdu_with_itt_flags(struct iscsi_context *iscsi, enum iscsi_opcode opcode, enum iscsi_opcode response_opcode, uint32_t itt, uint32_t flags); +struct iscsi_pdu *iscsi_allocate_pdu_with_itt_flags_size(struct iscsi_context *iscsi, + enum iscsi_opcode opcode, + enum iscsi_opcode response_opcode, + uint32_t itt, + uint32_t flags, + size_t payload_size); void iscsi_free_pdu(struct iscsi_context *iscsi, struct iscsi_pdu *pdu); void iscsi_pdu_set_pduflags(struct iscsi_pdu *pdu, unsigned char flags); void iscsi_pdu_set_immediate(struct iscsi_pdu *pdu); @@ -279,6 +298,11 @@ void iscsi_set_error(struct iscsi_context *iscsi, const char *error_string, unsigned char *iscsi_get_user_in_buffer(struct iscsi_context *iscsi, struct iscsi_in_pdu *in, uint32_t pos, ssize_t *count); unsigned char *scsi_task_get_data_in_buffer(struct scsi_task *task, uint32_t pos, ssize_t *count); +inline void* iscsi_malloc(struct iscsi_context *iscsi, size_t size); +inline void* iscsi_zmalloc(struct iscsi_context *iscsi, size_t size); +inline void* iscsi_realloc(struct iscsi_context *iscsi, void* ptr, size_t size); +inline void iscsi_free(struct iscsi_context *iscsi, void* ptr); +inline char* iscsi_strdup(struct iscsi_context *iscsi, const char* str); unsigned long crc32c(char *buf, int len); @@ -286,6 +310,8 @@ struct scsi_task *iscsi_scsi_get_task_from_pdu(struct iscsi_pdu *pdu); void iscsi_set_noautoreconnect(struct iscsi_context *iscsi, int state); +void iscsi_decrement_iface_rr(void); + #define ISCSI_LOG(iscsi, level, format, args...) \ do { \ if (level <= iscsi->log_level && iscsi->log_fn) { \ diff --git a/include/iscsi.h b/include/iscsi.h index 463f6a3..5ee61c2 100644 --- a/include/iscsi.h +++ b/include/iscsi.h @@ -77,6 +77,7 @@ struct iscsi_url { char user[MAX_STRING_SIZE+1]; char passwd[MAX_STRING_SIZE+1]; int lun; + struct iscsi_context *iscsi; }; /* @@ -532,6 +533,7 @@ iscsi_task_mgmt_target_cold_reset_async(struct iscsi_context *iscsi, struct iscsi_data { int size; + size_t alloc_size; unsigned char *data; }; @@ -1023,6 +1025,13 @@ iscsi_set_tcp_keepintvl(struct iscsi_context *iscsi, int value); EXTERN void iscsi_set_tcp_syncnt(struct iscsi_context *iscsi, int value); +/* + * This function is to set the interface that outbound connections for this socket are bound to. + * You max specify more than one interface here separated by comma. + */ +EXTERN void +iscsi_set_bind_interfaces(struct iscsi_context *iscsi, char * interfaces); + #ifdef __cplusplus } #endif diff --git a/include/scsi-lowlevel.h b/include/scsi-lowlevel.h index d3d7712..38787c1 100644 --- a/include/scsi-lowlevel.h +++ b/include/scsi-lowlevel.h @@ -839,4 +839,3 @@ void *scsi_malloc(struct scsi_task *task, size_t size); #endif #endif /* __scsi_lowlevel_h__ */ - diff --git a/lib/connect.c b/lib/connect.c index c43a7c6..95ce601 100644 --- a/lib/connect.c +++ b/lib/connect.c @@ -61,7 +61,7 @@ iscsi_testunitready_cb(struct iscsi_context *iscsi, int status, "failed."); ct->cb(iscsi, SCSI_STATUS_ERROR, NULL, ct->private_data); - free(ct); + iscsi_free(iscsi, ct); } scsi_free_scsi_task(task); return; @@ -80,7 +80,7 @@ iscsi_testunitready_cb(struct iscsi_context *iscsi, int status, ct->cb(iscsi, status?SCSI_STATUS_ERROR:SCSI_STATUS_GOOD, NULL, ct->private_data); scsi_free_scsi_task(task); - free(ct); + iscsi_free(iscsi, ct); } static void @@ -91,8 +91,9 @@ iscsi_login_cb(struct iscsi_context *iscsi, int status, void *command_data _U_, if (status == SCSI_STATUS_REDIRECT && iscsi->target_address[0]) { iscsi_disconnect(iscsi); + if (iscsi->bind_interfaces[0]) iscsi_decrement_iface_rr(); if (iscsi_connect_async(iscsi, iscsi->target_address, iscsi_connect_cb, iscsi->connect_data) != 0) { - free(ct); + iscsi_free(iscsi, ct); return; } return; @@ -100,7 +101,7 @@ iscsi_login_cb(struct iscsi_context *iscsi, int status, void *command_data _U_, if (status != 0) { ct->cb(iscsi, SCSI_STATUS_ERROR, NULL, ct->private_data); - free(ct); + iscsi_free(iscsi, ct); return; } @@ -121,14 +122,14 @@ iscsi_connect_cb(struct iscsi_context *iscsi, int status, void *command_data _U_ iscsi_set_error(iscsi, "Failed to connect to iSCSI socket. " "%s", iscsi_get_error(iscsi)); ct->cb(iscsi, SCSI_STATUS_ERROR, NULL, ct->private_data); - free(ct); + iscsi_free(iscsi, ct); return; } if (iscsi_login_async(iscsi, iscsi_login_cb, ct) != 0) { iscsi_set_error(iscsi, "iscsi_login_async failed."); ct->cb(iscsi, SCSI_STATUS_ERROR, NULL, ct->private_data); - free(ct); + iscsi_free(iscsi, ct); } } @@ -140,9 +141,10 @@ iscsi_full_connect_async(struct iscsi_context *iscsi, const char *portal, struct connect_task *ct; iscsi->lun = lun; - strncpy(iscsi->portal,portal,MAX_STRING_SIZE); + if (iscsi->portal != portal) + strncpy(iscsi->portal,portal,MAX_STRING_SIZE); - ct = malloc(sizeof(struct connect_task)); + ct = iscsi_malloc(iscsi, sizeof(struct connect_task)); if (ct == NULL) { iscsi_set_error(iscsi, "Out-of-memory. Failed to allocate " "connect_task structure."); @@ -218,6 +220,10 @@ int iscsi_reconnect(struct iscsi_context *old_iscsi) int retry = 0; + if (old_iscsi->last_reconnect) { + while (time(NULL) - old_iscsi->last_reconnect < 5) sleep(1); + } + try_again: iscsi = iscsi_create_context(old_iscsi->initiator_name); @@ -235,7 +241,10 @@ try_again: iscsi->lun = old_iscsi->lun; - strncpy(iscsi->portal,old_iscsi->portal, MAX_STRING_SIZE); + strncpy(iscsi->portal,old_iscsi->portal,MAX_STRING_SIZE); + + strncpy(iscsi->bind_interfaces,old_iscsi->bind_interfaces,MAX_STRING_SIZE); + iscsi->bind_interfaces_cnt = old_iscsi->bind_interfaces_cnt; iscsi->log_level = old_iscsi->log_level; iscsi->log_fn = old_iscsi->log_fn; @@ -318,18 +327,23 @@ try_again: } if (old_iscsi->incoming != NULL) { - iscsi_free_iscsi_in_pdu(old_iscsi->incoming); + iscsi_free_iscsi_in_pdu(old_iscsi, old_iscsi->incoming); } if (old_iscsi->inqueue != NULL) { - iscsi_free_iscsi_inqueue(old_iscsi->inqueue); + iscsi_free_iscsi_inqueue(old_iscsi, old_iscsi->inqueue); } close(iscsi->fd); iscsi->fd = old_iscsi->fd; + iscsi->mallocs+=old_iscsi->mallocs; + iscsi->frees+=old_iscsi->frees; + memcpy(old_iscsi, iscsi, sizeof(struct iscsi_context)); + memset(iscsi, 0, sizeof(struct iscsi_context)); free(iscsi); old_iscsi->is_reconnecting = 0; + old_iscsi->last_reconnect = time(NULL); return 0; } diff --git a/lib/discovery.c b/lib/discovery.c index f474ae7..1ddf8ef 100644 --- a/lib/discovery.c +++ b/lib/discovery.c @@ -79,19 +79,19 @@ iscsi_discovery_async(struct iscsi_context *iscsi, iscsi_command_cb cb, } static void -iscsi_free_discovery_addresses(struct iscsi_discovery_address *addresses) +iscsi_free_discovery_addresses(struct iscsi_context *iscsi, struct iscsi_discovery_address *addresses) { while (addresses != NULL) { struct iscsi_discovery_address *next = addresses->next; - free(discard_const(addresses->target_name)); + iscsi_free(iscsi, discard_const(addresses->target_name)); addresses->target_name = NULL; - free(discard_const(addresses->target_address)); + iscsi_free(iscsi, discard_const(addresses->target_address)); addresses->target_address = NULL; addresses->next = NULL; - free(addresses); + iscsi_free(iscsi, addresses); addresses = next; } } @@ -127,7 +127,7 @@ iscsi_process_text_reply(struct iscsi_context *iscsi, struct iscsi_pdu *pdu, "discovery data %d>%d", len, size); pdu->callback(iscsi, SCSI_STATUS_ERROR, NULL, pdu->private_data); - iscsi_free_discovery_addresses(targets); + iscsi_free_discovery_addresses(iscsi, targets); return -1; } @@ -135,40 +135,39 @@ iscsi_process_text_reply(struct iscsi_context *iscsi, struct iscsi_pdu *pdu, if (!strncmp((char *)ptr, "TargetName=", 11)) { struct iscsi_discovery_address *target; - target = malloc(sizeof(struct iscsi_discovery_address)); + target = iscsi_zmalloc(iscsi, sizeof(struct iscsi_discovery_address)); if (target == NULL) { iscsi_set_error(iscsi, "Failed to allocate " "data for new discovered " "target"); pdu->callback(iscsi, SCSI_STATUS_ERROR, NULL, pdu->private_data); - iscsi_free_discovery_addresses(targets); + iscsi_free_discovery_addresses(iscsi, targets); return -1; } - memset(target, 0, sizeof(struct iscsi_discovery_address)); - target->target_name = strdup((char *)ptr+11); + target->target_name = iscsi_strdup(iscsi,(char *)ptr+11); if (target->target_name == NULL) { iscsi_set_error(iscsi, "Failed to allocate " "data for new discovered " "target name"); pdu->callback(iscsi, SCSI_STATUS_ERROR, NULL, pdu->private_data); - free(target); + iscsi_free(iscsi, target); target = NULL; - iscsi_free_discovery_addresses(targets); + iscsi_free_discovery_addresses(iscsi, targets); return -1; } target->next = targets; targets = target; } else if (!strncmp((char *)ptr, "TargetAddress=", 14)) { - targets->target_address = strdup((char *)ptr+14); + targets->target_address = iscsi_strdup(iscsi, (char *)ptr+14); if (targets->target_address == NULL) { iscsi_set_error(iscsi, "Failed to allocate " "data for new discovered " "target address"); pdu->callback(iscsi, SCSI_STATUS_ERROR, NULL, pdu->private_data); - iscsi_free_discovery_addresses(targets); + iscsi_free_discovery_addresses(iscsi, targets); return -1; } } else { @@ -176,7 +175,7 @@ iscsi_process_text_reply(struct iscsi_context *iscsi, struct iscsi_pdu *pdu, "discovery string : %s", ptr); pdu->callback(iscsi, SCSI_STATUS_ERROR, NULL, pdu->private_data); - iscsi_free_discovery_addresses(targets); + iscsi_free_discovery_addresses(iscsi, targets); return -1; } @@ -185,7 +184,7 @@ iscsi_process_text_reply(struct iscsi_context *iscsi, struct iscsi_pdu *pdu, } pdu->callback(iscsi, SCSI_STATUS_GOOD, targets, pdu->private_data); - iscsi_free_discovery_addresses(targets); + iscsi_free_discovery_addresses(iscsi, targets); return 0; } diff --git a/lib/init.c b/lib/init.c index e3b33c8..74fab0a 100644 --- a/lib/init.c +++ b/lib/init.c @@ -33,25 +33,62 @@ #include "iscsi-private.h" #include "slist.h" +inline void* iscsi_malloc(struct iscsi_context *iscsi, size_t size) { + void * ptr = malloc(size); + if (ptr != NULL) iscsi->mallocs++; + return ptr; +} + +inline void* iscsi_zmalloc(struct iscsi_context *iscsi, size_t size) { + void * ptr = malloc(size); + if (ptr != NULL) { + memset(ptr,0x00,size); + iscsi->mallocs++; + } + return ptr; +} + +inline void* iscsi_realloc(struct iscsi_context *iscsi, void* ptr, size_t size) { + void * _ptr = realloc(ptr, size); + if (_ptr != NULL) { + iscsi->reallocs++; + } + return _ptr; +} + +inline void iscsi_free(struct iscsi_context *iscsi, void* ptr) { + if (ptr == NULL) return; + free(ptr); + iscsi->frees++; +} + +inline char* iscsi_strdup(struct iscsi_context *iscsi, const char* str) { + char *str2 = strdup(str); + if (str2 != NULL) iscsi->mallocs++; + return str2; +} + struct iscsi_context * iscsi_create_context(const char *initiator_name) { struct iscsi_context *iscsi; + if (!initiator_name[0]) { + return NULL; + } + iscsi = malloc(sizeof(struct iscsi_context)); if (iscsi == NULL) { return NULL; } - + memset(iscsi, 0, sizeof(struct iscsi_context)); strncpy(iscsi->initiator_name,initiator_name,MAX_STRING_SIZE); - if (!iscsi->initiator_name[0]) { - free(iscsi); - return NULL; - } iscsi->fd = -1; + + srand(time(NULL) ^ getpid() ^ (u_int32_t) ((uintptr_t) iscsi)); /* initialize to a "random" isid */ iscsi_set_isid_random(iscsi, rand(), 0); @@ -100,6 +137,10 @@ iscsi_create_context(const char *initiator_name) iscsi_set_tcp_syncnt(iscsi,atoi(getenv("LIBISCSI_TCP_SYNCNT"))); } + if (getenv("LIBISCSI_BIND_INTERFACES") != NULL) { + iscsi_set_bind_interfaces(iscsi,getenv("LIBISCSI_BIND_INTERFACES")); + } + return iscsi; } @@ -227,14 +268,21 @@ iscsi_destroy_context(struct iscsi_context *iscsi) } if (iscsi->incoming != NULL) { - iscsi_free_iscsi_in_pdu(iscsi->incoming); + iscsi_free_iscsi_in_pdu(iscsi, iscsi->incoming); } if (iscsi->inqueue != NULL) { - iscsi_free_iscsi_inqueue(iscsi->inqueue); + iscsi_free_iscsi_inqueue(iscsi, iscsi->inqueue); } iscsi->connect_data = NULL; + if (iscsi->mallocs != iscsi->frees) { + ISCSI_LOG(iscsi,1,"%d memory blocks lost at iscsi_destroy_context() after %d malloc(s), %d realloc(s) and %d free(s)",iscsi->mallocs-iscsi->frees,iscsi->mallocs,iscsi->reallocs,iscsi->frees); + } else { + ISCSI_LOG(iscsi,5,"memory is clean at iscsi_destroy_context() after %d mallocs, %d realloc(s) and %d frees",iscsi->mallocs,iscsi->reallocs,iscsi->frees); + } + + memset(iscsi, 0, sizeof(struct iscsi_context)); free(iscsi); return 0; @@ -393,13 +441,18 @@ iscsi_parse_url(struct iscsi_context *iscsi, const char *url, int full) tmp=strchr(portal,'/'); if (tmp) *tmp=0; } - - iscsi_url = malloc(sizeof(struct iscsi_url)); + + if (iscsi != NULL) + iscsi_url = iscsi_malloc(iscsi, sizeof(struct iscsi_url)); + else + iscsi_url = malloc(sizeof(struct iscsi_url)); + if (iscsi_url == NULL) { iscsi_set_error(iscsi, "Out-of-memory: Failed to allocate iscsi_url structure"); return NULL; } memset(iscsi_url, 0, sizeof(struct iscsi_url)); + iscsi_url->iscsi= iscsi; strncpy(iscsi_url->portal,portal,MAX_STRING_SIZE); @@ -431,7 +484,12 @@ iscsi_parse_portal_url(struct iscsi_context *iscsi, const char *url) void iscsi_destroy_url(struct iscsi_url *iscsi_url) { - free(iscsi_url); + struct iscsi_context *iscsi = iscsi_url->iscsi; + memset(iscsi_url, 0, sizeof(struct iscsi_url)); + if (iscsi != NULL) + iscsi_free(iscsi, iscsi_url); + else + free(iscsi_url); } diff --git a/lib/scsi-command.c b/lib/iscsi-command.c similarity index 99% rename from lib/scsi-command.c rename to lib/iscsi-command.c index d3b2fb9..fbbd016 100644 --- a/lib/scsi-command.c +++ b/lib/iscsi-command.c @@ -37,7 +37,7 @@ struct iscsi_scsi_cbdata { }; void -iscsi_free_scsi_cbdata(struct iscsi_scsi_cbdata *scsi_cbdata) +iscsi_free_scsi_cbdata(struct iscsi_context *iscsi, struct iscsi_scsi_cbdata *scsi_cbdata) { if (scsi_cbdata == NULL) { return; @@ -45,7 +45,7 @@ iscsi_free_scsi_cbdata(struct iscsi_scsi_cbdata *scsi_cbdata) if (scsi_cbdata->task != NULL) { scsi_cbdata->task = NULL; } - free(scsi_cbdata); + iscsi_free(iscsi, scsi_cbdata); } static void @@ -186,13 +186,13 @@ iscsi_scsi_command_async(struct iscsi_context *iscsi, int lun, return -1; } - scsi_cbdata = malloc(sizeof(struct iscsi_scsi_cbdata)); + scsi_cbdata = iscsi_zmalloc(iscsi, sizeof(struct iscsi_scsi_cbdata)); if (scsi_cbdata == NULL) { iscsi_set_error(iscsi, "Out-of-memory: failed to allocate " "scsi cbdata."); return -1; } - memset(scsi_cbdata, 0, sizeof(struct iscsi_scsi_cbdata)); + scsi_cbdata->task = task; scsi_cbdata->callback = cb; scsi_cbdata->private_data = private_data; @@ -204,7 +204,7 @@ iscsi_scsi_command_async(struct iscsi_context *iscsi, int lun, if (pdu == NULL) { iscsi_set_error(iscsi, "Out-of-memory, Failed to allocate " "scsi pdu."); - iscsi_free_scsi_cbdata(scsi_cbdata); + iscsi_free_scsi_cbdata(iscsi, scsi_cbdata); return -1; } pdu->scsi_cbdata = scsi_cbdata; diff --git a/lib/libiscsi.def b/lib/libiscsi.def index 6482822..ac8cb11 100644 --- a/lib/libiscsi.def +++ b/lib/libiscsi.def @@ -81,6 +81,7 @@ iscsi_set_tcp_keepidle iscsi_set_tcp_keepcnt iscsi_set_tcp_keepintvl iscsi_set_tcp_syncnt +iscsi_set_bind_interface iscsi_startstopunit_sync iscsi_startstopunit_task iscsi_synchronizecache10_sync diff --git a/lib/libiscsi.syms b/lib/libiscsi.syms index 68d5605..ebcbb56 100644 --- a/lib/libiscsi.syms +++ b/lib/libiscsi.syms @@ -79,6 +79,7 @@ iscsi_set_tcp_keepidle iscsi_set_tcp_keepcnt iscsi_set_tcp_keepintvl iscsi_set_tcp_syncnt +iscsi_set_bind_interface iscsi_startstopunit_sync iscsi_startstopunit_task iscsi_synchronizecache10_sync diff --git a/lib/login.c b/lib/login.c index f37ddc0..6126f4f 100644 --- a/lib/login.c +++ b/lib/login.c @@ -705,10 +705,10 @@ iscsi_login_async(struct iscsi_context *iscsi, iscsi_command_cb cb, return -1; } - pdu = iscsi_allocate_pdu_with_itt_flags(iscsi, + pdu = iscsi_allocate_pdu_with_itt_flags_size(iscsi, ISCSI_PDU_LOGIN_REQUEST, ISCSI_PDU_LOGIN_RESPONSE, - iscsi->itt, 0); + iscsi->itt, 0, 1024); if (pdu == NULL) { iscsi_set_error(iscsi, "Out-of-memory: Failed to allocate " "login pdu."); diff --git a/lib/pdu.c b/lib/pdu.c index f9cbf80..d8d1684 100644 --- a/lib/pdu.c +++ b/lib/pdu.c @@ -31,27 +31,28 @@ #include "slist.h" struct iscsi_pdu * -iscsi_allocate_pdu_with_itt_flags(struct iscsi_context *iscsi, enum iscsi_opcode opcode, - enum iscsi_opcode response_opcode, uint32_t itt, uint32_t flags) +iscsi_allocate_pdu_with_itt_flags_size(struct iscsi_context *iscsi, enum iscsi_opcode opcode, + enum iscsi_opcode response_opcode, uint32_t itt, uint32_t flags, size_t payload_size) { struct iscsi_pdu *pdu; - pdu = malloc(sizeof(struct iscsi_pdu)); + pdu = iscsi_zmalloc(iscsi, sizeof(struct iscsi_pdu)); if (pdu == NULL) { iscsi_set_error(iscsi, "failed to allocate pdu"); return NULL; } - memset(pdu, 0, sizeof(struct iscsi_pdu)); pdu->outdata.size = ISCSI_HEADER_SIZE; - pdu->outdata.data = malloc(pdu->outdata.size); + pdu->outdata.alloc_size = 64; + while (pdu->outdata.alloc_size < ISCSI_HEADER_SIZE+payload_size) pdu->outdata.alloc_size<<=1; + pdu->outdata.data = iscsi_malloc(iscsi, pdu->outdata.alloc_size); + memset(pdu->outdata.data, 0, ISCSI_HEADER_SIZE); if (pdu->outdata.data == NULL) { iscsi_set_error(iscsi, "failed to allocate pdu header"); - free(pdu); + iscsi_free(iscsi, pdu); return NULL; } - memset(pdu->outdata.data, 0, pdu->outdata.size); /* opcode */ pdu->outdata.data[0] = opcode; @@ -72,6 +73,13 @@ iscsi_allocate_pdu_with_itt_flags(struct iscsi_context *iscsi, enum iscsi_opcode return pdu; } +struct iscsi_pdu * +iscsi_allocate_pdu_with_itt_flags(struct iscsi_context *iscsi, enum iscsi_opcode opcode, + enum iscsi_opcode response_opcode, uint32_t itt, uint32_t flags) +{ + return iscsi_allocate_pdu_with_itt_flags_size(iscsi, opcode, response_opcode, itt, flags, 0); +} + struct iscsi_pdu * iscsi_allocate_pdu(struct iscsi_context *iscsi, enum iscsi_opcode opcode, enum iscsi_opcode response_opcode) @@ -79,6 +87,13 @@ iscsi_allocate_pdu(struct iscsi_context *iscsi, enum iscsi_opcode opcode, return iscsi_allocate_pdu_with_itt_flags(iscsi, opcode, response_opcode, iscsi->itt++, 0); } +struct iscsi_pdu * +iscsi_allocate_pdu_size(struct iscsi_context *iscsi, enum iscsi_opcode opcode, + enum iscsi_opcode response_opcode, size_t payload_size) +{ + return iscsi_allocate_pdu_with_itt_flags_size(iscsi, opcode, response_opcode, iscsi->itt++, 0, payload_size); +} + void @@ -89,18 +104,18 @@ iscsi_free_pdu(struct iscsi_context *iscsi, struct iscsi_pdu *pdu) return; } - free(pdu->outdata.data); + iscsi_free(iscsi, pdu->outdata.data); pdu->outdata.data = NULL; - free(pdu->indata.data); + iscsi_free(iscsi, pdu->indata.data); pdu->indata.data = NULL; if (pdu->scsi_cbdata) { - iscsi_free_scsi_cbdata(pdu->scsi_cbdata); + iscsi_free_scsi_cbdata(iscsi, pdu->scsi_cbdata); pdu->scsi_cbdata = NULL; } - free(pdu); + iscsi_free(iscsi, pdu); } @@ -108,8 +123,7 @@ int iscsi_add_data(struct iscsi_context *iscsi, struct iscsi_data *data, unsigned char *dptr, int dsize, int pdualignment) { - int len, aligned; - unsigned char *buf; + size_t len, aligned; if (dsize == 0) { iscsi_set_error(iscsi, "Trying to append zero size data to " @@ -122,25 +136,36 @@ iscsi_add_data(struct iscsi_context *iscsi, struct iscsi_data *data, if (pdualignment) { aligned = (aligned+3)&0xfffffffc; } - buf = malloc(aligned); - if (buf == NULL) { + + size_t new_alloc_size = data->alloc_size; + if (new_alloc_size < 64) new_alloc_size=64; + + while (aligned > new_alloc_size) new_alloc_size<<=1; + + if (data->data != NULL && data->alloc_size == 0) data->alloc_size=data->size; + + if (data->alloc_size == 0) { + data->data = iscsi_malloc(iscsi, new_alloc_size); + } + else + if (data->alloc_size != new_alloc_size) { + data->data = iscsi_realloc(iscsi, data->data, new_alloc_size); + } + + if (data->data == NULL) { iscsi_set_error(iscsi, "failed to allocate buffer for %d " - "bytes", len); + "bytes", (int) len); return -1; } + + data->alloc_size = new_alloc_size; + memcpy(data->data + data->size, dptr, dsize); - if (data->size > 0) { - memcpy(buf, data->data, data->size); - } - memcpy(buf + data->size, dptr, dsize); if (len != aligned) { /* zero out any padding at the end */ - memset(buf+len, 0, aligned-len); + memset(data->data+len, 0, aligned-len); } - free(data->data); - - data->data = buf; data->size = len; return 0; diff --git a/lib/socket.c b/lib/socket.c index b0274d4..79034e6 100644 --- a/lib/socket.c +++ b/lib/socket.c @@ -46,6 +46,12 @@ #include "iscsi-private.h" #include "slist.h" +static uint32_t iface_rr = 0; + +void iscsi_decrement_iface_rr() { + iface_rr--; +} + static void set_nonblocking(int fd) { #if defined(WIN32) @@ -122,7 +128,7 @@ iscsi_connect_async(struct iscsi_context *iscsi, const char *portal, return -1; } - addr = strdup(portal); + addr = iscsi_strdup(iscsi, portal); if (addr == NULL) { iscsi_set_error(iscsi, "Out-of-memory: " "Failed to strdup portal address."); @@ -151,7 +157,7 @@ iscsi_connect_async(struct iscsi_context *iscsi, const char *portal, host ++; str = strchr(host, ']'); if (str == NULL) { - free(addr); + iscsi_free(iscsi, addr); iscsi_set_error(iscsi, "Invalid target:%s " "Missing ']' in IPv6 address", portal); return -1; @@ -161,12 +167,12 @@ iscsi_connect_async(struct iscsi_context *iscsi, const char *portal, /* is it a hostname ? */ if (getaddrinfo(host, NULL, NULL, &ai) != 0) { - free(addr); + iscsi_free(iscsi, addr); iscsi_set_error(iscsi, "Invalid target:%s " "Can not resolv into IPv4/v6.", portal); return -1; } - free(addr); + iscsi_free(iscsi, addr); switch (ai->ai_family) { case AF_INET: @@ -216,6 +222,31 @@ iscsi_connect_async(struct iscsi_context *iscsi, const char *portal, set_tcp_syncnt(iscsi); } +#if __linux + if (iscsi->bind_interfaces[0]) { + char *pchr = iscsi->bind_interfaces, *pchr2; + int iface_n = iface_rr++%iscsi->bind_interfaces_cnt; + int iface_c = 0; + do { + pchr2 = strchr(pchr,','); + if (iface_c == iface_n) { + if (pchr2) pchr2[0]=0x00; + break; + } + if (pchr2) {pchr=pchr2+1;} + iface_c++; + } while (pchr2); + + int res = setsockopt(iscsi->fd, SOL_SOCKET, SO_BINDTODEVICE, pchr, strlen(pchr)); + if (res < 0) { + ISCSI_LOG(iscsi,1,"failed to bind to interface '%s': %s",pchr,strerror(errno)); + } else { + ISCSI_LOG(iscsi,3,"successfully bound to interface '%s'",pchr); + } + if (pchr2) pchr2[0]=','; + } +#endif + if (connect(iscsi->fd, ai->ai_addr, socksize) != 0 && errno != EINPROGRESS) { iscsi_set_error(iscsi, "Connect failed with errno : " @@ -297,12 +328,11 @@ iscsi_read_from_socket(struct iscsi_context *iscsi) ssize_t data_size, count; if (iscsi->incoming == NULL) { - iscsi->incoming = malloc(sizeof(struct iscsi_in_pdu)); + iscsi->incoming = iscsi_zmalloc(iscsi, sizeof(struct iscsi_in_pdu)); if (iscsi->incoming == NULL) { iscsi_set_error(iscsi, "Out-of-memory: failed to malloc iscsi_in_pdu"); return -1; } - memset(iscsi->incoming, 0, sizeof(struct iscsi_in_pdu)); } in = iscsi->incoming; @@ -347,7 +377,7 @@ iscsi_read_from_socket(struct iscsi_context *iscsi) /* if not, allocate one */ if (buf == NULL) { if (in->data == NULL) { - in->data = malloc(data_size); + in->data = iscsi_malloc(iscsi, data_size); if (in->data == NULL) { iscsi_set_error(iscsi, "Out-of-memory: failed to malloc iscsi_in_pdu->data(%d)", (int)data_size); return -1; @@ -386,7 +416,7 @@ iscsi_read_from_socket(struct iscsi_context *iscsi) return -1; } SLIST_REMOVE(&iscsi->inqueue, current); - iscsi_free_iscsi_in_pdu(current); + iscsi_free_iscsi_in_pdu(iscsi, current); } @@ -567,18 +597,20 @@ iscsi_queue_pdu(struct iscsi_context *iscsi, struct iscsi_pdu *pdu) } void -iscsi_free_iscsi_in_pdu(struct iscsi_in_pdu *in) +iscsi_free_iscsi_in_pdu(struct iscsi_context *iscsi, struct iscsi_in_pdu *in) { - free(in->data); - free(in); + iscsi_free(iscsi, in->data); + in->data=NULL; + iscsi_free(iscsi, in); + in=NULL; } void -iscsi_free_iscsi_inqueue(struct iscsi_in_pdu *inqueue) +iscsi_free_iscsi_inqueue(struct iscsi_context *iscsi, struct iscsi_in_pdu *inqueue) { while (inqueue != NULL) { struct iscsi_in_pdu *next = inqueue->next; - iscsi_free_iscsi_in_pdu(inqueue); + iscsi_free_iscsi_in_pdu(iscsi, inqueue); inqueue = next; } } @@ -647,3 +679,22 @@ int iscsi_set_tcp_keepalive(struct iscsi_context *iscsi, int idle, int count, in return 0; } + +void iscsi_set_bind_interfaces(struct iscsi_context *iscsi, char * interfaces) +{ +#if __linux + strncpy(iscsi->bind_interfaces,interfaces,MAX_STRING_SIZE); + iscsi->bind_interfaces_cnt=0; + char * pchr = interfaces; + char * pchr2 = NULL; + do { + pchr2 = strchr(pchr,','); + if (pchr2) {pchr=pchr2+1;} + iscsi->bind_interfaces_cnt++; + } while (pchr2); + ISCSI_LOG(iscsi,2,"will bind to one of the following %d interface(s) on next socket creation: %s",iscsi->bind_interfaces_cnt,interfaces); + if (!iface_rr) iface_rr=rand()%iscsi->bind_interfaces_cnt+1; +#else + ISCSI_LOG(iscsi,1,"binding to an interface is not supported on your OS"); +#endif +} diff --git a/win32/vsbuild.bat b/win32/vsbuild.bat index c16b6ea..0e48de0 100644 --- a/win32/vsbuild.bat +++ b/win32/vsbuild.bat @@ -14,7 +14,7 @@ cl /I. /Iinclude -Zi -Od -c -D_U_="" -DWIN32 -D_WIN32_WINNT=0x0600 -MDd lib\logi cl /I. /Iinclude -Zi -Od -c -D_U_="" -DWIN32 -D_WIN32_WINNT=0x0600 -MDd lib\md5.c -Folib\md5.obj cl /I. /Iinclude -Zi -Od -c -D_U_="" -DWIN32 -D_WIN32_WINNT=0x0600 -MDd lib\nop.c -Folib\nop.obj cl /I. /Iinclude -Zi -Od -c -D_U_="" -DWIN32 -D_WIN32_WINNT=0x0600 -MDd lib\pdu.c -Folib\pdu.obj -cl /I. /Iinclude -Zi -Od -c -D_U_="" -DWIN32 -D_WIN32_WINNT=0x0600 -MDd lib\scsi-command.c -Folib\scsi-command.obj +cl /I. /Iinclude -Zi -Od -c -D_U_="" -DWIN32 -D_WIN32_WINNT=0x0600 -MDd lib\iscsi-command.c -Folib\iscsi-command.obj cl /I. /Iinclude -Zi -Od -c -D_U_="" -DWIN32 -D_WIN32_WINNT=0x0600 -MDd lib\scsi-lowlevel.c -Folib\scsi-lowlevel.obj cl /I. /Iinclude -Zi -Od -c -D_U_="" -DWIN32 -D_WIN32_WINNT=0x0600 -MDd lib\socket.c -Folib\socket.obj cl /I. /Iinclude -Zi -Od -c -D_U_="" -DWIN32 -D_WIN32_WINNT=0x0600 -MDd lib\sync.c -Folib\sync.obj @@ -27,9 +27,9 @@ cl /I. /Iinclude -Zi -Od -c -D_U_="" -DWIN32 -D_WIN32_WINNT=0x0600 -MDd win32\wi rem rem create a linklibrary/dll rem -lib /out:lib\libiscsi.lib /def:lib\libiscsi.def lib\connect.obj lib\crc32c.obj lib\discovery.obj lib\init.obj lib\login.obj lib\md5.obj lib\nop.obj lib\pdu.obj lib\scsi-command.obj lib\scsi-lowlevel.obj lib\socket.obj lib\sync.obj lib\task_mgmt.obj lib\win32_compat.obj +lib /out:lib\libiscsi.lib /def:lib\libiscsi.def lib\connect.obj lib\crc32c.obj lib\discovery.obj lib\init.obj lib\login.obj lib\md5.obj lib\nop.obj lib\pdu.obj lib\iscsi-command.obj lib\scsi-lowlevel.obj lib\socket.obj lib\sync.obj lib\task_mgmt.obj lib\win32_compat.obj -link /DLL /out:lib\libiscsi.dll /DEBUG /DEBUGTYPE:cv lib\libiscsi.exp lib\connect.obj lib\crc32c.obj lib\discovery.obj lib\init.obj lib\login.obj lib\md5.obj lib\nop.obj lib\pdu.obj lib\scsi-command.obj lib\scsi-lowlevel.obj lib\socket.obj lib\sync.obj lib\task_mgmt.obj lib\win32_compat.obj ws2_32.lib kernel32.lib +link /DLL /out:lib\libiscsi.dll /DEBUG /DEBUGTYPE:cv lib\libiscsi.exp lib\connect.obj lib\crc32c.obj lib\discovery.obj lib\init.obj lib\login.obj lib\md5.obj lib\nop.obj lib\pdu.obj lib\iscsi-command.obj lib\scsi-lowlevel.obj lib\socket.obj lib\sync.obj lib\task_mgmt.obj lib\win32_compat.obj ws2_32.lib kernel32.lib