diff --git a/apps/sam/c/doc/whatsnew.txt b/apps/sam/c/doc/whatsnew.txt index 179058a0a..55b564fc8 100644 --- a/apps/sam/c/doc/whatsnew.txt +++ b/apps/sam/c/doc/whatsnew.txt @@ -1,4 +1,6 @@ v1.25 + * Added support for sessions - now LibSAM can have multiple SAM sessions + going at once (with different destinations) * Rewrote sendq functions to automatically send big packets, for better network performance diff --git a/apps/sam/c/inc/sam.h b/apps/sam/c/inc/sam.h index a0bd8174d..e83936302 100644 --- a/apps/sam/c/inc/sam.h +++ b/apps/sam/c/inc/sam.h @@ -77,6 +77,12 @@ typedef struct { typedef int_fast32_t sam_sid_t; /* stream id number */ +typedef struct { + socket_t sock; /* the socket used for communications with SAM */ + bool connected; /* whether the socket is connected */ + sam_sid_t prev_id; /* the last stream id number we used */ +} sam_sess_t; /* a SAM session */ + typedef enum { /* see sam_strerror() for detailed descriptions of these */ /* error codes from SAM itself (SAM_OK is not an actual "error") */ SAM_OK, SAM_CANT_REACH_PEER, SAM_DUPLICATED_DEST, SAM_I2P_ERROR, @@ -90,12 +96,17 @@ typedef enum { /* see sam_strerror() for detailed descriptions of these */ * Public functions */ -/* SAM controls */ -extern bool sam_close(); -extern samerr_t sam_connect(const char *samhost, uint16_t samport, - const char *destname, sam_conn_t style, uint_t tunneldepth); -extern void sam_naming_lookup(const char *name); -extern bool sam_read_buffer(); +/* SAM controls - sessions */ +extern sam_sess_t *sam_session_init(sam_sess_t *session); +extern void sam_session_free(sam_sess_t **session); +/* SAM controls - connection */ +extern bool sam_close(sam_sess_t *session); +extern samerr_t sam_connect(sam_sess_t *session, const char *samhost, + uint16_t samport, const char *destname, sam_conn_t style, + uint_t tunneldepth); +/* SAM controls - utilities */ +extern void sam_naming_lookup(sam_sess_t *session, const char *name); +extern bool sam_read_buffer(sam_sess_t *session); extern const char *sam_strerror(samerr_t code); /* SAM controls - callbacks */ extern void (*sam_diedback)(); @@ -104,24 +115,26 @@ extern void (*sam_namingback)(char *name, sam_pubkey_t pubkey, samerr_t result); /* Stream commands */ -extern void sam_stream_close(sam_sid_t stream_id); -extern sam_sid_t sam_stream_connect(const sam_pubkey_t dest); -extern samerr_t sam_stream_send(sam_sid_t stream_id, const void *data, - size_t size); +extern void sam_stream_close(sam_sess_t *session, sam_sid_t stream_id); +extern sam_sid_t sam_stream_connect(sam_sess_t *session, + const sam_pubkey_t dest); +extern samerr_t sam_stream_send(sam_sess_t *session, sam_sid_t stream_id, + const void *data, size_t size); /* Stream commands - callbacks */ extern void (*sam_closeback)(sam_sid_t stream_id, samerr_t reason); extern void (*sam_connectback)(sam_sid_t stream_id, sam_pubkey_t dest); extern void (*sam_databack)(sam_sid_t stream_id, void *data, size_t size); extern void (*sam_statusback)(sam_sid_t stream_id, samerr_t result); -/* Stream send queue */ -extern void sam_sendq_add(sam_sid_t stream_id, sam_sendq_t **sendq, - const void *data, size_t dsize); -extern void sam_sendq_flush(sam_sid_t stream_id, sam_sendq_t **sendq); +/* Stream send queue (experimental) */ +extern void sam_sendq_add(sam_sess_t *session, sam_sid_t stream_id, + sam_sendq_t **sendq, const void *data, size_t dsize); +extern void sam_sendq_flush(sam_sess_t *session, sam_sid_t stream_id, + sam_sendq_t **sendq); /* Datagram commands */ -extern samerr_t sam_dgram_send(const sam_pubkey_t dest, const void *data, - size_t size); +extern samerr_t sam_dgram_send(sam_sess_t *session, const sam_pubkey_t dest, + const void *data, size_t size); /* Datagram commands - callbacks */ extern void (*sam_dgramback)(sam_pubkey_t dest, void *data, size_t size); diff --git a/apps/sam/c/src/sam.c b/apps/sam/c/src/sam.c index f7d038e56..df3b0959f 100644 --- a/apps/sam/c/src/sam.c +++ b/apps/sam/c/src/sam.c @@ -31,23 +31,25 @@ #include "platform.h" #include "sam.h" -static bool sam_hello(); +static bool sam_hello(sam_sess_t *session); static void sam_log(const char *format, ...); -static void sam_parse(char *s); -static ssize_t sam_read1(char *buf, size_t n); -static ssize_t sam_read2(void *buf, size_t n); -static bool sam_readable(); +static void sam_parse(sam_sess_t *session, char *s); +static ssize_t sam_read1(sam_sess_t *session, char *buf, size_t n); +static ssize_t sam_read2(sam_sess_t *session, void *buf, size_t n); +static bool sam_readable(const sam_sess_t *session); static sam_sendq_t *sam_sendq_create(); -static samerr_t sam_session_create(const char *destname, sam_conn_t style, +static samerr_t sam_session_create(sam_sess_t *session, + const char *destname, sam_conn_t style, uint_t tunneldepth); -static bool sam_socket_connect(const char *host, uint16_t port); +static bool sam_socket_connect(sam_sess_t *session, const char *host, + uint16_t port); static bool sam_socket_resolve(const char *hostname, char *ipaddr); #ifdef WINSOCK static samerr_t sam_winsock_cleanup(); static samerr_t sam_winsock_startup(); static const char *sam_winsock_strerror(int code); #endif -static ssize_t sam_write(const void *buf, size_t n); +static ssize_t sam_write(sam_sess_t *session, const void *buf, size_t n); /* * Callback functions @@ -71,34 +73,30 @@ void (*sam_namingback)(char *name, sam_pubkey_t pubkey, /* our connection to a peer has completed */ void (*sam_statusback)(sam_sid_t stream_id, samerr_t result) = NULL; -static socket_t samd; /* The socket descriptor we're using for - communications with SAM */ -static bool samd_connected = false; /* Whether we're connected with SAM */ - /* * Closes the connection to the SAM host * * Returns: true on success, false on failure */ -bool sam_close() +bool sam_close(sam_sess_t *session) { - if (!samd_connected) + if (!session->connected) return true; #ifdef WINSOCK - if (closesocket(samd) == SOCKET_ERROR) { + if (closesocket(session->sock) == SOCKET_ERROR) { SAMLOG("Failed closing the SAM connection (%s)", sam_winsock_strerror(WSAGetLastError())); return false; } - samd_connected = false; + session->connected = false; if (sam_winsock_cleanup() == SAM_OK) return true; else return false; #else - if (close(samd) == 0) { - samd_connected = false; + if (close(session->sock) == 0) { + session->connected = false; return true; } else { SAMLOG("Failed closing the SAM connection (%s)", strerror(errno)); @@ -110,6 +108,7 @@ bool sam_close() /* * Connects to the SAM host * + * session - an unused SAM session created by sam_session_init() * samhost - SAM host * samport - SAM port * destname - destination name for this program, or "TRANSIENT" for a random @@ -117,9 +116,10 @@ bool sam_close() * tunneldepth - length of the I2P tunnels created by this program (longer is * more anonymous, but slower) * - * Returns: true on success, false on failure + * Returns: True on success, false on failure. If true, `session' will be ready + * for use. */ -samerr_t sam_connect(const char *samhost, uint16_t samport, +samerr_t sam_connect(sam_sess_t *session, const char *samhost, uint16_t samport, const char *destname, sam_conn_t style, uint_t tunneldepth) { samerr_t rc; @@ -150,7 +150,7 @@ samerr_t sam_connect(const char *samhost, uint16_t samport, return rc; #endif - if (!sam_socket_connect(samhost, samport)) { + if (!sam_socket_connect(session, samhost, samport)) { #ifdef WINSOCK SAMLOG("Couldn't connect to SAM at %s:%u (%s)", samhost, samport, sam_winsock_strerror(WSAGetLastError())); @@ -162,10 +162,10 @@ samerr_t sam_connect(const char *samhost, uint16_t samport, return SAM_SOCKET_ERROR; } - if (!sam_hello()) + if (!sam_hello(session)) return SAM_BAD_VERSION; - rc = sam_session_create(destname, style, tunneldepth); + rc = sam_session_create(session, destname, style, tunneldepth); if (rc != SAM_OK) return rc; @@ -182,7 +182,8 @@ samerr_t sam_connect(const char *samhost, uint16_t samport, * * Returns: true on success, false on failure */ -samerr_t sam_dgram_send(const sam_pubkey_t dest, const void *data, size_t size) +samerr_t sam_dgram_send(sam_sess_t *session, const sam_pubkey_t dest, + const void *data, size_t size) { char cmd[SAM_PKCMD_LEN]; @@ -201,8 +202,8 @@ samerr_t sam_dgram_send(const sam_pubkey_t dest, const void *data, size_t size) snprintf(cmd, sizeof cmd, "DATAGRAM SEND DESTINATION=%s SIZE=%dz\n", dest, size); #endif - sam_write(cmd, strlen(cmd)); - sam_write(data, size); + sam_write(session, cmd, strlen(cmd)); + sam_write(session, data, size); return SAM_OK; } @@ -213,14 +214,14 @@ samerr_t sam_dgram_send(const sam_pubkey_t dest, const void *data, size_t size) * * Returns: true on success, false on reply failure */ -static bool sam_hello() +static bool sam_hello(sam_sess_t *session) { #define SAM_HELLO_CMD "HELLO VERSION MIN=1.0 MAX=1.0\n" #define SAM_HELLO_REPLY "HELLO REPLY RESULT=OK VERSION=1.0" char reply[SAM_REPLY_LEN]; - sam_write(SAM_HELLO_CMD, strlen(SAM_HELLO_CMD)); - sam_read1(reply, SAM_REPLY_LEN); + sam_write(session, SAM_HELLO_CMD, strlen(SAM_HELLO_CMD)); + sam_read1(session, reply, SAM_REPLY_LEN); if (strncmp(reply, SAM_HELLO_REPLY, strlen(SAM_HELLO_REPLY)) == 0) return true; else { @@ -251,12 +252,12 @@ static void sam_log(const char *format, ...) * * name - name to lookup, or ME to lookup our own name */ -void sam_naming_lookup(const char *name) +void sam_naming_lookup(sam_sess_t *session, const char *name) { char cmd[SAM_CMD_LEN]; snprintf(cmd, sizeof cmd, "NAMING LOOKUP NAME=%s\n", name); - sam_write(cmd, strlen(cmd)); + sam_write(session, cmd, strlen(cmd)); return; } @@ -266,7 +267,7 @@ void sam_naming_lookup(const char *name) * * s - string of data that we read (read past tense) */ -static void sam_parse(char *s) +static void sam_parse(sam_sess_t *session, char *s) { #define SAM_DGRAM_RECEIVED_REPLY "DATAGRAM RECEIVED" #define SAM_NAMING_REPLY "NAMING REPLY" @@ -305,7 +306,7 @@ static void sam_parse(char *s) data is sent, the extra NUL character will just be ignored by the client program, because it is not added to the size */ - if (sam_read2(data, size) != -1) { + if (sam_read2(session, data, size) != -1) { p = data + size; *p = '\0'; /* see above NUL note */ sam_dgramback(dest, data, size); /* `data' must be freed */ @@ -439,7 +440,7 @@ static void sam_parse(char *s) data is sent, the extra NUL character will just be ignored by the client program, because it is not added to the size */ - if (sam_read2(data, size) != -1) { + if (sam_read2(session, data, size) != -1) { p = data + size; *p = '\0'; /* see above NUL note */ sam_databack(stream_id, data, size); /* `data' must be freed */ @@ -492,17 +493,17 @@ static void sam_parse(char *s) * * Returns: true if we read anything, or false if nothing was there */ -bool sam_read_buffer() +bool sam_read_buffer(sam_sess_t *session) { bool read_something = false; char reply[SAM_REPLY_LEN]; - if (sam_readable()) { + if (sam_readable(session)) { do { - sam_read1(reply, SAM_REPLY_LEN); + sam_read1(session, reply, SAM_REPLY_LEN); read_something = true; - sam_parse(reply); - } while (sam_readable()); + sam_parse(session, reply); + } while (sam_readable(session)); } return read_something; @@ -522,7 +523,7 @@ bool sam_read_buffer() * * Returns: number of bytes read, or -1 on error */ -static ssize_t sam_read1(char *buf, size_t n) +static ssize_t sam_read1(sam_sess_t *session, char *buf, size_t n) { size_t nleft; ssize_t nread; @@ -530,7 +531,7 @@ static ssize_t sam_read1(char *buf, size_t n) *buf = '\0'; /* this forces `buf' to be a string even if there is a sam_read1 error return */ - if (!samd_connected) { + if (!session->connected) { SAMLOGS("Cannot read from SAM because the SAM connection is closed"); sam_diedback(); return -1; @@ -539,7 +540,7 @@ static ssize_t sam_read1(char *buf, size_t n) p = buf; nleft = n; while (nleft > 0) { - nread = recv(samd, p, 1, 0); + nread = recv(session->sock, p, 1, 0); if (nread == -1) { if (errno == EINTR) /* see Unix Network Pgming vol 1, Sec. 5.9 */ continue; @@ -550,13 +551,13 @@ static ssize_t sam_read1(char *buf, size_t n) #else SAMLOG("recv() failed: %s", strerror(errno)); #endif - sam_close(); + sam_close(session); sam_diedback(); return -1; } } else if (nread == 0) { /* EOF */ SAMLOGS("Connection closed by the SAM host"); - sam_close(); + sam_close(session); sam_diedback(); return -1; } @@ -589,13 +590,13 @@ static ssize_t sam_read1(char *buf, size_t n) * * Returns: number of bytes read, or -1 on error */ -static ssize_t sam_read2(void *buf, size_t n) +static ssize_t sam_read2(sam_sess_t *session, void *buf, size_t n) { size_t nleft; ssize_t nread; void *p; - if (!samd_connected) { + if (!session->connected) { SAMLOGS("Cannot read from SAM because the SAM connection is closed"); sam_diedback(); return -1; @@ -604,7 +605,7 @@ static ssize_t sam_read2(void *buf, size_t n) p = buf; nleft = n; while (nleft > 0) { - nread = recv(samd, p, nleft, 0); + nread = recv(session->sock, p, nleft, 0); if (nread == -1) { if (errno == EINTR) /* see Unix Network Pgming vol 1, Sec. 5.9 */ continue; @@ -615,13 +616,13 @@ static ssize_t sam_read2(void *buf, size_t n) #else SAMLOG("recv() failed: %s", strerror(errno)); #endif - sam_close(); + sam_close(session); sam_diedback(); return -1; } } else if (nread == 0) { /* EOF */ SAMLOGS("Connection closed by the SAM host"); - sam_close(); + sam_close(session); sam_diedback(); return -1; } @@ -640,23 +641,23 @@ static ssize_t sam_read2(void *buf, size_t n) * * Returns: true if data is waiting, false otherwise */ -static bool sam_readable() +static bool sam_readable(const sam_sess_t *session) { fd_set rset; /* set of readable descriptors */ struct timeval tv; int rc; - if (!samd_connected) { + if (!session->connected) { SAMLOGS("Cannot read from SAM because the SAM connection is closed"); sam_diedback(); return false; } /* it seems like there should be a better way to do this (i.e. not select)*/ FD_ZERO(&rset); - FD_SET(samd, &rset); + FD_SET(session->sock, &rset); tv.tv_sec = 0; tv.tv_usec = 10; - rc = select(samd + 1, &rset, NULL, NULL, &tv); + rc = select(session->sock + 1, &rset, NULL, NULL, &tv); if (rc == 0) return false; else if (rc > 0) @@ -674,14 +675,15 @@ static bool sam_readable() /* * Adds data to the send queue * + * stream_id - stream number to send to if the queue is full * sendq - the send queue * data - data to add * dsize - the size of the data * * Returns: true on success, false on error */ -void sam_sendq_add(sam_sid_t stream_id, sam_sendq_t **sendq, const void *data, - size_t dsize) +void sam_sendq_add(sam_sess_t *session, sam_sid_t stream_id, + sam_sendq_t **sendq, const void *data, size_t dsize) { assert(dsize >= 0); if (dsize == 0) { @@ -704,7 +706,7 @@ void sam_sendq_add(sam_sid_t stream_id, sam_sendq_t **sendq, const void *data, if ((*sendq)->size + dsize == SAM_STREAM_PAYLOAD_MAX) { memcpy((*sendq)->data + (*sendq)->size, data, dsize); (*sendq)->size = SAM_STREAM_PAYLOAD_MAX; - sam_sendq_flush(stream_id, sendq); + sam_sendq_flush(session, stream_id, sendq); return; } @@ -713,8 +715,8 @@ void sam_sendq_add(sam_sid_t stream_id, sam_sendq_t **sendq, const void *data, memcpy((*sendq)->data + (*sendq)->size, data, s); //append as much as we can dsize -= s; /* update dsize to the size of whatever data hasn't been sent*/ (*sendq)->size = SAM_STREAM_PAYLOAD_MAX; /* it's a full packet */ - sam_sendq_flush(stream_id, sendq); /* send the queued data */ - sam_sendq_add(stream_id, sendq, data + s, dsize); /* recurse the rest */ + sam_sendq_flush(session, stream_id, sendq); /* send the queued data */ + sam_sendq_add(session, stream_id, sendq, data + s, dsize); /* recurse */ return; } @@ -740,12 +742,13 @@ static sam_sendq_t *sam_sendq_create() /* * Sends the data in the send queue to the specified stream * - * sendq - the send queue * stream_id - stream number to send to + * sendq - the send queue */ -void sam_sendq_flush(sam_sid_t stream_id, sam_sendq_t **sendq) +void sam_sendq_flush(sam_sess_t *session, sam_sid_t stream_id, + sam_sendq_t **sendq) { - sam_stream_send(stream_id, (*sendq)->data, (*sendq)->size); + sam_stream_send(session, stream_id, (*sendq)->data, (*sendq)->size); /* we now free it in case they aren't going to use it anymore */ free((*sendq)->data); free(*sendq); @@ -754,17 +757,45 @@ void sam_sendq_flush(sam_sid_t stream_id, sam_sendq_t **sendq) return; } +/* + * Allocates memory for the session and sets its default values + * + * session - pointer to a previously allocated sam_sess_t to initalise, or NULL + * if you want memory to be allocated by this function + */ +sam_sess_t *sam_session_init(sam_sess_t *session) +{ + if (session == NULL) + session = malloc(sizeof(sam_sess_t)); + session->connected = false; + session->prev_id = 0; + + return session; +} + +/* + * Frees memory used by the session and sets the pointer to NULL + * + * session - pointer to a pointer to a sam_sess_t + */ +void sam_session_free(sam_sess_t **session) +{ + free(session); + *session = NULL; +} + /* * Sends the second SAM handshake command and checks the reply * * destname - destination name for this program, or "TRANSIENT" to create a * random temporary destination + * style - type of connection to use (SAM_STREAM, SAM_DGRAM, or SAM_RAW) * tunneldepth - length of the I2P tunnels created by this program * * Returns: SAM error code */ -static samerr_t sam_session_create(const char *destname, sam_conn_t style, - uint_t tunneldepth) +static samerr_t sam_session_create(sam_sess_t *session, const char *destname, + sam_conn_t style, uint_t tunneldepth) { #define SAM_SESSTATUS_REPLY_OK "SESSION STATUS RESULT=OK" #define SAM_SESSTATUS_REPLY_DD "SESSION STATUS RESULT=DUPLICATED_DEST" @@ -790,8 +821,8 @@ static samerr_t sam_session_create(const char *destname, sam_conn_t style, assert(false); /* unimplemented */ } - sam_write(cmd, strlen(cmd)); - sam_read1(reply, SAM_REPLY_LEN); + sam_write(session, cmd, strlen(cmd)); + sam_read1(session, reply, SAM_REPLY_LEN); if (strncmp(reply, SAM_SESSTATUS_REPLY_OK, strlen(SAM_SESSTATUS_REPLY_OK)) == 0) return SAM_OK; @@ -816,20 +847,20 @@ static samerr_t sam_session_create(const char *destname, sam_conn_t style, * * Returns: true on sucess, false on error, with errno set */ -bool sam_socket_connect(const char *host, uint16_t port) +bool sam_socket_connect(sam_sess_t *session, const char *host, uint16_t port) { struct sockaddr_in hostaddr; int rc; char ipaddr[INET_ADDRSTRLEN]; - samd = socket(AF_INET, SOCK_STREAM, 0); + session->sock = socket(AF_INET, SOCK_STREAM, 0); #ifdef WINSOCK - if (samd == INVALID_SOCKET) { + if (session->sock == INVALID_SOCKET) { SAMLOG("socket() failed: %s", sam_winsock_strerror(WSAGetLastError())); return false; } #else - if (samd == -1) { + if (session->sock == -1) { SAMLOG("socket() failed: %s", strerror(errno)); return false; } @@ -852,7 +883,7 @@ bool sam_socket_connect(const char *host, uint16_t port) } else if (rc == -1) return false; - rc = connect(samd, (struct sockaddr *)&hostaddr, sizeof hostaddr); + rc = connect(session->sock, (struct sockaddr *)&hostaddr, sizeof hostaddr); if (rc == -1) { #ifdef WINSOCK SAMLOG("connect() failed: %s", sam_winsock_strerror(WSAGetLastError())); @@ -862,7 +893,7 @@ bool sam_socket_connect(const char *host, uint16_t port) return false; } - samd_connected = true; + session->connected = true; return true; } @@ -926,7 +957,7 @@ retry: * * stream_id - stream number to close */ -void sam_stream_close(sam_sid_t stream_id) +void sam_stream_close(sam_sess_t *session, sam_sid_t stream_id) { char cmd[SAM_CMD_LEN]; @@ -935,7 +966,7 @@ void sam_stream_close(sam_sid_t stream_id) #else snprintf(cmd, sizeof cmd, "STREAM CLOSE ID=%d\n", stream_id); #endif - sam_write(cmd, strlen(cmd)); + sam_write(session, cmd, strlen(cmd)); return; } @@ -947,22 +978,21 @@ void sam_stream_close(sam_sid_t stream_id) * * Returns: stream id number */ -sam_sid_t sam_stream_connect(const sam_pubkey_t dest) +sam_sid_t sam_stream_connect(sam_sess_t *session, const sam_pubkey_t dest) { char cmd[SAM_PKCMD_LEN]; - static sam_sid_t id = 0; - id++; /* increment the id for the connection */ + session->prev_id++; /* increment the id for the connection */ #ifdef FAST32_IS_LONG snprintf(cmd, sizeof cmd, "STREAM CONNECT ID=%ld DESTINATION=%s\n", - id, dest); + session->prev_id, dest); #else snprintf(cmd, sizeof cmd, "STREAM CONNECT ID=%d DESTINATION=%s\n", - id, dest); + session->prev_id, dest); #endif - sam_write(cmd, strlen(cmd)); + sam_write(session, cmd, strlen(cmd)); - return id; + return session->prev_id; } /* @@ -974,7 +1004,8 @@ sam_sid_t sam_stream_connect(const sam_pubkey_t dest) * * Returns: true on success, false on failure */ -samerr_t sam_stream_send(sam_sid_t stream_id, const void *data, size_t size) +samerr_t sam_stream_send(sam_sess_t *session, sam_sid_t stream_id, + const void *data, size_t size) { char cmd[SAM_CMD_LEN]; @@ -1000,8 +1031,8 @@ samerr_t sam_stream_send(sam_sid_t stream_id, const void *data, size_t size) snprintf(cmd, sizeof cmd, "STREAM SEND ID=%d SIZE=%dz\n", stream_id, size); #endif - sam_write(cmd, strlen(cmd)); - sam_write(data, size); + sam_write(session, cmd, strlen(cmd)); + sam_write(session, data, size); return SAM_OK; } @@ -1233,13 +1264,13 @@ const char *sam_winsock_strerror(int code) * * Returns: `n', or -1 on error */ -static ssize_t sam_write(const void *buf, size_t n) +static ssize_t sam_write(sam_sess_t *session, const void *buf, size_t n) { size_t nleft; ssize_t nwritten; const char *p; - if (!samd_connected) { + if (!session->connected) { SAMLOGS("Cannot write to SAM because the SAM connection is closed"); sam_diedback(); return -1; @@ -1257,7 +1288,7 @@ static ssize_t sam_write(const void *buf, size_t n) p = buf; nleft = n; while (nleft > 0) { - nwritten = send(samd, p, nleft, 0); + nwritten = send(session->sock, p, nleft, 0); if (nwritten <= 0) { if (errno == EINTR) /* see Unix Network Pgming vol 1, Sec. 5.9 */ continue; @@ -1268,7 +1299,7 @@ static ssize_t sam_write(const void *buf, size_t n) #else SAMLOG("send() failed: %s", strerror(errno)); #endif - sam_close(); + sam_close(session); sam_diedback(); return -1; }