return NULL;
}
#endif
+ ast_pthread_mutex_lock(&p->lock);
ast_pthread_mutex_unlock(&iflock);
return p;
}
return 0;
}
-static int transmit_response(struct sip_pvt *p, char *msg, struct sip_request *req)
+static int __transmit_response(struct sip_pvt *p, char *msg, struct sip_request *req, int reliable)
{
struct sip_request resp;
+ int seqno = 0;
+ if (reliable && (sscanf(get_header(req, "CSeq"), "%i ", &seqno) != 1)) {
+ ast_log(LOG_WARNING, "Unable to determine sequence number from '%s'\n", get_header(req, "CSeq"));
+ return -1;
+ }
respprep(&resp, p, msg, req);
add_header(&resp, "Content-Length", "0");
add_blank_header(&resp);
- return send_response(p, &resp, 0, 0);
+ return send_response(p, &resp, reliable, seqno);
+}
+
+static int transmit_response(struct sip_pvt *p, char *msg, struct sip_request *req)
+{
+ return __transmit_response(p, msg, req, 0);
+}
+static int transmit_response_reliable(struct sip_pvt *p, char *msg, struct sip_request *req)
+{
+ return __transmit_response(p, msg, req, 1);
}
static int transmit_response_with_allow(struct sip_pvt *p, char *msg, struct sip_request *req)
f.offset = 0;
f.data = buf;
f.datalen = strlen(buf);
- ast_queue_frame(p->owner, &f, 1);
+ ast_queue_frame(p->owner, &f, 0);
}
}
f.offset = 0;
f.data = NULL;
f.datalen = 0;
- ast_queue_frame(p->owner, &f, 1);
+ ast_queue_frame(p->owner, &f, 0);
}
}
}
}
msg = strchr(c, ' ');
if (!msg) msg = ""; else msg++;
-retrylock:
- ast_pthread_mutex_lock(&p->lock);
- /* Go ahead and lock the owner if it has one -- we may need it */
- if (p->owner && pthread_mutex_trylock(&p->owner->lock)) {
- ast_log(LOG_DEBUG, "Failed to grab lock, trying again...\n");
- ast_pthread_mutex_unlock(&p->lock);
- /* Sleep infintismly short amount of time */
- usleep(1);
- goto retrylock;
- }
owner = p->owner;
if (p->peerpoke) {
/* We don't really care what the response is, just that it replied back.
ast_sched_del(sched, peer->pokeexpire);
if (!strcasecmp(msg, "INVITE"))
transmit_request(p, "ACK", 0, 0);
- sip_destroy(p);
- p = NULL;
+ p->needdestroy = 1;
/* Try again eventually */
if ((peer->lastms < 0) || (peer->lastms > peer->maxms))
peer->pokeexpire = ast_sched_add(sched, DEFAULT_FREQ_NOTOK, sip_poke_peer_s, peer);
static int handle_request(struct sip_pvt *p, struct sip_request *req, struct sockaddr_in *sin)
{
+ /* Called with p->lock held, as well as p->owner->lock if appropriate, keeping things
+ relatively static */
struct sip_request resp;
char *cmd;
char *cseq;
/* Response to our request -- Do some sanity checks */
if (!p->initreq.headers) {
ast_log(LOG_DEBUG, "That's odd... Got a response on a call we dont know about.\n");
- sip_destroy(p);
+ p->needdestroy = 1;
return 0;
} else if (p->ocseq && (p->ocseq < seqno)) {
ast_log(LOG_DEBUG, "Ignoring out of order response %d (expecting %d)\n", seqno, p->ocseq);
if (res) {
if (res < 0) {
ast_log(LOG_NOTICE, "Failed to authenticate user %s\n", get_header(req, "From"));
- sip_destroy(p);
+ p->needdestroy = 1;
}
return 0;
}
transmit_response(p, "404 Not Found", req);
else
transmit_response(p, "484 Address Incomplete", req);
- sip_destroy(p);
- p = NULL;
- c = NULL;
+ p->needdestroy = 1;
} else {
/* If no extension was specified, use the s one */
if (!strlen(p->exten))
p->tag = rand();
/* First invitation */
c = sip_new(p, AST_STATE_DOWN, strlen(p->username) ? p->username : NULL);
+ if (c) {
+ /* Pre-lock the call */
+ ast_pthread_mutex_lock(&c->lock);
+ }
}
} else
ast_setstate(c, AST_STATE_RING);
if (ast_pbx_start(c)) {
ast_log(LOG_WARNING, "Failed to start PBX :(\n");
- ast_hangup(c);
- transmit_response(p, "503 Unavailable", req);
- sip_destroy(p);
+ sip_hangup(c);
+ transmit_response_reliable(p, "503 Unavailable", req);
+ c = NULL;
}
break;
case AST_STATE_RING:
} else {
if (p) {
ast_log(LOG_NOTICE, "Unable to create/find channel\n");
- transmit_response(p, "503 Unavailable", req);
- sip_destroy(p);
+ transmit_response_reliable(p, "503 Unavailable", req);
+ p->needdestroy = 1;
}
}
} else if (!strcasecmp(cmd, "REFER")) {
ast_rtp_stop(p->rtp);
}
if (p->owner)
- ast_queue_hangup(p->owner, 1);
+ ast_queue_hangup(p->owner, 0);
transmit_response(p, "200 OK", req);
} else if (!strcasecmp(cmd, "MESSAGE")) {
if (sipdebug)
if ((res = register_verify(p, sin, req, e)) < 0)
ast_log(LOG_NOTICE, "Registration from '%s' failed for '%s'\n", get_header(req, "To"), inet_ntoa(sin->sin_addr));
if (res < 1) {
- sip_destroy(p);
+ p->needdestroy = 1;
}
} else if (!strcasecmp(cmd, "ACK")) {
/* Uhm, I haven't figured out the point of the ACK yet. Are we
ast_pthread_mutex_lock(&netlock);
p = find_call(&req, &sin);
if (p) {
+retrylock:
+ /* Go ahead and lock the owner if it has one -- we may need it */
+ if (p->owner && pthread_mutex_trylock(&p->owner->lock)) {
+ ast_log(LOG_DEBUG, "Failed to grab lock, trying again...\n");
+ ast_pthread_mutex_unlock(&p->lock);
+ /* Sleep infintismly short amount of time */
+ usleep(1);
+ goto retrylock;
+ }
memcpy(&p->recv, &sin, sizeof(p->recv));
handle_request(p, &req, &sin);
+ if (p->owner)
+ ast_pthread_mutex_unlock(&p->owner->lock);
+ ast_pthread_mutex_unlock(&p->lock);
}
ast_pthread_mutex_unlock(&netlock);
return 1;