return; /* this returns to afp_disconnect */
}
+ if (dsi->flags & DSI_DISCONNECTED) {
+ LOG(log_note, logtype_afpd, "Disconnected session terminating");
+ exit(0);
+ }
+
dsi_attention(AFPobj->handle, AFPATTN_SHUTDOWN);
afp_dsi_close(AFPobj);
if (sig) /* if no signal, assume dieing because logins are disabled &
}
}
+/* SIGURG handler (primary reconnect) */
static void afp_dsi_transfer_session(int sig _U_)
{
uint16_t dsiID;
LOG(log_note, logtype_afpd, "afp_dsi_transfer_session: received socket fd: %i", socket);
dsi->socket = socket;
- dsi->flags |= DSI_RECONSOCKET;
- dsi->flags &= ~DSI_DISCONNECTED;
+ dsi->flags = DSI_RECONSOCKET;
dsi->datalen = 0;
+ dsi->eof = dsi->start = dsi->buffer;
+ dsi->in_write = 0;
dsi->header.dsi_requestID = dsiID;
dsi->header.dsi_command = DSIFUNC_CMD;
siglongjmp(recon_jmp, 1);
}
-/* */
-static void afp_dsi_sleep(void)
-{
- dsi_sleep(AFPobj->handle, 1);
-}
-
/* ------------------- */
static void afp_dsi_timedown(int sig _U_)
{
/* we got some traffic from the client since the previous timer tick. */
if ((dsi->flags & DSI_DATA)) {
dsi->flags &= ~DSI_DATA;
- dsi->flags &= ~DSI_DISCONNECTED;
- return;
+ return;
}
dsi->tickle++;
+ LOG(log_note, logtype_afpd, "afp_alarm: tickle count: %i", dsi->tickle);
if (dsi->flags & DSI_SLEEPING) {
if (dsi->tickle > AFPobj->options.sleep) {
}
/* if we're in the midst of processing something, don't die. */
- if ( !(dsi->flags & DSI_RUNNING) && (dsi->tickle > AFPobj->options.timeout)) {
+ if ( !(dsi->flags & DSI_RUNNING) && (dsi->tickle >= AFPobj->options.timeout)) {
LOG(log_error, logtype_afpd, "afp_alarm: child timed out, entering disconnected state");
+ dsi->proto_close(dsi);
dsi->flags |= DSI_DISCONNECTED;
return;
}
obj->exit = afp_dsi_die;
obj->reply = (int (*)()) dsi_cmdreply;
obj->attention = (int (*)(void *, AFPUserBytes)) dsi_attention;
- obj->sleep = afp_dsi_sleep;
dsi->tickle = 0;
memset(&action, 0, sizeof(action));
/* get stuck here until the end */
while (1) {
- if (sigsetjmp(recon_jmp, 1) != 0) {
- LOG(log_note, logtype_afpd, "Resuming operation after succesfull primary reconnect");
- dsi->flags &= ~(DSI_RUNNING | DSI_DATA);
- dsi->eof = dsi->start = dsi->buffer;
- dsi->in_write = 0;
+ if (sigsetjmp(recon_jmp, 1) != 0)
+ /* returning from SIGALARM handler for a primary reconnect */
continue;
- }
+
+ /* Blocking read on the network socket */
cmd = dsi_receive(dsi);
+
if (cmd == 0) {
+ /* cmd == 0 is the error condition */
if (dsi->flags & DSI_RECONSOCKET) {
/* we just got a reconnect so we immediately try again to receive on the new fd */
dsi->flags &= ~DSI_RECONSOCKET;
}
}
- dsi->tickle = 0;
- dsi_sleep(dsi, 0); /* wake up */
+ if (!dsi->flags & DSI_EXTSLEEP) {
+ dsi->flags &= ~DSI_SLEEPING;
+ dsi->tickle = 0;
+ }
if (reload_request) {
reload_request = 0;
}
/* ---------------------- */
-int afp_zzz ( /* Function 122 */
- AFPObj *obj,
- char *ibuf _U_, size_t ibuflen _U_,
- char *rbuf, size_t *rbuflen)
+int afp_zzz(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
{
- u_int32_t retdata;
+ uint32_t data;
+ DSI *dsi = (DSI *)AFPobj->handle;
*rbuflen = 0;
- retdata = obj->options.sleep /120;
- if (!retdata) {
- retdata = 1;
+ if (ibuflen < 4)
+ return AFPERR_MISC;
+ memcpy(&data, ibuf, 4); /* flag */
+ data = ntohl(data);
+
+ /*
+ * Possible sleeping states:
+ * 1) normal sleep: DSI_SLEEPING (up to 10.3)
+ * 2) extended sleep: DSI_SLEEPING | DSI_EXTSLEEP (starting with 10.4)
+ */
+
+ if (data & AFPZZZ_EXT_WAKEUP) {
+ /* wakeup request from exetended sleep */
+ if (dsi->flags & DSI_EXTSLEEP)
+ dsi->flags &= ~(DSI_SLEEPING | DSI_EXTSLEEP);
+ } else {
+ /* sleep request */
+ dsi->flags |= DSI_SLEEPING;
+ if (data & AFPZZZ_EXT_SLEEP)
+ dsi->flags |= DSI_EXTSLEEP;
}
- *rbuflen = sizeof(retdata);
- retdata = htonl(retdata);
- memcpy(rbuf, &retdata, sizeof(retdata));
- if (obj->sleep)
- obj->sleep();
- rbuf += sizeof(retdata);
+ /*
+ * According to AFP 3.3 spec we should not return anything,
+ * but eg 10.5.8 server still returns the numbers of hours
+ * the server is keeping the sessino (ie max sleeptime).
+ */
+ data = obj->options.sleep / 120; /* hours */
+ if (!data) {
+ data = 1;
+ }
+ *rbuflen = sizeof(data);
+ data = htonl(data);
+ memcpy(rbuf, &data, sizeof(data));
+ rbuf += sizeof(data);
+
return AFP_OK;
}
void (*logout)(void), (*exit)(int);
int (*reply)(void *, int);
int (*attention)(void *, AFPUserBytes);
- void (*sleep)(void);
/* to prevent confusion, only use these in afp_* calls */
char oldtmp[AFPOBJ_TMPSIZ + 1], newtmp[AFPOBJ_TMPSIZ + 1];
void *uam_cookie; /* cookie for uams */
static void status_flags(char *data, const int notif, const int ipok,
const unsigned char passwdbits, const int dirsrvcs _U_, int flags)
{
- u_int16_t status;
+ uint16_t status;
+
+ status = AFPSRVRINFO_COPY
+ | AFPSRVRINFO_SRVSIGNATURE
+ | AFPSRVRINFO_SRVMSGS
+ | AFPSRVRINFO_FASTBOZO
+ | AFPSRVRINFO_SRVRDIR
+ | AFPSRVRINFO_SRVUTF8
+ | AFPSRVRINFO_EXTSLEEP;
- status = AFPSRVRINFO_COPY;
if (passwdbits & PASSWD_SET) /* some uams may not allow this. */
status |= AFPSRVRINFO_PASSWD;
if (passwdbits & PASSWD_NOSAVE)
status |= AFPSRVRINFO_NOSAVEPASSWD;
- status |= AFPSRVRINFO_SRVSIGNATURE;
- /* only advertise tcp/ip if we have a valid address */
- if (ipok)
+ if (ipok) /* only advertise tcp/ip if we have a valid address */
status |= AFPSRVRINFO_TCPIP;
- status |= AFPSRVRINFO_SRVMSGS;
- /* Allow the user to decide if we should support server notifications.
- * With this turned off, the clients will poll for directory changes every
- * 10 seconds. This might be too costly to network resources, so make
- * this an optional thing. Default will be to _not_ support server
- * notifications. */
- if (notif) {
+ if (notif) /* Default is yes */
status |= AFPSRVRINFO_SRVNOTIFY;
- }
- status |= AFPSRVRINFO_FASTBOZO;
- status |= AFPSRVRINFO_SRVRDIR; /* AFP 3.1 specs says we need to specify this, but may set the count to 0 */
- /* We don't set the UTF8 name flag here, we don't know whether we have enough space ... */
-
- if (flags & OPTION_UUID) /* 05122008 FIXME: can we set AFPSRVRINFO_UUID here ? see AFPSRVRINFO_SRVRDIR*/
- status |= AFPSRVRINFO_UUID;
+ if (flags & OPTION_UUID)
+ status |= AFPSRVRINFO_UUID;
status = htons(status);
memcpy(data + AFPSTATUS_FLAGOFF, &status, sizeof(status));
data += len;
offset = htons(offset);
memcpy(begin + *nameoffset, &offset, sizeof(u_int16_t));
-
- /* Now set the flag ... */
- memcpy(&status, begin + AFPSTATUS_FLAGOFF, sizeof(status));
- status = ntohs(status);
- status |= AFPSRVRINFO_SRVUTF8;
- status = htons(status);
- memcpy(begin + AFPSTATUS_FLAGOFF, &status, sizeof(status));
}
/* return length of buffer */
#define AFPTRANS_ALL (AFPTRANS_DDP | AFPTRANS_TCP)
/* server flags */
-#define AFPSRVRINFO_COPY (1<<0) /* supports copyfile */
-#define AFPSRVRINFO_PASSWD (1<<1) /* supports change password */
+#define AFPSRVRINFO_COPY (1<<0) /* supports copyfile */
+#define AFPSRVRINFO_PASSWD (1<<1) /* supports change password */
#define AFPSRVRINFO_NOSAVEPASSWD (1<<2) /* don't allow save password */
#define AFPSRVRINFO_SRVMSGS (1<<3) /* supports server messages */
#define AFPSRVRINFO_SRVSIGNATURE (1<<4) /* supports server signature */
#define AFPSRVRINFO_TCPIP (1<<5) /* supports tcpip */
#define AFPSRVRINFO_SRVNOTIFY (1<<6) /* supports server notifications */
-
#define AFPSRVRINFO_SRVRECONNECT (1<<7) /* supports server reconnect */
#define AFPSRVRINFO_SRVRDIR (1<<8) /* supports directories service */
-
#define AFPSRVRINFO_SRVUTF8 (1<<9) /* supports UTF8 names AFP 3.1 */
#define AFPSRVRINFO_UUID (1<<10) /* supports UUIDs */
-#define AFPSRVRINFO_FASTBOZO (1<<15) /* fast copying */
+#define AFPSRVRINFO_EXTSLEEP (1<<11) /* supports extended sleep */
+#define AFPSRVRINFO_FASTBOZO (1<<15) /* fast copying */
#define AFP_OK 0
#define AFPERR_DID1 -4000 /* not an afp error DID is 1*/
AFPMESG_SERVER = 1
} afpmessage_t;
+/* extended sleep flag */
+#define AFPZZZ_EXT_SLEEP 1
+#define AFPZZZ_EXT_WAKEUP 2
+
+
/* AFP functions */
#define AFP_BYTELOCK 1
#define AFP_CLOSEVOL 2
#define DSI_DATA (1 << 0) /* we have received a DSI command */
#define DSI_RUNNING (1 << 1) /* we have received a AFP command */
#define DSI_SLEEPING (1 << 2) /* we're sleeping after FPZzz */
-#define DSI_DISCONNECTED (1 << 3) /* we're in diconnected state after a socket error */
-#define DSI_DIE (1 << 4) /* SIGUSR1, going down in 5 minutes */
-#define DSI_NOREPLY (1 << 5) /* in dsi_write we generate our own replies */
-#define DSI_RECONSOCKET (1 << 6) /* we have a new socket from primary reconnect */
-#define DSI_RECONINPROG (1 << 7) /* used in the new session in reconnect */
+#define DSI_EXTSLEEP (1 << 3) /* we're sleeping after FPZzz */
+#define DSI_DISCONNECTED (1 << 4) /* we're in diconnected state after a socket error */
+#define DSI_DIE (1 << 5) /* SIGUSR1, going down in 5 minutes */
+#define DSI_NOREPLY (1 << 6) /* in dsi_write we generate our own replies */
+#define DSI_RECONSOCKET (1 << 7) /* we have a new socket from primary reconnect */
+#define DSI_RECONINPROG (1 << 8) /* used in the new session in reconnect */
/* basic initialization: dsi_init.c */
extern DSI *dsi_init (const dsi_proto /*protocol*/,
extern int dsi_tickle (DSI *);
extern void dsi_getstatus (DSI *);
extern void dsi_close (DSI *);
-extern void dsi_sleep (DSI *, const int );
#define DSI_NOWAIT 1
/* low-level stream commands -- in dsi_stream.c */
return len;
}
-/* ---------------------------------------
-*/
-void dsi_sleep(DSI *dsi, const int state)
-{
- if (state)
- dsi->flags |= DSI_SLEEPING;
- else
- dsi->flags &= ~DSI_SLEEPING;
-}
-
/* ---------------------------------------
*/
static void block_sig(DSI *dsi)
if ( child->pid != pid) {
if (child->idlen == idlen && memcmp(child->clientid, id, idlen) == 0) {
if ( child->time != boottime ) {
+ /* Client rebooted */
if (uid == child->uid) {
kill_child(child);
- LOG(log_note, logtype_default, "Disconnected child[%u], client rebooted.", child->pid);
+ LOG(log_warning, logtype_default,
+ "Terminated disconnected child[%u], client rebooted.",
+ child->pid);
} else {
- LOG(log_note, logtype_default, "Session with different pid[%u]", child->pid);
+ LOG(log_warning, logtype_default,
+ "Session with different pid[%u]", child->pid);
}
+ } else {
+ kill_child(child);
+ LOG(log_note, logtype_default,
+ "Terminated disconnected session[%u]", child->pid);
}
- if (child->killed)
- kill_child(child); /* this will send SIGKILL */
- LOG(log_note, logtype_default, "", child->pid, pid);
}
} else {
/* update childs own slot */
return -1;
memcpy (clientid, p, idlen);
- LOG (log_debug, logtype_afpd, "ipc_get_session(pid: %u, uid: %u, time %x)",
- ipc->child_pid, ipc->uid, boottime);
+ LOG(log_debug, logtype_afpd, "ipc_get_session(pid: %u, uid: %u, time: 0x%08x)",
+ ipc->child_pid, ipc->uid, boottime);
server_child_kill_one_by_id(children,
CHILD_DSIFORK,